// //  ストップウォッチ&タイマー // 2007/5/21 by TEP // 2007/5/25 基本形がほぼ完成 // 2007/5/27 ルーチンなど整理 // #include #include // Definition of base section #define SW_ON 0 #define SW_OFF 1 #define LOW 0 #define HIGH 1 #define SW1 p3_5 #define SW2 p1_0 #define RE_A p1_1 #define RE_B p1_2 #define BZ p1_3 #define LCD_DB p1 #define LCD_DB7 p1_7 #define LCD_DB6 p1_6 #define LCD_DB5 p1_5 #define LCD_DB4 p1_4 #define LCD_STB p3_3 #define LCD_RS p3_4 // #define LED p1_0 // 大域変数 char Mode_tors; // 1.タイマー 2.ストップウオッチ // タクトスイッチ用 char Sw_state = 0; char Sw1_state = 0; // SW1 結果 ON=1 OFF=0 char Sw2_state = 0; // SW2 結果 ON=1 OFF=0 // ロータリーエンコーダー用 char Newdata,Olddata; char Newport0,Newport1; char Oldport0,Oldport1; signed char Enc_direction; // タイマ・計時用 long Msecond; char Second; char Minute; char Hour; char SetSecond = 0; char SetMinute = 0; char SetHour = 0; long Count = 0; char ii = 0; // 表示メッセージバッファ char MsgALM1[] = "Timer 00:00:00\0"; char MsgALM2[] = "Set Hour 00\0"; char MsgALM3[] = "Set Minute 00\0"; char MsgALM4[] = "Set Second 00\0"; char MsgALM5[] = "1.Start 2.Set \0"; char MsgALM6[] = "1.Stop 2.Menu \0"; char Msg1[] = "Timer&StopWatch \0"; char Msg2[] = "1.Timer 2.StopW \0"; char Msg3[] = "Time 00:00:00.00\0"; char Msg4[] = "Lap 00:00:00.00\0"; char MsgSpace[]= " \0"; // プロトタイピング void Lcd_init(void); void Lcd_output(char *str); void Lcd_clear(void); void Lcd_cmd(char cmd); void Lcd_data(char asci); void Lcd_out(char code, char flag); void Lcd_locate(char x, char y); void Lcd_cursol(char c_mode); void Lcd_line_print(char y,char *str); void Lcd_Itostring(char y, int digit, unsigned long data, char *buffer, char z); void Time_update(void); void Itostring(int digit, unsigned long data, char *buffer); void Timer_disp(void); void Timer_set(void); void Delay(long usec); void Delay_ms(unsigned long msec); void Get_encdata(void); void Get_sw_data(void); void Buzzer(char mode); // ----- ポート入出力の設定 ----- void sfr_iod(void) { pd1_4 = 1; // LCD pd1_5 = 1; pd1_6 = 1; pd1_7 = 1; pd3_3 = 1; pd3_4 = 1; pd1_3 = 1; // BEEP //drr0 = 1; // LED //pd1_0 = 1; //p1_0 = 1; // H で LED Off } // ----- ポートデータの初期設定 ----- void sfr_init(void) { p1 = 0xf0; tcss = 0x11; // timer x の設定 prex = 250-1; tx = 100-1; txs = 0; // timer X 停止 prez = 25 - 1; // timer Z の設定 tzsc = 50 - 1; tzpr = 50 - 1; tzmr = 0x50; pum = 0; tzs = 0; // timer Z 停止 } // ----- クロックの切替 (20MHz) ----- void main_ck(void) { asm("FCLR I"); prcr = 1; cm13 = 1; cm15 = 1; cm05 = 0; cm16 = 0; cm17 = 0; cm06 = 0; asm("nop"); asm("nop"); asm("nop"); asm("nop"); ocd2 = 0; prcr = 0; } //-------------------------------------------------------------- // メインルーチン //-------------------------------------------------------------- void main(void) { main_start: main_ck(); // メインクロック切替 sfr_init(); // ポート初期化 sfr_iod(); // ポート入出力設定 Lcd_init(); // LCD初期化 Lcd_cursol(1); Lcd_line_print(1,Msg1); // Msg1[] = "Timer&StopWatch \0" Lcd_line_print(2,Msg2); // Msg2[] = "1.Timer 2.StopW \0" asm("FSET I"); // 割り込み許可 Sw1_state = Sw2_state =0; // スイッチ入力フラグ初期化 // モードの選択ルーチン Mode_tors = 1.タイマー 2.ストップウオッチ while ((Sw1_state==0) && (Sw2_state==0)){ Get_sw_data(); // スイッチ入力 } Buzzer(1); if (Sw1_state == 1){ // Mode_tors : 動作モードフラグ Mode_tors = 1; // 1.タイマー 2.ストップウオッチ } else if (Sw2_state == 1){ Mode_tors = 2; } // --------------------------------------------------------------------------- // タイマー時の処理ルーチン // --------------------------------------------------------------------------- timer_start: if ( Mode_tors == 1 ){ Lcd_line_print( 1, MsgALM1 ); // スタートボタン処理 ------------------------------------------------------- Delay_ms(500); Lcd_line_print( 2, MsgALM5 ); // MsgALM5[] = "1.Start 2.Set \0" Sw1_state = Sw2_state = 0; while ((Sw1_state == 0) && (Sw2_state==0)){ // SW入力 Get_sw_data(); } Delay_ms(500); // SW1でタイマースタートするが、スタートまでにインターバルがある。無視! if ( Sw2_state == 1 ){ // このDelayがないと、次のキー入力で都合が悪い  Buzzer(1); // SW2でタイマー時間設定へ Hour = SetHour; Minute = SetMinute; Second = SetSecond; Timer_disp(); Timer_set(); goto timer_start; } // ダウンカウント開始 ------------------------------------------------------- Buzzer(1); Lcd_line_print( 2, MsgALM6 ); // MsgALM6[] = "1.Stop 2.Menu \0"; Count = 100; // 1秒経過カウント txs = 1; // timerX Start while(1){ while (Count >0){ while(ir_txic == 0){} ir_txic = 0; Count --; if (SW1==SW_ON){ // SW1=STOPボタン Buzzer(1); Delay_ms(500); goto timer_start; } if (SW2==SW_ON){ // SW2=トップメニューへ戻る Buzzer(1); Delay_ms(500); goto main_start; } } // ダウンカウントと桁下がり判断ルーチン -------------------------------- Timer_disp(); if (Second==0){ if (Minute==0){ if(Hour==0){ Timer_disp(); Buzzer(5); Hour = SetHour; Minute = SetMinute; Second = SetSecond; Timer_disp(); goto timer_start; } Hour--; Minute = 60; } Minute--; Second = 60; } Second--; Count = 100; } goto timer_start; } // --------------------------------------------------------------------------- // ストップウォッチモード メインルーチン // --------------------------------------------------------------------------- stopwatch_start: strcpy(Msg3 , "Time 00:00:00.00"); // ストップウォッチ 表示初期化 strcpy(Msg4 , "Lap 00:00:00.00"); Sw1_state = Sw2_state = 0; if ( Mode_tors == 2 ){ // ストップウォッチの処理 Lcd_clear(); Lcd_output(Msg3); // Msg3[] = "Time 00:00:00.00\0" Lcd_cmd(0xC0); Lcd_output(Msg4); Sw1_state = 0; ii=0; while (Sw1_state == 0){ Get_sw_data(); } // SW1でスタート Sw1_state = Sw2_state = 0; Delay_ms(500); // スタートスイッチを押してから計測開始までの Buzzer(1); // インターバルができてしまうが無視する Hour = 0; Minute = 0; Second = 0; Msecond = 0; txs= 1; // timerX スタート while (Sw1_state == 0){ // SW1でストップ while(ir_txic == 0){} // 10msのインターバル ir_txic = 0; // 割り込み要求ビットクリア Get_sw_data(); Time_update(); Itostring(2, Msecond, Msg3 + 14); Itostring(2, Second, Msg3 + 11); Itostring(2, Minute, Msg3 + 8); Itostring(2, Hour, Msg3 + 5); Lcd_cmd(0x80); // カーソル1行目先頭に移動 Lcd_output(Msg3); // Msg3[] = "Time 00:00:00.00\0" if ( Sw2_state == 1 ){ // SW2でラップ表示 Itostring(2, Msecond, Msg4 + 14); Itostring(2, Second, Msg4 + 11); Itostring(2, Minute, Msg4 + 8); Itostring(2, Hour, Msg4 + 5); Lcd_cmd(0xC0); Lcd_output(Msg4); Sw2_state = 0; } } Sw1_state = Sw2_state = 0; txs= 0; ir_txic = 0; Buzzer(1); Delay_ms(500); while (Sw1_state==0) { Get_sw_data(); if (Sw2_state == 1){ // SW2でストップウオッチリセット Buzzer(1); Lcd_output(Msg3); Delay_ms(500); goto stopwatch_start; } } Sw1_state = Sw2_state = 0; } Buzzer(5); Delay_ms(500); goto main_start;// メインメニューに戻る } //-------------------------------------------------------------- // タイマー 設定時間入力 //-------------------------------------------------------------- void Timer_set(void) { Sw1_state = Sw2_state = 0; Count = SetHour; // MsgALM1[] = "Timer hh:mm:ss\0" Lcd_Itostring( 2, 2, Count, MsgALM2, 14 ); // 表示用文字列の書き換え 及び 表示 // MsgALM2[] = "Set Hour 00\0"; Delay_ms(500); Sw1_state = 0; while( Sw1_state == 0 ) { // SW1でセット Get_encdata(); // エンコーダー入力 Get_sw_data(); // SW入力 if ( Count >=24 ) { Count = 0; } Lcd_Itostring( 2, 2, Count, MsgALM2, 14 ); } Buzzer(1); Hour = SetHour = Count; Lcd_Itostring( 1, 2, Count, MsgALM1, 8 ); // MsgALM1[] = "Timer XX:mm:ss\0" // 設定「分」入力ルーチン ---------------------------------------------------- Count = SetMinute; Lcd_Itostring( 2,2,Count,MsgALM3,14 ); // MsgALM3[] = "Set Minute 00\0"; Delay_ms(500); Sw1_state = 0; while(Sw1_state == 0) { Get_encdata(); // エンコーダー入力 Get_sw_data(); // SW入力 if (Count >=60) { Count = 60; } Lcd_Itostring( 2,2,Count,MsgALM3,14 ); } Minute = SetMinute = Count; Buzzer(1); Lcd_Itostring( 1,2,Count,MsgALM1,11 ); // MsgALM1[] = "Timer hh:XX:ss\0" // 設定「秒」入力ルーチン ---------------------------------------------------- Count = SetSecond; Lcd_Itostring( 2,2,Count,MsgALM4,14 ); // MsgALM4[] = "Set Second 00\0"; Delay_ms(500); Sw1_state = 0; while(Sw1_state == 0) { Get_encdata(); // エンコーダー入力 Get_sw_data(); // SW入力 if (Count >=60) { Count = 60; } Lcd_Itostring( 2,2,Count,MsgALM4,14); } Second = SetSecond = Count; Buzzer(1); Lcd_Itostring( 1,2,Count,MsgALM1,14 ); // MsgALM1[] = "Timer hh:mm:XX\0" } //-------------------------------------------------------------- // タイマー 時間表示処理 //-------------------------------------------------------------- void Timer_disp(void) { Itostring(2,Hour,MsgALM1+8); Itostring(2,Minute,MsgALM1+11); Itostring(2,Second,MsgALM1+14); Lcd_locate(1,1); Lcd_output(MsgALM1); } //-------------------------------------------------------------- // ストップウォッチ カウント処理 //-------------------------------------------------------------- void Time_update(void) { Msecond = Msecond + 10; if (Msecond == 1000){ Msecond = 0; Second++; // 秒カウントアップ if(Second == 60){ // 60秒か? Second = 0; Minute++; // 分カウントアップ if(Minute == 60){ // 60分か? Minute = 0; Hour++; // 時カウントアップ if(Hour == 24){ // 24時か? Hour = 0; } } } } } //-------------------------------------------------------------- // 数値から文字列に変換(Char型) //-------------------------------------------------------------- void Itostring(int digit, unsigned long data, char *buffer) { char i; buffer += digit; //文字列の最後 for(i=digit; i>0; i--) //最下位桁から上位へ { buffer--; //ポインター1 *buffer = (data % 10) + '0'; //その桁数値を文字にして格納 data = data / 10; //桁-1 } } //-------------------------------------------------------------- // 数値から文字列に変換、指定行に表示 //-------------------------------------------------------------- void Lcd_Itostring(char y, int digit, unsigned long data, char *buffer, char z) { Itostring(digit, data, buffer+z); if (y==1){ Lcd_cmd(0x80); } else if (y==2){ Lcd_cmd(0xC0); } Lcd_output(buffer); } //-------------------------------------------------------------- // ロータリーエンコーダー処理 //-------------------------------------------------------------- void Get_encdata(void) { Newdata = (RE_A << 1) + RE_B; if ( (Olddata != Newdata) ) { Newport0 = Newdata & 0x01; Newport1 = Newdata & 0x02; Oldport0 = Olddata & 0x01; Oldport1 = Olddata & 0x02; if ((Oldport0==0)&&(Newport0==1)){ //Switch Edge detect if (Newport1==2){ //rotate Count++; } } if ((Oldport1==0)&&(Newport1==2)){ //Switch Edge detect if (Newport0==1){ //rotate if (Count>0){ //ゼロ以下にはならない Count--; } } } Olddata = Newdata; //Refresh data } } //-------------------------------------------------------------- // スイッチ入力処理(ディレイによるチャタリング除去) //-------------------------------------------------------------- void Get_sw_data(void) { if (SW1 == SW_ON){ Delay_ms(30); if (SW1 == SW_ON){ Sw1_state = 1; } } if (SW2 == SW_ON){ Delay_ms(30); if (SW2 == SW_ON){ Sw2_state = 1; } } if ((Sw1_state==1) || (Sw2_state==1)){ Sw_state = 1; } else { Sw_state = 0; Sw1_state = 0; Sw2_state = 0; } } //-------------------------------------------------------------- // ブザー出力(タイマZ使用 output:p1_3) // mode: 1.単発 2.複数回の回数指定数値 //-------------------------------------------------------------- void Buzzer(char mode) { if (mode == 1){ tzs = 1; Delay_ms(200); tzs = 0; } else { while (mode > 0){ tzs = 1; Delay_ms(500); tzs = 0; Delay_ms(500); mode--; } } } //----- ディレイ関数 msec単位 ----- void Delay_ms(unsigned long msec) { msec = (msec * 5000) / 40000; //クロックで補正 msec = msec * 1000; //時間調整 while(msec--){} } //----- ディレイ関数 1usec単位 ----- void Delay(long usec) { usec = (usec * 20000) / 45000; while(usec--){} } //---------------------------------------------------- // 液晶表示器制御ライブラリ //---------------------------------------------------- //----- LCD初期化関数 ----- void Lcd_init() { Delay(20000); //20msec wait Lcd_out(0x03, 1); //8bit mode set Delay(5000); //5msec wait Lcd_out(0x03, 1); //8bit mode set Delay(1000); Lcd_out(0x03, 1); //8bit mode set Delay(1000); Lcd_out(0x02, 1); //4bit mode set Delay(1000); Lcd_cmd(0x2C); //DL=0 4bit mode Lcd_cmd(0x08); //display off C=D=B=0 Lcd_cmd(0x0E); //display on D=B=1 C=0 Lcd_cmd(0x06); //entry I/D=1 S=0 Lcd_cmd(0x01); //all clear } //----- データ出力サブ関数 ----- void Lcd_out(char code, char flag) { LCD_DB = (LCD_DB & 0x0f) | (code << 4); //出力データ下位4ビットを出力 if (flag == 0) //表示データかコマンドか LCD_RS = 1; //表示データの場合RS=1 else LCD_RS = 0; //コマンドデータの場合RS=0 asm("NOP"); //NOP スキュー確保 LCD_STB = 1; //STB ON asm("NOP"); asm("NOP"); //パルス幅確保230nsec以上 asm("NOP"); asm("NOP"); LCD_STB = 0; //STB OFF } //----- 1文字表示関数 ----- void Lcd_data(char asci) { Lcd_out(asci>>4, 0); //上位4ビット出力 Lcd_out(asci, 0); //下位4ビット出力 Delay(50); //50μsec待ち } //----- コマンド出力関数 ----- void Lcd_cmd(char cmd) { Lcd_out(cmd>>4, 1); //上位4ビット出力 Lcd_out(cmd, 1); //下位4ビット出力 if((cmd == 0x01) || (cmd == 0x02)) Delay(2000); //2msec待ち else Delay(50); //50usec待ち } //----- 全消去関数 ----- void Lcd_clear() { Lcd_cmd(0x01); //初期化コマンド出力 } //----- 文字列出力関数 ----- void Lcd_output(char *str) { while(*str != 0x00) //文字列の終わり判定 { Lcd_data(*str); //文字列1文字出力 str++; //ポインタ+1 } } //----- カーソル位置に移動 ----- void Lcd_locate(char x, char y) { char i; if (y == 1){ Lcd_cmd(0x02); x--; while ( x ){ Lcd_cmd(0x14); x--; } }else if (y == 2){ Lcd_cmd(0x02); x--; for (i=1;i<=40;i++){ Lcd_cmd(0x14); } while ( x ){ Lcd_cmd(0x14); x--; } } } //----- カーソル表示制御 ----- void Lcd_cursol(char c_mode) { switch ( c_mode){ case 1: // 1.カーソルOFF、ブリンクOFF Lcd_cmd(0x0c); break; case 2: // 2.カーソルOFF、ブリンクON Lcd_cmd(0x0d); break; case 3: // 3.カーソルON、ブリンクOFF Lcd_cmd(0x0e); break; case 4: // 4.カーソルON、ブリンクON Lcd_cmd(0x0f); break; } } //----- 文字列出力関数(行指定あり) ----- void Lcd_line_print(char y,char *str) { if (y == 1){ Lcd_cmd(0x80); } else if(y == 2){ Lcd_cmd(0xC0); } while(*str != 0x00){ //文字列の終わり判定 Lcd_data(*str); //文字列1文字出力 str++; //ポインタ+1 } }