目次
2人用に対応。9999秒の秒読みに対応。
2008/12/26のエントリー『対局時計を自作(4)「2桁の秒読みに対応」』以来、約4ヶ月ぶりに自作対局時計の機能を向上させた。
7セグLED表示とボタンが正式に2人用になった。また、動画では30秒の秒読みとしているが、9999秒まで設定可能だ(後述するソースのTM_LIMITの部分を9999に変更すればOK)。
7セグデコーダ、3to8デコーダ利用
前回のエントリーで懸念事項に挙げたポート数については、
- 7セグ制御・・・BCD-to-Seven Segment Decoder/Driver HD74HC4511Pを利用
- 7Pinを4Pinに圧縮
- コモン制御・・・3-LINE TO 8-LINE DECODERS SN74HC138Nを利用
- 8Pinを3Pinに圧縮
とすることで、大いに余裕を持って対応できた(写真参考)。
回路組みとコーディングに、苦節4ヶ月を要した・・・わけではなく、前回更新時以来ずっとモチベーションが上がらずノータッチだった。ゴールデンウィークに入りやる気が起き、GW中の2日間でここまで仕上げた。
id:readingknowledgeさんとたまたま開発時期が重なり、競うような形で開発を進めていたわけだが、私の方が急にフェードアウトしてしまう形となり、大変申し訳ないと感じていた。ただ、長くホームページを運営している者同士、この辺りのマイペース感、のらりくらり感は、一方で理解していただいている感覚とも思っている。
余談だが、モチベーションが急激に失われた理由は以下の通り。
- 年末将棋合宿までに仕上げて持って行くのがそもそもの目的で、それが終了してしまったため。ちなみに、完成度が低すぎたので結局合宿に持って行くのは断念した。参加者の1人は、後で本ブログを見てくれたようだ。
- 昨年大晦日間近、回路組みを失敗し、過電流で4桁7セグLEDが焼失した。性根がソフト屋さん(最近は仕事でコーディングしていないが)で、「これだからハードは嫌なんだよ・・・」と逆切れ。買い換えたのはこのGW中だった。今回、LEDの色が赤から青に変わっているのはそのためだ。
今後の課題、ToDoリスト
- 左右各4桁に対応できたので、上位2桁と下位2桁を使って、時・分の時間指定をできるようにする。
- 時間設定機能を追加する。(現状では、時間設定を変えるにはソフトを書き換える必要がある)
スケッチ公開
参考までに、以下に現状のArduinoのProcessingスケッチを載せておく。
#define TM_LIMIT 30 // 持ち時間 #define CATHODE // カソードコモンLED利用時。アノード時はコメントアウト // 状態 stateCC(CCはChessClockの略) // 1 (CNTDOWN): 秒読み状態 // 2 (CNTSTOP): 時間切れ状態 #define CNTDOWN 0 #define CNTSTOP 1 volatile int stateCC = CNTDOWN; // 手番 #define LEFT 0 #define RIGHT 1 volatile int stateTeban = LEFT; int dispNumArray[8] = { TM_LIMIT/1000, (TM_LIMIT/100)%10, (TM_LIMIT/10)%10, TM_LIMIT%10, TM_LIMIT/1000, (TM_LIMIT/100)%10, (TM_LIMIT/10)%10, TM_LIMIT%10 }; // 各セグ制御用(BCD-to-Seven Segment Decoder/Driver HD74HC4511P) #define SEG_1 6 // A #define SEG_2 7 // B #define SEG_3 8 // C #define SEG_4 9 // D // コモン制御用(3-LINE TO 8-LINE DECODERS SN74HC138N) #define COMMON_1 10 // A #define COMMON_2 11 // B #define COMMON_3 12 // C #define BUZZER 13 volatile unsigned long countBuf = 0; // 着手時のmillis時間保持用 volatile int usingSec = 0; // 使用時間 // 各桁のコモン制御用ポート定義 int digitArray[3]={ COMMON_1, COMMON_2, COMMON_3 }; // 各Segment制御用ポート定義 int SegArray[4] = { SEG_1, SEG_2, SEG_3, SEG_4 }; // ブザーOn/Off用。 void buzzer( boolean soundOn ){ digitalWrite( BUZZER, soundOn ); } // コモン端子制御用 void ctrlCommon( int port, boolean lightOn ){ digitalWrite( port, lightOn ); } // 数字表示 void dispNum(int num){ static unsigned long millisBuf = 0; static int digit = 0; int n; // 8桁の数字セット if( stateTeban == LEFT ){ n = 0; } else { n = 4; } dispNumArray[n ] = num/1000; dispNumArray[n+1] = (num/100)%10; dispNumArray[n+2] = (num/10)%10; dispNumArray[n+3] = num%10; // 光らせる桁設定 if( millis()-millisBuf >= 1 ){ // X msおきにコモン切換 if(digit>8){digit=0;} else {digit++;} millisBuf = millis(); } // コモン端子制御。 ctrlCommon( COMMON_3, digit>>2 ); ctrlCommon( COMMON_2, (digit>>1) & 1 ); ctrlCommon( COMMON_1, digit & 1 ); // 光らせる桁の数字の7セグ出力 digitalWrite( SEG_4, dispNumArray[digit] >> 3 ); digitalWrite( SEG_3, (dispNumArray[digit] >> 2) & 1 ); digitalWrite( SEG_2, (dispNumArray[digit] >> 1) & 1 ); digitalWrite( SEG_1, dispNumArray[digit] & 1 ); } void setup(){ int i; // 7セグ用Pin初期化 for(i=0; i<4; i++){ pinMode(SegArray[i], OUTPUT); } // コモン制御用Pin初期化 for(i=0; i<3; i++){ pinMode(digitArray[i], OUTPUT); } // ブザー用Pin初期化 pinMode(BUZZER,OUTPUT); // チェスクロボタン押しで割り込み発生 attachInterrupt(LEFT, pushButtonLeft, RISING); attachInterrupt(RIGHT, pushButtonRight, RISING); } void pushButtonLeft(){ pushButton(LEFT ); } void pushButtonRight(){ pushButton(RIGHT); } void pushButton( int button ){ if( button == LEFT && stateTeban == RIGHT ) return; if( button == RIGHT && stateTeban == LEFT ) return; switch(stateCC){ case CNTDOWN: stateTeban = ~stateTeban; usingSec = 0; countBuf = millis(); // チェスクロボタン押した時の時刻保持 break; case CNTSTOP: default: break; } } void loop(){ switch(stateCC){ case CNTDOWN: usingSec = millis() - countBuf; TM_LIMIT - usingSec/1000; // 7セグ関連 dispNum( TM_LIMIT - usingSec/1000 ); // カウントダウン表示 // ブザー音関連 if(usingSec <= 50){ // ボタン押し直後は鳴らさない buzzer(false); } else if(TM_LIMIT - usingSec/1000 <= 5){ // ラスト5秒 buzzer(true); } else if(TM_LIMIT - usingSec/1000 <= 10){ // ラスト10秒 if(usingSec%1000 >= 0 && usingSec%1000 <= 50){ buzzer(true); } else{buzzer(false);} } else if( (TM_LIMIT*1000-usingSec)%10000 >= 9950 ){ // それ以前は10秒毎 buzzer(true); } else{buzzer(false);} // 時間使い切った場合 if(usingSec == TM_LIMIT*1000){ stateCC = CNTSTOP; } break; case CNTSTOP: dispNum(0); buzzer(false); break; default: break; } }
コメント