AVRマイコンデジタル時計をユニバーサル基板へ実装

先日のブレッドボードデジタル時計をユニバーサル基板上に実装しました。

できあがり


比較のものを載せていないですが、大きさは
ユニバーサル基板が「Cタイプ(72x48mm)」で、電池の大きさを含めると、
72x55x14mm ほどです。

使い方

ボタンの使い方は下のようになっています。

  • 右の赤色のボタン
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分くらいは余裕を持って生活したほうが健康には良さそうです。
(いいわけですか・・・。)

今後やること

プラスチックのケースに収めたいです。

LEGOブロックでケースを作ろうかなと思っています。

追記

2012年3月31日
AVR Studioのプロジェクトファイルを追加しました。