対局時計を自作(5)「秒読み対戦に対応」

目次

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;
}
}
この記事を気に入ったらシェアしよう
URLをコピーする
URLをコピーしました!

この記事を書いた人

「三間飛車のひとくちメモ」管理人、兼「フラ盤」作者、兼二児のパパ。将棋クエスト四段。
「三間飛車の普及活動を通して将棋ファンの拡大に貢献する」をモットーに、奇をてらわない文章とデザインで記事を書き続けています。

コメント

コメントする

目次
閉じる