AVRマイコンデジタル時計をユニバーサル基板へ実装
先日のブレッドボードデジタル時計をユニバーサル基板上に実装しました。
材料
前回から新たに増えた素材は以下のものです。
使い方
ボタンの使い方は下のようになっています。
- 右の赤色のボタン
上 | 1分増加 |
下 | 1分減らす |
- 左の青色のボタン
上 | 1時間増加 |
下 | 1時間減らす |
ソースコード
実は、7セグ表示器に間違ってカソードコモンの「OSL40562-LRA」をはんだ付けしてしまいました。
回路としてはどちらでも構わないので、プログラムを以下に示すものに変えました。
また、AVR Studioのプロジェクトファイルはこちらです。
/*********************************** デジタル時計 V1.1をカソードコモン対応 参考: AVR タイマー実験 http://www9.plala.or.jp/fsson/NewHP_elc/AVR/Avr_Tmr0_OVF.html ユアネーム・7セグ・12セグフォント大全集 http://www.yourname.jp/soft/digitalfonts-20090306.shtml ************************************/ #include <avr/io.h> #include <avr/interrupt.h> #define BTN_TH 20 #define F_CPU 1000000 /* CPUクロック周波数[Hz] */ #define PITCH 100 /* 割り込み周波数[Hz] */ #define PRESC 64 /* プリスケーラ値 (分周比) */ #define INTRCOUNT (0x10000 - ((F_CPU / PRESC) / PITCH)) /* アノードコモンの場合 unsigned int led_seg[4] = {0xff, 0xff, 0xff, 0xff}; */ unsigned int led_seg[4] = {0x00, 0x00, 0x00, 0x00}; unsigned char hour = 0, min = 0, sec = 0, cnt = 0, on_dp = 1; ISR (SIG_OVERFLOW1) { TCNT1 = INTRCOUNT; /* タイマ1の初期値設定 */ cnt++; if (cnt > 99) { cnt = 0; on_dp = !on_dp; sec++; if (sec > 59) { sec = 0; min++; if (min > 59) { min = 0; hour++; if (hour > 23) hour = 0; } } } } void timer1_init(void) { TCCR1A = 0; /* TCCR1A タイマモード */ TCCR1B = 3; /* プリスケーラ (64分周) */ TIFR1 |= (1 << TOV1); /* オーバーフローフラグをクリア */ TIMSK1 |= (1 << TOIE1); /* オーバーフロー割り込み許可 */ } /* アノードコモンの場合 const unsigned int to_num_pattern[10] = { 0xff - 0xfc, 0xff - 0x60, 0xff - 0xda, 0xff - 0xf2, 0xff - 0x66, 0xff - 0xb6, 0xff - 0xbe, 0xff - 0xe0, 0xff - 0xfe, 0xff - 0xf6}; */ const unsigned int to_num_pattern[10] = { 0xfc, 0x60, 0xda, 0xf2, 0x66, 0xb6, 0xbe, 0xe0, 0xfe, 0xf6}; void scan(void) { static unsigned char line = 0; PORTD = led_seg[line]; DDRB = 1 << line; line = (line + 1) % 4; } void display(unsigned long num) { led_seg[3] = to_num_pattern[(num / 1000) % 10]; led_seg[2] = to_num_pattern[(num / 100) % 10]; if (on_dp) { /* アノードコモンの場合 led_seg[2] &= 0xfe; */ led_seg[2] |= 0x01; } led_seg[1] = to_num_pattern[(num / 10) % 10]; led_seg[0] = to_num_pattern[num % 10]; } int main(){ unsigned char btn_cnt[4] = {0}; /* ポートのデータ方向(入力/出力)設定 */ DDRB = 0x00; DDRC = 0x00; DDRD = 0xff; /* ポートの初期値設定 */ /* アノードコモンの場合 PORTB = 0xff; */ PORTB = 0x00; PORTC = 0xff; PORTD = 0x00; timer1_init(); sec = 0; min = 0; hour = 0; cnt = 0; TCNT1 = INTRCOUNT; /* タイマ1の初期値設定 */ sei(); while (1) { scan(); /* M-- についてのチェック */ if ((PINC & 0x01) == 0) { if (btn_cnt[0] > BTN_TH) { btn_cnt[0] = 0; cnt = 0; sec = 0; min--; if (min == 255) min = 59; } else { btn_cnt[0]++; } } else { btn_cnt[0] = 0; } /* M++ についてのチェック */ if ((PINC & 0x02) == 0) { if (btn_cnt[1] > BTN_TH) { btn_cnt[1] = 0; cnt = 0; sec = 0; min++; if (min > 59) min = 0; } else { btn_cnt[1]++; } } else { btn_cnt[1] = 0; } /* H-- についてのチェック */ if ((PINC & 0x04) == 0) { if (btn_cnt[2] > BTN_TH) { btn_cnt[2] = 0; cnt = 0; sec = 0; hour--; if (hour == 255) hour = 23; } else { btn_cnt[2]++; } } else { btn_cnt[2] = 0; } /* H++ についてのチェック */ if ((PINC & 0x08) == 0) { if (btn_cnt[3] > BTN_TH) { btn_cnt[3] = 0; cnt = 0; sec = 0; hour++; if (hour > 23) hour = 0; } else { btn_cnt[3]++; } } else { btn_cnt[3] = 0; } display((unsigned long)(hour * 100 + min)); } }
所感
お昼12時から今(22:18)まで動かしてみた時点で、
2分ほど遅れています。
だいたい半日で2分遅れるので、1日で4分ほど遅れる様子です。
時計としては致命的かもしれません。
ですが、「所さんのDAITAI時計」とかをみると、
5分くらいは余裕を持って生活したほうが健康には良さそうです。
(いいわけですか・・・。)
追記
2012年3月31日
AVR Studioのプロジェクトファイルを追加しました。