Arduinoでカウントダウンタイマー(その2)
内蔵RC発信8MHzでは時計の精度があまりに悪いため、16MHzのセラロックをつなぐ。
セラロックを繋ぐためには、スイッチ2個を別のピンに繋げる必要があったが、空いたピンは1つだけだったため、スイッチ1つで動くようスケッチを直す。短く押すとSTART/STOP、長押しがRESETとした。
また、開始・終了時の演出も変更した。
#include <MsTimer2.h> /* カウントダウンタイマー 1button Arduinoバージョン(RCDuinoでない) ohguma 2011-10-07 Charlieplexing 16segment LED display test by ikkei 2011.01.13 http://web.mac.com/kxm_ikkei/Site/16segLED.html http://blog.goo.ne.jp/jh3kxm/e/f309b4d7fce979808e75db0e4bc7f7a3 Arduinoより2ピン多く使えるRCduino http://web.me.com/kuwatay/morecat_lab./Blog/%E3%82%A8%E3%83%B3%E3%83%88%E3%83%AA%E3%83%BC/2011/7/2_RCduino.html arduinoのデジタル入出力について http://nekosan0.bake-neko.net/structure_digital_port.html MsTimer2(ミリ秒単位で指定するタイマ) http://www.musashinodenpa.com/arduino/ref/index.php?f=1&pos=1996 */ // 1st digit pin assign #define L01 9 // Anode ・・・・Common #define L02 2 // G2 #define L03 3 // B #define L04 4 // A2 #define L05 5 // J #define L06 6 // I #define L07 7 // A1 #define L08 8 // H #define L09 1 // F #define L10 12 // G1 #define L11 11 // E #define L12 10 // D2 #define L13 A0 // M #define L14 A1 // L #define L15 A2 // D1 #define L16 A3 // K #define L17 A4 // C #define L18 A5 // DP const byte LINE[ 6 ][ 18 ] = { { L01, L02, L03, L04, L05, L06, L07, L08, L09, L10, L11, L12, L13, L14, L15, L16, L17, L18 }, { L03, L02, L01, L04, L05, L06, L07, L08, L09, L10, L11, L12, L13, L14, L15, L16, L17, L18 }, { L05, L02, L03, L04, L01, L06, L07, L08, L09, L10, L11, L12, L13, L14, L15, L16, L17, L18 }, { L06, L02, L03, L04, L05, L01, L07, L08, L09, L10, L11, L12, L13, L14, L15, L16, L17, L18 }, { L08, L02, L03, L04, L05, L06, L07, L01, L09, L10, L11, L12, L13, L14, L15, L16, L17, L18 }, { L09, L02, L03, L04, L05, L06, L07, L08, L01, L10, L11, L12, L13, L14, L15, L16, L17, L18 } }; const unsigned long FONT[]={ 0x00000, 0x01010, 0x09000, 0x1915A, 0x05C5C, 0x03030, 0x03C1C, 0x06000, 0x02004, 0x00420, 0x03434, 0x11110, 0x0000A, 0x10100, 0x10000, 0x02020, 0x0EAEA, 0x01010, 0x1C9C8, 0x1C94A, 0x11310, 0x04B4C, 0x14BCA, 0x06820, 0x1CBCA, 0x1CB4A, 0x01010, 0x01020, 0x02004, 0x10148, 0x00420, 0x1CA10, 0x0C9DA, 0x1A022, 0x1D85A, 0x04AC8, 0x0D85A, 0x14BC8, 0x14B80, 0x14ACA, 0x18382, 0x05858, 0x080CA, 0x02384, 0x002C8, 0x0A682, 0x08686, 0x0CACA, 0x1CB80, 0x0CACE, 0x1CB84, 0x14B4A, 0x05810, 0x082CA, 0x022A0, 0x082A6, 0x02424, 0x02410, 0x06868, 0x00AC0, 0x12510, 0x0C00A, 0x00600, 0x00048, 0x00400, 0x019D8, 0x003D0, 0x001C0, 0x011D8, 0x001E0, 0x15110, 0x01B50, 0x00390, 0x000C0, 0x01050, 0x03014, 0x01018, 0x10192, 0x00190, 0x001D0, 0x01B80, 0x01B10, 0x00180, 0x1000C, 0x11118, 0x000D8, 0x000A0, 0x000DA, 0x02424, 0x1900A, 0x00160, 0x05118, 0x01010, 0x11850, 0x02600, 0x1FFFF, }; unsigned long segment[6] = { 0, 0, 0, 0, 0, 0 }; void alloff(void) { for ( byte i=0; i < 18; i++){ digitalWrite( LINE[ 0 ][ i ], LOW ); pinMode( LINE[ 0 ][ i ], INPUT ); } } void LED_scan( void ) { static byte digit = 0; // make dead time all output Off (Input) alloff(); // anode common output High pinMode( LINE[ digit ][ 0 ], OUTPUT); digitalWrite( LINE[ digit ][ 0 ], HIGH); // segment data output Low for ( byte i=0; i < 17; i++){ if ( bitRead( segment[ digit ], i)){ pinMode( LINE[ digit ][ 17-i ], OUTPUT); } } // next digit digit++; if ( digit >= 6 ){ digit = 0; } } //タイマー表示値 byte ms010 = 0; byte ms100 = 0; byte s01 = 0; byte s10 = 0; byte m01 = 0; byte m10 = 0; #define MINUTE 1 #define MINUTE_MIN 1 #define MINUTE_MAX 15 byte default_minute = MINUTE; #define ST_STOP 0 //停止中 #define ST_RUN 1 //カウントダウン中 #define ST_COMPLETE 2 //カウントダウン終了 #define ST_CONFIG 3 //設定中 #define ST_RESET 4 //停止中でリセット後 byte status = ST_RESET; #define BLINK_COMPLETE 100 //1=10ms,100=1sec #define BLINK_CONFIG 50 //1=10ms, 50=0.5sec byte blink = 0; #define SW_PIN 13 #define SW_ON 0 //pull up のため逆転 #define SW_OFF 1 //pull up のため逆転 #define SW_DELAY 100 //チャタリング防止期間[ms] #define SW_PERIOD_LONG 500 //長押ししきい値[ms] int sw_val = SW_OFF; //現在のリセットスイッチ値 int sw_last = SW_OFF; //前回のリセットスイッチ値 unsigned long sw_delay = 0; //リセットスイッチのチャタリング防止遅延時間ms unsigned long sw_long = 0; //長押し判定時間ms #define BUZZER_PIN 0 #define BUZZER_SHORT 10 //短ブザー 10mx #define BUZZER_MIDDLE 100 //中ブザー 100mx #define BUZZER_LONG 500 //長ブザー 500mx unsigned long bz_stop = 0; //ブザー停止時間ms void setup(){ pinMode(BUZZER_PIN, OUTPUT); digitalWrite(BUZZER_PIN, LOW); pinMode(SW_PIN, INPUT); digitalWrite(SW_PIN, HIGH); alloff(); MsTimer2::set( 2, LED_scan); // 2ms/digit MsTimer2::start(); time_reset(); } void loop() { if (status == ST_COMPLETE) { if (blink < BLINK_COMPLETE / 2) { segment[0] = FONT[0]; segment[1] = FONT[0]; segment[2] = FONT[0]; segment[3] = FONT[0]; segment[4] = FONT[0]; segment[5] = FONT[0]; } else { segment[0] = FONT['F' - ' ']; segment[1] = FONT['I' - ' ']; segment[2] = FONT['N' - ' ']; segment[3] = FONT['I' - ' ']; segment[4] = FONT['S' - ' ']; segment[5] = FONT['H' - ' ']; } } else if (status == ST_CONFIG && blink < BLINK_CONFIG / 2) { segment[0] = FONT[0]; segment[1] = FONT[0]; segment[2] = FONT[0]; segment[3] = FONT[0]; segment[4] = FONT[0]; segment[5] = FONT[0]; } else { if (m10 == 0) { //10分の桁 segment[0] = FONT[0]; } else { segment[0] = FONT['0' - ' ' + m10 ]; } segment[1] = FONT['0' - ' ' + m01 ]; segment[2] = FONT['0' - ' ' + s10 ]; segment[3] = FONT['0' - ' ' + s01 ]; segment[4] = FONT['0' - ' ' + ms100 ]; segment[5] = FONT['0' - ' ' + ms010 ]; } if (status == ST_COMPLETE) { blink++; if (blink >= BLINK_COMPLETE) { blink = 0; } } else if (status == ST_CONFIG) { blink++; if (blink >= BLINK_CONFIG) { blink = 0; } } byte b; b = sw(); if (b == 1) { //スタートスイッチ処理 sw_start(); } else if (b == 2) { //リセットスイッチ処理 sw_reset(); } if (status == ST_RUN) { time_countdown(); } //ブザー if (bz_stop > millis()) { digitalWrite(BUZZER_PIN, HIGH); } else { bz_stop = 0; digitalWrite(BUZZER_PIN, LOW); } delay(10); } /** * スイッチ処理 * * @return byte 0:押されていない, 1:短押し, 2:長押し */ byte sw() { unsigned long now; sw_val = digitalRead(SW_PIN); if ( sw_val == sw_last ) { //スイッチ値変化なし if (sw_val == SW_ON && sw_long > 0 && sw_long < millis()) { //スイッチON で 計測開始後かつ長押し時刻を過ぎたら長押し sw_long = 0; return 2; } return 0; } //以下はスイッチ値変化ありの際の処理 if ( 0 == sw_delay ) { //チャタリング防止遅延時間の設定 sw_delay = millis() + SW_DELAY ; return 0; } now = millis(); if ( sw_delay < now ) { //チャタリング防止遅延時間経過中 return 0; } //チャタリング防止遅延時間経過済 //前回値として現在の値を保存 sw_last = sw_val; //チャタリング防止時間をクリア sw_delay = 0; if ( SW_ON == sw_val ) { //SWがONの時、ボタン状態決定時間設定 sw_long = now + SW_PERIOD_LONG ; return 0; } //以下SWはOFF if (sw_long == 0) { //キャンセル処理 return 0; } //ボタン離し処理 byte ret = 1; if (now > sw_long) { ret = 2; } sw_long = 0; return ret; } /** * スタートスイッチ処理 */ void sw_start() { if ( ST_RESET == status ) { time_start(); status = ST_RUN; } else if ( ST_STOP == status ) { status = ST_RUN; } else if ( ST_RUN == status ){ status = ST_STOP; } else if ( ST_CONFIG == status ) { default_minute++; if (default_minute > MINUTE_MAX) { default_minute = MINUTE_MIN; } time_reset(); } } /** * リセットスイッチ処理 */ void sw_reset() { //SWがONになった時の処理 if (( ST_STOP == status ) || ( ST_COMPLETE == status )) { time_reset(); status = ST_RESET; } else if (ST_RESET == status) { status = ST_CONFIG; } else if (ST_CONFIG == status) { time_reset(); status = ST_RESET; } } /** * 開始アニメ */ void time_start() { int i; int j; int k; for (i = 3; i > 0; i--) { for (j = 7; j >= 0; j--) { segment[0] = FONT[0]; segment[1] = FONT[0]; segment[2] = FONT[0]; segment[3] = FONT[0]; segment[4] = FONT[0]; segment[5] = FONT[0]; if ( 1 <= j && 6 >= j) { segment[j - 1] = FONT[ '0' - ' ' + i]; delay(BUZZER_MIDDLE); } else { segment[0] = FONT['S' - ' ']; segment[1] = FONT['T' - ' ']; segment[2] = FONT['A' - ' ']; segment[3] = FONT['R' - ' ']; segment[4] = FONT['T' - ' ']; segment[5] = FONT[0]; if (7 == j) { digitalWrite(BUZZER_PIN, HIGH); delay(BUZZER_MIDDLE); digitalWrite(BUZZER_PIN, LOW); delay(BUZZER_MIDDLE); } else { delay(BUZZER_MIDDLE*2); } } } } bz_stop = millis() + BUZZER_LONG; } /** * カウントダウン処理 */ void time_countdown() { //カウントダウン終了 if ( 0 == m10 && 0 == m01 && 0 == s10 && 0 == s01 && 0 == ms100 && 0 == ms010 ) { int i; int j; for(j = 0; j < 3; j++) { for(i = 0; i < 4; i++) { digitalWrite(BUZZER_PIN, HIGH); delay(50); digitalWrite(BUZZER_PIN, LOW); delay(50); } delay(400); } status = ST_COMPLETE; return; } //ビープ音 if (bz_stop == 0) { if ((s10 % 3) == 2 && 9 == s01 && 9 == ms100 ) { //XX分 59秒 9X : 30秒毎にピピっとならす。 bz_stop = millis() + BUZZER_SHORT; } else if ( 0 == m10 && 0 == m01 && 0 == s10 && 9 == ms100 ) { //00分 0X秒 9X : 10秒切ったら1秒毎にピピっとならす。 bz_stop = millis() + BUZZER_SHORT; } } ms010--; if ( ms010 > 9 ){ ms010 = 9; ms100--; } if ( ms100 > 9 ){ ms100 = 9; s01--; } if ( s01 > 9 ){ s01 = 9; s10--; } if ( s10 > 9 ){ s10 = 5; m01--; } if ( m01 > 9 ){ m01 = 9; m10--; } if ( m10 > 9 ){ m10 = 9; } } /** * リセット処理 */ void time_reset() { ms010 = 0; ms100 = 0; s01 = 0; s10 = 0; m01 = default_minute % 10; m10 = (default_minute - default_minute % 10) / 10; }