====== 簡易ストップウォッチ(7セグ4桁) ====== ===== 概要 ===== 前回製作した、簡易時計(7セグ4桁)の回路を少し変更して、簡易なストップウォッチを製作しました。 <仕様> * カウントの精度は、次の4種類から選択できます。(表示モード) * 1/1000秒単位、1/100秒単位、1/10秒単位、秒単位 * 4桁の7セグメントLEDに結果を表示します。 ===== 動作原理 ===== <メイン処理> * スタートスイッチ(START)が押下されると、クロック変数(clock_msec)を“0"クリアし、スタートフラグ(flag)を“1"にします。 * ストップスイッチ(STOP)が押下されると、スタートフラグ(flag)を“0"にします。 * クロック変数を引数にして、カウント表示関数(count_disp)を呼び出します。 <カウント表示処理> * 表示モードに応じた桁数に、クロック変数を変換します。 * 変換した値(カウント値)を引数にして、セグメントデータ設定関数(segment_set_data)を呼び出します。 <セグメントデータ設定処理> * 引数で渡されたカウント値(seg1,seg2,seg3,seg4)を、表示用変数(seg_dat)にセットします。 * 引数で渡されたドット値を、ドット変数(dot_point)にセットします。 <割り込み処理> * TIMER2を使用して、1msecの割り込みを発生させます。 * ダイナミック点灯処理を呼び出します。 * スタートフラグ(flag)が“1"であれば、クロック変数(clock_msec)をインクリメントします。 <ダイナミック点灯処理> * 呼び出される毎に、セグメントを順次切り替えて、表示用変数(seg_dat)の値を点灯させます。 * ドット変数(dot_point)に応じたセグメントのドットを点灯させます。 ===== 回路図 ===== 7セグメントLEDは、“簡易接続方式"としています。“標準接続方式"の場合には、簡易時計(7セグ4桁)を参考にしてください。 PICの各I/Oピンの最大電流は、25mAなので、これを超えない範囲で電流制限抵抗(R4,R5,R6,R7)を調整してください。(200Ω~1kΩ) {{:imgpaste:202004:htmikan-20200430-135817.png}} ===== ソースコード ===== //********************************************************************** //■■■関数&共有データ宣言■■■ extern void main(); extern void init_port(); extern void init_segment(); extern void init_timer(); extern void segment_disp(); extern void segment_set_data(short seg1, short seg2, short SEG3, short seg4, short dot); extern void interrupt(); extern void count_disp(long cnt); extern long clock_msec; extern short flag; //********************************************************************** //■■■マクロ定義■■■ //7SEG-SELECT #define ACTIVE_LOW //簡易接続、標準接続(B(2SA1015)) #ifdef ACTIVE_LOW #define SEG_ON 0 #define SEG_OFF 1 #else //標準接続(A(2SC1815)) #define SEG_ON 1 #define SEG_OFF 0 #endif sbit SEG1 at PORTA.B1; sbit SEG1_Direction at TRISA.B1; #define SEG1_ON SEG1 = SEG_ON #define SEG1_OFF SEG1 = SEG_OFF sbit SEG2 at PORTA.B0; sbit SEG2_Direction at TRISA.B0; #define SEG2_ON SEG2 = SEG_ON #define SEG2_OFF SEG2 = SEG_OFF sbit SEG3 at PORTA.B7; sbit SEG3_Direction at TRISA.B7; #define SEG3_ON SEG3 = SEG_ON #define SEG3_OFF SEG3 = SEG_OFF sbit SEG4 at PORTA.B6; sbit SEG4_Direction at TRISA.B6; #define SEG4_ON SEG4 = SEG_ON #define SEG4_OFF SEG4 = SEG_OFF //7SEG-DATA #define SEG_DATA PORTB #define SEG_DATA_Direction TRISB //SWITCH sbit SW_START at PORTA.B2; sbit SW_START_Direction at TRISA.B2; sbit SW_STOP at PORTA.B3; sbit SW_STOP_Direction at TRISA.B3; sbit SW_MODE_0 at PORTA.B4; sbit SW_MODE_0_Direction at TRISA.B4; sbit SW_MODE_1 at PORTA.B5; sbit SW_MODE_1_Direction at TRISA.B5; //other #define INPUT_MODE 1 #define OUTPUT_MODE 0 //********************************************************************** //■■■メイン関数■■■ void main() { OSCCON = 0b01110000; //クロックを8MHzに設定します。 ANSEL = 0b00000000; //A/D変換モジュールは使用しません。 // init_port(); init_segment(); init_timer(); // 割り込みを許可します。 INTCON.PEIE = 1; INTCON.GIE = 1; // while (1) { if ((SW_START == 0) && (flag == 0)) { clock_msec = 0; flag = 1; } if ((SW_STOP == 0) && (flag == 1)) { flag = 0; } count_disp(clock_msec); } } //********************************************************************** //■■■カウント表示関数■■■ void count_disp(long cnt) { char buf[12]; // if ((SW_MODE_1 == 1) && (SW_MODE_0 == 1)) { LongWordToStr(cnt, buf); buf[6] = (buf[6] == ' ') ? 0 : buf[6] - '0'; buf[7] = (buf[7] == ' ') ? 0 : buf[7] - '0'; buf[8] = (buf[8] == ' ') ? 0 : buf[8] - '0'; buf[9] = (buf[9] == ' ') ? 0 : buf[9] - '0'; segment_set_data(buf[6], buf[7], buf[8], buf[9], 1); return; } if ((SW_MODE_1 == 1) && (SW_MODE_0 == 0)) { LongWordToStr(cnt, buf); buf[5] = (buf[5] == ' ') ? 0 : buf[5] - '0'; buf[6] = (buf[6] == ' ') ? 0 : buf[6] - '0'; buf[7] = (buf[7] == ' ') ? 0 : buf[7] - '0'; buf[8] = (buf[8] == ' ') ? 0 : buf[8] - '0'; segment_set_data(buf[5], buf[6], buf[7], buf[8], 2); return; } if ((SW_MODE_1 == 0) && (SW_MODE_0 == 1)) { LongWordToStr(cnt, buf); buf[4] = (buf[4] == ' ') ? 0 : buf[4] - '0'; buf[5] = (buf[5] == ' ') ? 0 : buf[5] - '0'; buf[6] = (buf[6] == ' ') ? 0 : buf[6] - '0'; buf[7] = (buf[7] == ' ') ? 0 : buf[7] - '0'; segment_set_data(buf[4], buf[5], buf[6], buf[7], 3); return; } if ((SW_MODE_1 == 0) && (SW_MODE_0 == 0)) { LongWordToStr(cnt, buf); buf[3] = (buf[3] == ' ') ? 0 : buf[3] - '0'; buf[4] = (buf[4] == ' ') ? 0 : buf[4] - '0'; buf[5] = (buf[5] == ' ') ? 0 : buf[5] - '0'; buf[6] = (buf[6] == ' ') ? 0 : buf[6] - '0'; buf[7] = (buf[7] == ' ') ? 0 : buf[7] - '0'; segment_set_data(buf[3], buf[4], buf[5], buf[6], 4); return; } } //********************************************************************** //■■■セグメント初期化関数■■■ void init_segment() { SEG1_Direction = OUTPUT_MODE; SEG1_OFF; SEG2_Direction = OUTPUT_MODE; SEG2_OFF; SEG3_Direction = OUTPUT_MODE; SEG3_OFF; SEG4_Direction = OUTPUT_MODE; SEG4_OFF; // SEG_DATA_Direction = 0b00000000; SEG_DATA = 0x00; } //********************************************************************** //■■■入出力ポート初期化関数■■■ void init_port() { SW_START_Direction = INPUT_MODE; SW_START_Direction = INPUT_MODE; SW_MODE_0_Direction = INPUT_MODE; SW_MODE_1_Direction = INPUT_MODE; } //********************************************************************** //■■■タイマー初期化関数■■■ void init_timer() { T2CON.T2CKPS1 = 0; T2CON.T2CKPS0 = 0; T2CON.TOUTPS3 = 1; T2CON.TOUTPS2 = 1; T2CON.TOUTPS1 = 1; T2CON.TOUTPS0 = 1; TMR2 = 0; PIE1.TMR2IE = 1; PIR1.TMR2IF = 0; PR2 = 125; //125=1msec/((1sec/8MHz)*4*16PS) T2CON.TMR2ON = 1; } //********************************************************************** //■■■セグメントデータ設定関数■■■ short seg_dat[4] = {0, 0, 0, 0}; short dot_point = 0; // void segment_set_data(short seg1, short seg2, short SEG3, short seg4, short dot) { seg_dat[0] = seg1; seg_dat[1] = seg2; seg_dat[2] = seg3; seg_dat[3] = seg4; dot_point = dot; } //********************************************************************** //■■■割り込み関数■■■ long clock_msec = 0; short flag = 0; void interrupt() { if (PIR1.TMR2IF == 1) { PIR1.TMR2IF = 0; // segment_disp(); // if (flag == 1) { clock_msec++; } } } //********************************************************************** //■■■セグメントデータ表示関数■■■ short seg_tbl[10] = { 0b00111111, //0 0b00000110, //1 0b01011011, //2 0b01001111, //3 0b01100110, //4 0b01101101, //5 0b01111101, //6 0b00100111, //7 0b01111111, //8 0b01101111 //9 }; short seg_cnt = 0; // void segment_disp() { switch (seg_cnt) { case 0: SEG4_OFF; SEG_DATA = seg_tbl[seg_dat[0]]; if (dot_point == 1) { SEG_DATA.B7 = 1; } SEG1_ON; seg_cnt = 1; break; case 1: SEG1_OFF; SEG_DATA = seg_tbl[seg_dat[1]]; if (dot_point == 2) { SEG_DATA.B7 = 1; } SEG2_ON; seg_cnt = 2; break; case 2: SEG2_OFF; SEG_DATA = seg_tbl[seg_dat[2]]; if (dot_point == 3) { SEG_DATA.B7 = 1; } SEG3_ON; seg_cnt = 3; break; case 3: SEG3_OFF; SEG_DATA = seg_tbl[seg_dat[3]]; if (dot_point == 4) { SEG_DATA.B7 = 1; } SEG4_ON; seg_cnt = 0; break; } } //********************************************************************** ===== 動作確認 ===== {{:imgpaste:202004:htmikan-20200430-135937.png?500}} 左側:1/1000秒単位での測定結果です。 右側:1/100秒単位での測定結果です。 {{:imgpaste:202004:htmikan-20200430-140002.png}}{{:imgpaste:202004:htmikan-20200430-140006.png}} 左側:1/10秒単位での測定結果です。 右側:1秒単位での測定結果です。 {{:imgpaste:202004:htmikan-20200430-140013.png}}{{:imgpaste:202004:htmikan-20200430-140018.png}} このページは稲崎様の閉鎖したHPのコピーで、著作権は稲崎様にあります。[[elechobby:picdic:picdic|詳細]] This page is a copy of Mr. Inasaki's closed website, and the copyright is held by him.[[elechobby:picdic:picdic|Details]]