Hi-tech-Cのソースファイルです。拡張子を〜.cに変更して下さい。 /******************************************************** * 連続間欠タイマー + 得点表示(カウンター) Version_16 * タクトスイッチによる時間設定の小型モデル * LCDのBigFontによる前面表示+上面もLCD * Pic:16F1827 MPLAB IDE Ver8.84 HI-TECH C v9.83 * I2cで2つのLCDをコントロール(PCF8574T(I2c)+1602 と AQM0802) **********************************************************/ // 音が減衰する程度 指定値(ms)で1/16減少 #define EnvelopeConst 50 // 音符と音符の間の無音時間(ms) #define Silent 10 // (30→10) #include #include "ohkinakurino_k.h" // 『大きな栗の木の下で』 // const unsigned int Music[] = {楽譜データ} #define _XTAL_FREQ 8000000 // 8MHz // 音源:RA3(CCP3) #define BzPort RA4 // ブザー音 #define TRIS_Bz TRISA4 // 出力切替 #define ADDR1 0x4E // I2cアダプタPCF8574Tのアドレス #define ADDR2 0x7C // AQM0802のアドレス #define SDA RA6 #define SCL RA7 #define TRISSDA TRISA6 /*** 調整用定数(AQM0802) ***/ //#define CONTRAST 0x18 // for 5.0V #define CONTRAST 0x2A // for 3.3V 42/64段階 /***** コンフィギュレーションの設定 ********/ __CONFIG(FOSC_INTOSC // INTOSCIO oscillator I/O function & WDTE_OFF // Watchdog Timer disabled & PWRTE_ON // Power-up Timer enabled & BOREN_ON // Brown Out enabled & MCLRE_ON // MCLR RA5はリセット & CP_OFF // Program memory code protection is disabled & CPD_OFF // データメモリーを保護しない(OFF) & CLKOUTEN_OFF // CLKOUTピンをRA6ピンで使用する(OFF) & IESO_OFF // Internal External Switchover mode is disabled & FCMEN_OFF // Fail-Safe Clock Monitor is disabled & WRT_OFF ); // Flashメモリーを保護しない(OFF) __CONFIG(PLLEN_OFF // 動作クロックを32MHzでは動作させない(OFF) & STVREN_ON // Stack Overflow/Underflow will cause a Reset & BORV_LO // 電源電圧降下常時監視電圧(2.5V)設定(LO) & LVP_OFF ); // 低電圧プログラミング機能使用しない(OFF) // 音の高さを決める定数 for 8MHz Fosc PWM Freq 16.525kHz const unsigned int dW_tbl[] = { // Do, Do#, Re, Re#, Mi, Fa, Fa#, So, So#, Ra, Ra#, Si, 0,0x112,0x122,0x133,0x146,0x159,0x16E,0x183,0x19B,0x1B3,0x1CD,0x1E8,0x205, //12 0x224,0x245,0x267,0x28C,0x2B3,0x2DC,0x307,0x336,0x366,0x39A,0x3D1,0x40B, 0x449,0x48A,0x4CF,0x518,0x566,0x5B8,0x60F,0x66C,0x6CD,0x735,0x7A3,0x817, 0x892,0x915,0x99F,0xA31,0xACD,0xB71,0xC1F,0xCD8,0xD9B,0xE6A,0xF46,0x102E, 0x1125,0x122A,0x133E,0x1463,0x159A,0x16E3,0x183F,0x19B0,0x1B37,0x1CD5,0x1E8C,0x205D, 0x224A,0x2454,0x267D,0x28C7,0x2B34,0x2DC6,0x307E,0x3361,0x366F,0x39AB,0x3D19,0x40BB }; // 0x892(index 37) が中心のド(60 0x3E) ,0xD9B はラ (440Hz) // CGRAM(5x8ドット)に格納する内容(下側の5ビット) const char FontParts[][8] = { // 0x1F→0b11111 { 0x1F, 0x1F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00 },// 0x00 { 0x18, 0x1C, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F },// 0x01 { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x0F, 0x07, 0x03 },// 0x02 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F },// 0x03 { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1C, 0x18 },// 0x04 { 0x1F, 0x1F, 0x1F, 0x00, 0x00, 0x00, 0x1F, 0x1F },// 0x05 { 0x1F, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F },// 0x06 { 0x03, 0x07, 0x0F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F } // 0x07 }; // CGRAM(0x00-07)を組み合わせて作る数字(0-9)とコロン // 0x20は空白、0xFFは塗りつぶし、0xA5は点 // 左3つが1行目、右3つが2行目 const char BigNum[11][6] = { // キャラクターのアドレス { 0x07, 0x00, 0x01, 0x02, 0x03, 0x04 }, // 0 { 0x00, 0x01, 0x20, 0x03, 0xFF, 0x03 }, // 1 { 0x05, 0x05, 0x01, 0xFF, 0x06, 0x06 }, // 2 { 0x00, 0x05, 0x01, 0x03, 0x06, 0x04 }, // 3 { 0x02, 0x03, 0xFF, 0x20, 0x20, 0xFF }, // 4 { 0xFF, 0x05, 0x05, 0x06, 0x06, 0x04 }, // 5 { 0x07, 0x05, 0x05, 0x02, 0x06, 0x04 }, // 6 { 0x00, 0x00, 0x01, 0x20, 0x07, 0x20 }, // 7 { 0x07, 0x05, 0x01, 0x02, 0x06, 0x04 }, // 8 { 0x07, 0x05, 0x01, 0x06, 0x06, 0x04 }, // 9 { 0x20, 0xA5, 0x20, 0x20, 0xA5, 0x20 } // : }; // タイマー用変数 unsigned int Time, Time2; // 設定秒数計(繰り返し,インターバル) unsigned int m_time, s_time;// 設定秒数(分、10秒) unsigned char min1, sec1, sec2;// 分数、カウント秒、インターバル秒 unsigned char BF; // 開始ブザーフラグ unsigned char chflg; // 秒が変わったフラグ unsigned char Mode; // 処理モード: 0〜3 unsigned char Count; // 20mSのカウント(50回で1秒) unsigned char sw; // タクトスイッチ unsigned char melody_on; unsigned char melody_stop; // ビッグフォント用 unsigned char su[4]; // su[0]分:su[2],su[3]秒:Right ** Left ** // カウンター用変数 unsigned int RIGHT,LEFT; // 得点の変数(右,左) unsigned char SIDE; // サーブ側表示 R=>0, L=>1 unsigned char colon; // サーブ側変動時:点灯、連続得点:消灯 unsigned char Tact; // 得点用タクトスイッチ // メロディ用 unsigned int accWave,incWave; unsigned char amp,wave; void melody_k(); // オルゴール演奏改良版(3連符可) // メロディ用変数 unsigned int Track; // 音符位置 unsigned int Note; // 音符 unsigned char tempo; // テンポ unsigned char Len; // 演奏長さ char AmpCnt = 25; // 振幅調整 char TmpCnt = 65; // テンポ調整 char TmpFlg = 0; // テンポフラグ char SltCnt = 20; // 無音時間 char SltFlg = 0; // 無音フラグ char ampNext; // 次音符音量 // LCD用関数 LCD1602は4ビットモードで稼働 void I2c_Start(void); void I2c_Stop(void); unsigned char I2c_Out(unsigned char data); void lcd_common(unsigned char data); void lcd_data(unsigned char data); void lcd_cmd(unsigned char data); void lcd_init1(void); void lcd_str(char* ptr); // AQM0802 は8ビットモードで稼働 void lcd_data2(unsigned char data); void lcd_cmd2(unsigned char data); void lcd_init2(void); void lcd_str2(char* ptr); // CGRAM用のデータ(custom)をメモリに格納する関数 void lcd_Def_Char(char adrs, char *pattern){ lcd_cmd(0x40 | (adrs << 3)); //CGRAMアドレス (adrs: 0-7) for(char i=0; i<8; i++){ lcd_data(pattern[i]); } } unsigned char Msg1[] = "クリカエシ = x:xx "; // 前面LCD用 unsigned char Int1[] = "インターバル = xx "; unsigned char Msg2[] = "Rep x:xx"; // 計測時間表示(上面LCD) unsigned char Int2[] = "Int xx"; // インターバル秒の表示 unsigned char Counter_b1[] = "L R "; // カウンタ上1行目 unsigned char Counter_b2[] = " xx : xx"; // カウンタ上2行目 // 数値をASCII文字に変換する関数 void i_to_str(char digit, unsigned int data, char *buffer); void Hyouji1a(void);// タイマー時 void Hyouji1b(void);// タイマー時 void Hyouji2(void); // タイマー時BigFont void Hyouji3(void); // カウンター時 void bzr1(void); // プ void bzr2(void); // ピ void delay_10us(unsigned char t1); // 10μs遅延 void delay_10ms(unsigned char t2); // 10ms遅延 unsigned char keysearch(); // どのキー? unsigned char getkey(); // 確認5回 void main(void) { OSCCON = 0b01110000;// 内部クロック 8Mhz(右端は:10,00どちらも可) ANSELA = 0x00; // 全てデジタルIO ANSELB = 0x00; // 全てデジタルIO TRISA = 0x3C; // RA2,3,4,5入力(RA3,4 はその都度出力に) TRISB = 0x0F; // 0-3:入力(タクトSW) // タイマー0の設定 秒カウントダウン・タイマー用 OPTION_REG = 0x87; // 内部プルアップ無し、プリスケーラ 1/256 // TOCS=0,TOSE=0,PSA=0,PS2〜0=1:1:1 INTCON = 0xC0; // GIE=1, PEIE=1; T0IE=0, T0IF=0 TMR0 = 0x64; // 初期値:100 0.5μS×(256-100)×256 => 約20mS T0IE = 0; // Timer0 始動はまだ // Timer1 の設定 メロディの出力 T1CON = 0b01000000; // Fosc ps 1/1 TMR1ONまだ TMR1 = 0xE100; // +7936 (0.992ms) で Carry TMR1IF = 0; // Timer1フラグクリア // PWM, Timer2 の設定 減衰音の作成 CCPTMRS = 0b00000000;// CCP3をTimer2に割当て CCP3CON = 0b00001100;// CCP3をPWMモードに設定 // (かつCCPR3Lの下位2ビットを0に設定) T2CON = 0b00000000; // Timer2 OFF PreS 1/1 PR2 = 0x7F; // 繰返し周波数 15.625KHz TMR2IF = 0; // Timer2フラグクリア TMR2IE = 1; // Timer2割込み有効 PEIE = 1; // ペリフェラル割込み有効 GIE = 1; // 全割込み処理を許可する // 電源安定時間 delay_10ms(10); // 液晶表示器の初期化 lcd_init1(); lcd_init2(); // CGRAM0x00〜07へフォントデータ書込み for(char j=0; j<8; j++){ lcd_Def_Char(j, &FontParts[j][0]); } /**** メインループ *****/ // 機能切替SW(RA2)により、タイマーとカウンターに動作分岐 if(RA2 == 1){ // 機能切替スイッチ=off(デフォルト:1) // タイマーの場合 : 変数初期化 Count = 0; // 50回で1秒 BF = 0; // 開始ブザーフラグ Time2 = 0; // インターバル0 Mode = 0; // 動作モード(0:設定 1:開始 2:動作中 3:インターバル) while(1){ // 通常のループ switch(Mode){ // 0:設定 1:開始 2:動作中 3:インターバル case 0: // 時間設定 sw = getkey(); // RB0〜3:どのキーを押した? switch(sw){ case 1: // 分のボタンON m_time = m_time + 60; bzr1(); if(m_time > 240){ m_time = 0; // 4分を超えたら0に } while(RB0 == 0); // チャタリングの防止 delay_10ms(2); break; case 2: // 10秒のボタンON if(m_time == 0 && s_time < 20){ s_time = s_time + 5; }else{ // 最初だけ 5秒ずつ加算(15秒の設定可) s_time = s_time + 10; } bzr1(); if(s_time > 55){ s_time = 0; // 55秒を超えたら0に } while(RB1 == 0); delay_10ms(2); break; case 3: // インターバル設定 Time2 = Time2 + 5; // 5秒ずつ if(Time2 > 30)Time2 = 0; // 最長30秒 bzr1(); while(RB2 == 0); delay_10ms(2); break; case 4: // スタートボタンON while(RB3 == 0); delay_10ms(10); Time = m_time + s_time; if(Time > 0){ Mode = 1; }else{ //時間設定無しで開始ボタンは、稼働不可 Mode = 0; } break; } // 時間設定中の表示 Time = m_time + s_time; Hyouji1a(); Hyouji1b(); break; case 1: // 開始へ T0IE = 1; // タイマ0始動 Mode = 2; BF = 1; // ブザーフラグ lcd_cmd(0x01); // 一旦消去(前面LCD) break; case 2: // 設定時間計測中 Hyouji1b(); Hyouji2(); // 前面LCDはビッグフォント if(RB3 == 0){ // 止(始)ボタンONなら while(RB3 == 0); delay_10ms(10); T0IE = 0; // タイマ0停止 Time = m_time + s_time; // タイムの再設定 Mode = 0; // 時間設定へ break; } if(BF == 1){ bzr2(); // 開始のブザーを鳴らす delay_10ms(2); // ピッピッ bzr2(); BF = 0; } if(0 < Time && Time < 4){ // 残り3秒からプッ if(chflg == 1){ // 1秒経過ごと chflg = 0; bzr1(); } } break; case 3: // インターバル lcd_cmd(0x01); // 画面消去(前面LD) if(melody_on == 1){ melody_on = 0; // フラグをリセット melody_k(); // メロディを } break; default: break; } // end_switch } // end_while }else{ // RA2=0(on)の場合 // カウンター動作 PORTB = 0x0F; RIGHT = 0; LEFT = 0; SIDE = 2; // (0:右 1:左)最初はどちらでもない colon = 1; // コロン表示 while(1){ Tact = getkey(); // どのキー(RB0〜RB3)を押した? switch(Tact){ case 1: // 左得点 bzr1(); LEFT++; if(LEFT > 99)LEFT = 0; if(SIDE != 1){ SIDE = 1; // 左DOT点灯 colon = 1; // サイドが変わったら }else{ // コロン点灯 colon =0; } while(RB0 == 0); delay_10ms(10); // タクトスイッチの誤動作防止 break; case 2: // 左減点 bzr2(); if(LEFT)LEFT--; // 0なら減点無し while(RB1 == 0); delay_10ms(10); break; case 3: // 右減点 bzr2(); if(RIGHT)RIGHT--; // 0なら減点無し while(RB2 == 0); delay_10ms(10); break; case 4: // 右得点 bzr1(); RIGHT++; if(RIGHT > 99)RIGHT = 0; if(SIDE != 0){ SIDE = 0; // 右DOT点灯 colon = 1; }else{ colon = 0; } while(RB3 == 0); delay_10ms(10); break; default: break; } // end_case Hyouji3(); } // end_while2 } // end_else } // end_main /** 割込み処置 **/ void interrupt isr(void){ // Timer0 は秒数カウント、Timer2はメロディ用 if(TMR2IF){ // Timer2 割込みを確認 TMR2IF = 0; // Timer2 フラグ リセット accWave += incWave; // 周期計算 if((STATUS & 0x01)==1)wave ^= 1;// キャリが出れば、波形反転 if(wave)CCPR3L = amp; // 波形ONなら、 出力あり else CCPR3L = 0; // OFFなら、出力なし } if(T0IF == 1){ // タイマー0の割込み発生か? TMR0 = 0x64; // タイマー0の初期化 Count++; // 割込み発生の回数をカウントする T0IF = 0; // タイマー0割込フラグをリセット if(Count >= 50){ // 割込みを50回カウントすると約1秒 Count = 0; Time--; chflg = 1; // 1秒経過フラグ } if(Mode == 3 && Time == 1)TRISA3 = 1;// 残1秒でメロディ消す if(Time==0){ if(Mode == 2){ // 通常のタイムアップ? if(Time2 == 0){ // インターバル無しなら Time = m_time + s_time; // 繰り返し時間をセット Mode = 1; }else{ Time = Time2; melody_on = 1; Mode = 3; // インターバル・モードへ } }else if(Mode == 3){ // インターバルの終了なら melody_stop = 1; // メロディ中止フラグ Time = m_time + s_time; Mode = 1; } // end_if(Mode == 2) } // End_if(Tome==0) } //if (T0IF == 1) } /** メロディ関数 **/ void melody_k(){ unsigned char Step; CCP3CON = 0b00001100;//CCP3をPWMモードに設定 TRISA3 = 0; // 音源(RA3)を出力に Track = 0; melody_stop = 0; // フラグリセット Step = 1; TMR1ON = 1; while(1){ //------------ 1ms 毎のタイミング処理 ---------------------- if(TMR1IF){ // 1ms 毎に実施 TMR1H = 0xE1; // 次の 1ms を設定 TMR1IF = 0; // フラグクリア //------- 振幅調整 50ms ----------------------------------- if(AmpCnt-- == 1){ AmpCnt = EnvelopeConst; // 音量を 50ms毎に amp = (int)amp * 15/16; // -6% する } //------- テンポ調整 ----------------------------------- if(TmpCnt-- == 1){ TmpCnt = tempo; // テンポ毎に TmpFlg = 1; // テンポフラグをセット } //------- Silent時間 ----------------------------------- if(SltCnt-- == 1){ // 消音時間になれば SltFlg = 1; // 消音フラグをセット } } if(RB3 == 0){ // 始/止が押されたなら while(RB3 == 0); delay_10ms(2); Step = 6; // 終了処理へ Mode = 0; } if(chflg == 1){ chflg = 0; // Hyouji1a(); // 前面表示は無し Hyouji1b(); } if(melody_stop == 1)Step = 6; //------------------- 主フロー制御 --------------- switch(Step){ case 1: // ====== 楽譜の設定 ====== if(Music[Track]==0xFFFF)Track=0;// 楽譜終了なら先頭に tempo = 2500/Music[Track++]; // 楽譜のテンポ取得(7500→2500) TMR2ON = 1; // Timer2 on TmpCnt = tempo; // テンポセット TmpFlg = 0; // フラグりセット Step = 2; break; case 2: // ====== 音符の設定 ====== Note = Music[Track++]; // 音符を取得 if(Note == 0xFFFF){ // 曲の終了なら Track = 0; // 先頭に Step = 1; break; } Len = Note & 0x00FF; // 音符の長さ取得 Note = Note >> 8; // 音高を取り出す if(Note){ // 音符なら incWave = dW_tbl[Note - 23];// 音高を繰返し時間に変換 ampNext = 0x7F; // 音量最大 }else{ // 休符なら incWave = 0; // 繰返し なし ampNext = 0; // 音量OFF } Step = 3; break; case 3: // ====== 音符の演奏開始 ====== if(TmpFlg){ // テンポ待ち TmpFlg = 0; // テンポフラグリセット amp = ampNext; // 音量最大 AmpCnt = EnvelopeConst; // 音量減少リセット Step = 4; } break; case 4: // ====== 音符の演奏継続 ====== if(TmpFlg){ // テンポ待ち TmpFlg = 0; // テンポフラグリセット if(Len-- == 2){ // 音符終了なら SltCnt = tempo - Silent;// 消音時間をセットし SltFlg = 0; // 消音フラグをリセット Step = 5; } } break; case 5: // ====== 音符の演奏終了 ====== if(SltFlg){ // 時間を待つ amp = 0; // 音量OFF Step = 2; // 次の音符取得へ } break; case 6: // ====== 楽譜の演奏終了 ====== TMR1ON = 0; // Timer1 Off TMR2ON = 0; // Timer2 Off break; } // end_switch if(Step == 6){ TRISA3 = 1; // RA3を入力にして return; } } // end_while } // end_melody_k /***** 表示1( LCDで残り時間やインターバル時間を表示 ) *****/ void Hyouji1a(void){ min1 = Time /60; // 総秒数→x分 sec1 = Time % 60; // 総秒数→x0秒 sec2 = Time2; // インターバル秒 i_to_str(1,min1, Msg1+8); // Msg1の9桁目から i_to_str(2,sec1, Msg1+10); // Msg1の11桁目から i_to_str(2,sec2, Int1+10); // Int1の11桁目から lcd_cmd(0x80); // 表示位置を1行目1列[00H]に設定 lcd_str(Msg1); // [00H]から書込まれる(表示する) lcd_cmd(0xC0); // 表示位置を2行目1列[40H]に設定 lcd_str(Int1); // [40H]から書込まれる(表示する) } void Hyouji1b(void){ if(Mode == 3){ min1 = (m_time + s_time) / 60; sec1 = (m_time + s_time) % 60; sec2 = Time; }else{ min1 = Time /60; // 総秒数→x分 sec1 = Time % 60; // 総秒数→x0秒 sec2 = Time2; // インターバル秒 } i_to_str(1,min1, Msg2+4); // Msg2の5桁目から i_to_str(2,sec1, Msg2+6); // Msg2の7桁目から i_to_str(2,sec2, Int2+6); // Int2の7桁目から lcd_cmd2(0x80); // 表示位置を1行目1列[00H]に設定 lcd_str2(Msg2); // [00H]から書込まれる(表示する) lcd_cmd2(0xC0); // 表示位置を2行目1列[40H]に設定 lcd_str2(Int2); // [40H]から書込まれる(表示する) } void Hyouji2(){ // BigFont // 表示は左から(Set DDRAM Address 0b1xxxxxxx + position) // s[0]〜[3]はアドレスの数値、n1〜n4は文字を入れる if(Time < 60){ su[0] = ' '; // 分表示なし su[1] = ' '; // コロン無し }else{ su[0] = (Time / 60); su[1] = 10; // コロン有り } if(Time < 10){ su[2] = ' '; su[3] = Time; }else{ su[2] = (Time % 60) / 10; su[3] = Time % 10; } // 表示部 unsigned char adr1 = 0x80; // 1行目左(00) unsigned char adr2 = 0xC0; // 2行目左(40) for(char k=0; k<4; k++){ // 4文字分 if(su[k] == ' '){ // 値が無い時は lcd_cmd(adr1); for(char m=0; m<3; m++){// 空白で埋める lcd_data(0x20); // 0x20:空白 } lcd_cmd(adr2); for(char n=3; n<6; n++){ lcd_data(0x20); } }else{ lcd_cmd(adr1); // 書き始め:左上へ unsigned char Ban; Ban = su[k]; for(char m=0; m<3; m++){ // 上3桁表示 lcd_data(BigNum[Ban][m]); } lcd_cmd(adr2); // 下3桁表示 for(char n=3; n<6; n++){ lcd_data(BigNum[Ban][n]); } } adr1 += 4; // 4桁(文字3桁+空白1桁)右へ adr2 += 4; } } // カウンター用・表示データの設定(LEFT RIGHTの数値→LCDのデータに) void Hyouji3(void){ // SIDE:0 右 SIDE:1 左 ::後ろから見て // 上側のLCDの表示は左右が逆になる。 if(SIDE == 0){ Counter_b1[2] = ' '; // 上面LCD Counter_b1[7] = 0x2A; // アスタリスク lcd_cmd(0x83); // 前面LCD:4桁目 lcd_data(0x2A); // アスタリスク lcd_cmd(0x8C); // 13桁目 lcd_data(0x20); // 空白 }else if(SIDE == 1){ Counter_b1[2] = 0x2A; Counter_b1[7] = ' '; lcd_cmd(0x83); lcd_data(0x20); lcd_cmd(0x8C); lcd_data(0x2A); } i_to_str(2, RIGHT, Counter_b2+6); // 上2行目右 i_to_str(2, LEFT, Counter_b2+1); // 上2行目左 su[0] = RIGHT / 10; // 値をセット if(su[0] == 0)su[0]=' '; su[1] = RIGHT % 10; su[2] = LEFT / 10; if(su[2] == 0)su[2]=' '; su[3] = LEFT % 10; Counter_b2[4]= ' ';// コロン消去 lcd_cmd(0x88); lcd_data(0x20); lcd_cmd(0xC8); lcd_data(0x20); if(colon == 1){ // コロン点灯 Counter_b2[4]= ':'; lcd_cmd(0x88); lcd_data(0xA5); lcd_cmd(0xC8); lcd_data(0xA5); } lcd_cmd2(0x80); lcd_str2(Counter_b1); lcd_cmd2(0xC0); lcd_str2(Counter_b2); unsigned char adr1 = 0x80; // 1行目左(00) unsigned char adr2 = 0xC0; // 2行目左(40) unsigned char Ban; for(char k=0; k<4; k++){ // 4文字分 if(su[k] == ' '){ // 値が無い時は lcd_cmd(adr1); for(char m=0; m<3; m++){// 空白で埋める lcd_data(0x20); } lcd_cmd(adr2); for(char n=3; n<6; n++){ lcd_data(0x20); } }else{ lcd_cmd(adr1); // 書き始め:左上へ Ban = su[k]; for(char m=0; m<3; m++){ // 上3桁表示 lcd_data(BigNum[Ban][m]); } lcd_cmd(adr2); // 下3桁表示 for(char n=3; n<6; n++){ lcd_data(BigNum[Ban][n]); } } if(k == 1){ adr1 += 5; // 中央は2列空ける adr2 += 5; }else{ adr1 += 4; adr2 += 4; } } } //*** int整数からASCII文字に変換 *** void i_to_str(char digit, unsigned int data, char *buffer){ char i; buffer += digit; // 最後の数字位置 for(i=digit; i>0; i--) { // 変換は下位から上位へ buffer--; // ポインター1 *buffer = (data % 10) + '0'; // ASCIIへ data = data / 10; // 次の桁へ } } /** Start Condiotion **/ void I2c_Start(void){ // SCL,SDAは通常:High SDA = 0; // 先に SDA=Low TRISSDA = 0; // SDA出力 } /** Stop Condition **/ void I2c_Stop(void){ SCL = 0; // SCL Low SDA = 0; // SDA Low TRISSDA = 0; // 出力モードに戻す SCL = 1; // 先にSCLをHigh SDA = 1; // 後からSDAをHigh } /** I2c_で1バイト出力(1ビットずつ) **/ unsigned char I2c_Out(unsigned char data){ int i; unsigned char BitPos, ACK; TRISSDA = 0; // SDA出力モード BitPos = 0x80; // ビット位置初期値(左端) for(i=0; i<8; i++) // 8ビット繰り返し { SCL = 0; // SCL Low if((data & BitPos) != 0) // ビット出力 SDA = 1; // SDA High else SDA = 0; // SDA Low BitPos = BitPos >> 1; // ビット位置移動 SCL = 1; // SCL Highに戻す } /* Ack チェック */ SCL = 0; // クロック1Low TRISSDA = 1; // 入力モードにしてACK入力 ACK = SDA; // ACKチェック for delay ACK = SDA; // ACKチェック SCL = 1; // クロックHighに戻す return(ACK); // ACKを戻り値とする } /** アダプターへデータ送信(基本) **/ void lcd_common(unsigned char data){ I2c_Start(); // スタート I2c_Out(ADDR1); // LCD1のアドレス I2c_Out(data); // 表示データ出力 I2c_Stop(); // ストップ delay_10us(5); // 30μsec待ち } /** 液晶へ1文字表示データ出力 **/ void lcd_data(unsigned char data){ unsigned char hydata; // 上位4ビット hydata = data & 0xf0 | 0x0D; // +Backlight,EN,RS lcd_common(hydata); delay_10us(2); lcd_common(hydata & ~0x04); // Enable_Pulse -> Low delay_10us(2); // 下位4ビット hydata = (data << 4) & 0xf0 | 0x0D; // +Backlight,EN,RS lcd_common(hydata); delay_10us(2); lcd_common(hydata & ~0x04); // Enable_Pulse -> Low delay_10us(5); } /** 液晶へ1コマンド出力 **/ void lcd_cmd(unsigned char data){ unsigned char command; // 上位4ビット command = data & 0xf0 | 0x0C; // +Backlight,EN,(RS:0) lcd_common(command); delay_10us(2); lcd_common(command & ~0x04); // Enable_Pulse -> Low delay_10us(2); // 下位4ビット command = (data << 4) & 0xf0 | 0x0C;// +Backlight,EN lcd_common(command); delay_10us(2); lcd_common(command & ~0x04); // Enable_Pulse -> Low delay_10us(5); } /** 初期化関数 **/ void lcd_init1(void){ delay_10ms(10); // 0.1秒待つ(電源が安定するまで) // 8ビットモード lcd_common(0x34); delay_10us(1); lcd_common(0x34 & ~0x04);// Enable→0 lcd_common(0x34); delay_10us(1); lcd_common(0x34 & ~0x04); lcd_common(0x34); delay_10us(1); lcd_common(0x34 & ~0x04); delay_10us(1); // 4bit_mode & BackLight,EN lcd_common(0x2C); // '2'のデータと'1100' delay_10us(1); lcd_common(0x2C & ~0x04);// Enable を 0 に delay_10us(5); // ここから4ビット通常モード delay_10us(10); lcd_cmd(0x28); // 4ビット × 2, 2line delay_10us(10); lcd_cmd(0x08); // Display off,Cutsor off Blink off delay_10us(10); lcd_cmd(0x01); // Display clear delay_10ms(1); lcd_cmd(0x06); // Entry mode delay_10us(10); lcd_cmd(0x0c); // Display on,Cursor off delay_10us(10); } /** 文字列表示関数 **/ void lcd_str(char *ptr){ while(*ptr != 0) //文字取り出し lcd_data(*ptr++); //文字表示 } /* ここからLCD2 */ /** 液晶へ1文字表示データ出力 **/ void lcd_data2(unsigned char data){ I2c_Start(); // スタート I2c_Out(ADDR2); // AQM0802のアドレス I2c_Out(0x40); // 表示データ指定 I2c_Out(data); // 表示データ出力 I2c_Stop(); // ストップ delay_10us(3); // 遅延 } /** 液晶へ1コマンド出力 **/ void lcd_cmd2(unsigned char cmd){ I2c_Start(); // スタート I2c_Out(ADDR2); // アドレス I2c_Out(0x00); // コマンド指定 I2c_Out(cmd); // コマンド出力 I2c_Stop(); // ストップ delay_10us(3); // 30μsec待ち } /** 初期化関数AQM0802 **/ void lcd_init2(void){ delay_10ms(10); lcd_cmd2(0x38); // 8bit 2line Normal mode lcd_cmd2(0x39); // 拡張モード設定 lcd_cmd2(0x14); // OSC 183Hz BIAS 1/5 /* コントラスト設定 */ lcd_cmd2(0x70 + (CONTRAST & 0x0F)); lcd_cmd2(0x5C + (CONTRAST >> 4)); // lcd_cmd2(0x6A); // Follower for 5.0V lcd_cmd2(0x6B); // Follower for 3.3V delay_10ms(3); lcd_cmd2(0x38); // Set Normal mode lcd_cmd2(0x0C); // Display On lcd_cmd2(0x01); // Clear Display } /** 文字列表示関数 **/ void lcd_str2(char *ptr){ while(*ptr != 0) //文字取り出し lcd_data2(*ptr++); //文字表示 } // 押されている(=0の)SWを探す unsigned char keysearch(){ unsigned char tsw; switch (PORTB & 0b00001111){// RB0〜RB3 case 0b00001110:// 押されたビットが0になる tsw = 1; break; case 0b00001101: tsw = 2; break; case 0b00001011: tsw = 3; break; case 0b00000111: tsw = 4; break; default: tsw = 0; } return (tsw); } // 5回連続で「押」を確認したら、その値を返す unsigned char getkey(){ unsigned char newval, oldval, cnt; oldval = 0x00; while(1){ for(cnt = 0; cnt < 5; cnt++){ newval = keysearch(); if(newval != oldval){ cnt = 0; oldval = newval; } delay_10us(10); } return(newval); } } // 遅延タイマ void delay_10us(unsigned char t1){ while(t1){ __delay_us(10); // 10μsec t1--; // 10μsec x time } } void delay_10ms(unsigned char t2){ while(t2){ __delay_ms(10); // 10msec t2--; // 10msec x time } } // ブザー用ルーチン void bzr1(void){ // 残り3秒および得点のプ TRIS_Bz = 0; // 出力指定 int i; for (i = 0; i < 80 ; i++) { BzPort = 1 ; delay_10us(60); BzPort = 0 ; delay_10us(60); } TRIS_Bz = 1; // 入力に戻す } void bzr2(void){ // 開始および減点のピ TRIS_Bz = 0; int i; for (i = 0; i < 60 ; i++) { BzPort = 1 ; delay_10us(40); BzPort = 0 ; delay_10us(40); } TRIS_Bz = 1; } // メロディ用データ ファイル名:ohkinakurino_k.h const unsigned int Music[] = { 130, // 大きな栗の木の下で 0x3C08,0x3C04,0x3E04,0x4004,0x4004,0x4308,0x4004,0x4004, 0x3E04,0x3E04,0x3C08,0x0008,0x4008,0x4108,0x4308,0x4808, 0x4508,0x4808,0x430C,0x0004,0x4808,0x4808,0x4708,0x4308, 0x4504,0x4504,0x4504,0x4504,0x4308,0x0008,0x3C08,0x3C04, 0x3E04,0x4004,0x4004,0x4308,0x4004,0x4004,0x3E04,0x3E04, 0x3C0C,0x0004, 0xFFFF, 0xFFFF, };