対局時計を自作(4)「2桁の秒読みに対応」

目次

99秒までの秒読みに対応


開発が思うように進まず、前回(12/14のエントリー参照)からの進歩としては、2桁の秒読みに対応できただけ。
「デンシ電気店 ヤフーショップ」というところから、ダイナミックドライブ用配線済みの4桁7セグLED「LED/E3-4040CHR2」を入手した。
上記動画で数字がちかちか点滅して見えるのは、各桁を短い周期で交互に光らせる「ダイナミック点灯」を行なっているから。ただし人間の肉眼であれば、常に光っているように見える。
左側のボタンとLEDはまだ未使用。

今後の課題

7セグデコーダドライバ、または3to8デコーダ/デマルチプレクサ(Demultiplexer。コモン端子制御用に利用したい)が無い現状では、ポートが足りない(はず)。

  • ブザー用・・・1Pin
  • 7セグ用・・・7Pin(7セグデコーダがあれば4Pinで表現可能)
  • ボタン用・・・1ボタンにつき1Pin
  • コモン制御用・・・1桁につき1Pin(3to8デコーダ/デマルチプレクサがあれば、8桁までを3Pinで表現可能)

つまり、2ボタン+4桁を単純に表現すると、1+7+2+4=14Pinとなり、ArduinoのDigital In/Out Pin13個を超えてしまう。

ウケるのか?

明日から、1泊2日の某温泉将棋合宿に参加する。対局時計の数は足りているのだが、笑いをとるだけのために本対局時計を持っていく予定。というか実は、本開発の根本的な目的の1つは、この合宿に持っていく(そして笑いをとる)ことだった。もっと完成度を上げたかったのだが・・・無念。

スケッチ公開

参考までに、以下に現状のProcessingスケッチを載せておく。



主な変更点は、数字を表示するdispNum関数。その他、millis()で取得した時間データをうっかりInt型変数で受け取っていたバグ(前回は時間が短くバグが表面化していなかった)を修正したりしている。アノード→カソード変換など、どうもスマートじゃないところが散見かも。

#define TM_LIMIT 30  // 持ち時間
#define CATHODE // カソードコモンLED利用時。アノード時はコメントアウト
// 状態 stateCC(CCはChessClockの略)
// 1 (CNTDOWN): 秒読み状態
// 2 (CNTSTOP): 時間切れ状態
#define CNTDOWN 0
#define CNTSTOP 1
volatile int stateCC = CNTDOWN;
unsigned long countBuf = 0;  // 着手時のmillis時間保持用
int usingSec = 0;  // 使用時間
// 各桁のコモン制御用ポート定義
int digitArray[2]={9,10};
// 各SegmentとPin対応。2,3Pinは割り込み用に空ける
int SegArray[7] = {0,1,4,5,6,7,8};
// 0〜9の7セグ表示パターン アノードコモンLED用
boolean LEDArray[10][7]={ {0,0,0,0,0,0,1},
{1,0,0,1,1,1,1},
{0,0,1,0,0,1,0},
{0,0,0,0,1,1,0},
{1,0,0,1,1,0,0},
{0,1,0,0,1,0,0},
{0,1,0,0,0,0,0},
{0,0,0,1,1,0,1},
{0,0,0,0,0,0,0},
{0,0,0,0,1,0,0} };
// カソードコモンLEDに変換する際に用いる関数。各ビット反転
void changeCommonAtoC(void){
int i,j;
for(i=0; i<10; i++){
for(j=0; j<7; j++){
LEDArray[i][j]= !LEDArray[i][j];
}
}
}
// ブザーOn/Off用。13Pin利用
void buzzer( boolean soundOn ){
digitalWrite(13,soundOn);
}
// コモン端子制御用
void ctrlCommon( int port, boolean lightOn ){
digitalWrite(port, lightOn);
}
// 数字表示
void dispNum(int num){
static unsigned long millisBuf = 0;
static int digit = 1;
int num1;  // 光らせる桁に表示させたい数字設定用
// 光らせる桁設定 現状2桁だけ。1→2→1→・・・
if( millis()-millisBuf >= 10 ){  // 10msおきにコモン切換
if(digit>=2){digit=1;}
else        {digit++;}
millisBuf = millis();
}
// 光らせる桁の数字取得
for(int n=digit; n!=1; n--){ num=num/10; }  // 右へ桁シフトし下位桁削除
num1 = num%10;  // 上位桁の数字クリア
// コモン端子制御。光らせる桁のコモンのみHIGH
for(int i=0; i<2; i++){ ctrlCommon( digitArray[i], digit==i+1 ); }
// ↑digitとi+1が等しいときのみtrueとなる
// 光らせる桁の数字の7セグ出力
for(int j=0; j<7; j++){
digitalWrite(SegArray[j], LEDArray[num1][j]);
}
}
void setup(){
int i;
//カソードコモンLED使用ならばカソード用に変換
#ifdef CATHODE
changeCommonAtoC();
#endif
// 7セグ用Pin初期化
for(i=0; i<=7; i++){
pinMode(SegArray[i], OUTPUT);
}
// ブザー用Pin初期化
pinMode(13,OUTPUT);
// コモン制御用Pin初期化
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
// チェスクロボタン押しで割り込み発生
attachInterrupt(0, pushButton, RISING);
}
void pushButton(){
switch(stateCC){
case CNTDOWN:
usingSec = 0;
countBuf = millis();  // チェスクロボタン押した時の時刻保持
break;
case CNTSTOP:
default:
break;
}
}
void loop(){
switch(stateCC){
case CNTDOWN:
usingSec = millis() - countBuf;
// 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をコピーしました!

この記事を書いた人

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

コメント

コメントする

目次
閉じる