目次

時計ユニット(RTC)

概要

秋月電子通商で販売している「リアルタイムクロックモジュール(RTC-8564NB)」を利用した時計を作成しました。このモジュールの特長は以下のとおりです。

動作原理

RTCとPICとの接続は、I2Cインターフェースを使用します。
I2CとはInter Integrated Circuitの略で、主に同一基板内などの近距離に配置されたデバイス間での高速通信(100Kbps/400Kbps/3.4Mbps)を行うための方式です。
デバイス間はSDA(serial data)とSCL(serial clock)の2本の信号線だけをバスとして共有して通信を行います。

今回使用したモジュールのブロック図です。

このモジュールは、次のレジスタテーブルを利用して、データの書き込みや読み出しを行います。

今回は、機能を最小限に絞り込みました。
<時刻の設定>

<時刻の読出>
時分秒のデータを、レジスタテーブルの02,03,04より順次読み出しLCDに表示します。

回路図

ソースコード

I2Cインタフェースは、今後も使用する機会があると思いますので、汎用性を考えて以下のような関数を用意しました。

watch.c
//********************************************************************** 
 
#define	i2c_SCL			PORTB.F0
#define	i2c_SDA			PORTB.F1
#define	i2c_SDA_TRIS	TRISB.F1
 
#define	sw_min			PORTB.F2
#define	sw_hou			PORTB.F3
 
//********************************************************************** 
 
void	i2c_Start()
{
	if (i2c_SDA_TRIS != 0)
		i2c_SDA_TRIS = 0;
	i2c_SDA = 1;
	i2c_SCL = 0;
	i2c_SCL = 1;
	i2c_SDA = 0;
	i2c_SCL = 0;
}
 
void	i2c_Stop()
{
	if (i2c_SDA_TRIS != 0)
		i2c_SDA_TRIS = 0;
	i2c_SDA = 0;
	i2c_SCL = 0;
	i2c_SCL = 1;
	i2c_SDA = 1;
	i2c_SCL = 0;
}
 
void	i2c_Ack()
{
	if (i2c_SDA_TRIS != 0)
		i2c_SDA_TRIS = 0;
	i2c_SDA = 0;
	i2c_SCL = 1;
	i2c_SCL = 0;
}
 
void	i2c_Nack()
{
	if (i2c_SDA_TRIS != 0)
		i2c_SDA_TRIS = 0;
	i2c_SDA = 1;
	i2c_SCL = 1;
	i2c_SCL = 0;
}
 
void	i2c_SendByte(unsigned char data)
{
	unsigned char cnt;
	if (i2c_SDA_TRIS != 0)
		i2c_SDA_TRIS = 0;
	for (cnt = 0; cnt < 8; cnt++) {
		if ((data & 0b10000000) == 0)
			i2c_SDA = 0;
		else
			i2c_SDA = 1;
		i2c_SCL = 1;
		i2c_SCL = 0;
		data = data << 1;
	}
	i2c_SDA_TRIS = 1;
	i2c_SCL = 1;
	i2c_SCL = 0;
}
 
unsigned	char	i2c_RecvByte()
{
	unsigned char cnt, data;
	data = 0x00;
	if (i2c_SDA_TRIS == 0)
		i2c_SDA_TRIS = 1;
	for (cnt = 0; cnt < 8; cnt++) {
		i2c_SCL = 1;
		if (i2c_SDA == 1)
			data.F0 = 1;
		else
			data.F0 = 0;
		i2c_SCL = 0;
		if (cnt < 7)
			data = data << 1;
	}
	return(data);
}
 
//********************************************************************** 
 
void	main()
{
	unsigned	short	sec, min, hou, temp, cnt;
	char	buf[10];
	//
	OSCCON = 0b01110000;	// クロックは8Mhz 
	CMCON = 0b00000111;		// コンパレータは使用しない。
	ANSEL = 0b00000000;		// A/D変換は使用しない。 
	TRISA = 0b00111110;
	TRISB = 0b00001100;
	OPTION_REG.F7 = 0;
	//
	Lcd_Custom_Config(&PORTB, 7, 6, 5, 4, &PORTA, 6, 7, 0);
	TRISA = 0b00111110;
	TRISB = 0b00001100;
	Lcd_Custom_Cmd(LCD_CLEAR);
	Lcd_Custom_Cmd(LCD_CURSOR_OFF);
	Lcd_Custom_Out(2, 1, "      watch R1.0");
	//
	Delay_ms(1000);
	i2c_Start();
	i2c_SendByte(0b10100010);
	i2c_SendByte(0x02);
	i2c_SendByte(0b00000000);
	i2c_SendByte(0b00000000);
	i2c_SendByte(0b00010010);
	i2c_Stop();
	//
	while (1) {
		if (sw_min == 0)	// 分の設定 
		{
			while (sw_min == 0)
				Delay_ms(10);
			min &= 0x7F;
			temp = ((min >> 4) & 0x0F) * 10;
			min = temp + (min & 0x0F);
			min++;
			min = (min >= 60) ? 0 : min;
			temp = (min / 10) * 16;
			temp = temp + (min - ((min / 10) * 10));
			i2c_Start();
			i2c_SendByte(0b10100010);
			i2c_SendByte(0x03);
			i2c_SendByte(temp);
			i2c_Stop();
		}
		if (sw_hou == 0)	// 時の設定
		{
			while (sw_hou == 0)
				Delay_ms(10);
			hou &= 0x3F;
			temp = ((hou >> 4) & 0x0F) * 10;
			hou = temp + (hou & 0x0F);
			hou++;
			hou = (hou >= 24) ? 0 : hou;
			temp = (hou / 10) * 16;
			temp = temp + (hou - ((hou / 10) * 10));
			i2c_Start();
			i2c_SendByte(0b10100010);
			i2c_SendByte(0x04);
			i2c_SendByte(temp);
			i2c_Stop();
		}
		// 	時分秒の読み出し 
		i2c_Start();
		i2c_SendByte(0b10100010);
		i2c_SendByte(0x02);
		i2c_Start();
		i2c_SendByte(0b10100011);
		sec = i2c_RecvByte();
		i2c_Ack();
		min = i2c_RecvByte();
		i2c_Ack();
		hou = i2c_RecvByte();
		i2c_Nack();
		i2c_Stop();
		// 時の表示 
		hou &= 0x3F;
		temp = ((hou >> 4) & 0x0F) * 10;
		temp += (hou & 0x0F);
		ByteToStr(temp, buf);
		buf[1] = (buf[1] == ' ') ? '0' : buf[1];
		Lcd_Custom_Out(1, 1, &buf[1]);
		// 分の表示 
		min &= 0x7F;
		temp = ((min >> 4) & 0x0F) * 10;
		temp += (min & 0x0F);
		ByteToStr(temp, buf);
		buf[0] = ':';
		buf[1] = (buf[1] == ' ') ? '0' : buf[1];
		Lcd_Custom_Out(1, 3, buf);
		// 秒の表示 
		sec &= 0x7F;
		temp = ((sec >> 4) & 0x0F) * 10;
		temp += (sec & 0x0F);
		ByteToStr(temp, buf);
		buf[0] = ':';
		buf[1] = (buf[1] == ' ') ? '0' : buf[1];
		Lcd_Custom_Out(1, 6, buf);
		//
		for (cnt = 0; cnt < 16; cnt++) {
			if ((temp / 4) >= cnt)
				Lcd_Custom_Chr(2, cnt + 1, 0xFF);
			else
				Lcd_Custom_Chr(2, cnt + 1, ' ');			
		}
	}
}
 
//**********************************************************************

動作確認

いつものようにブレッドボードで確認しました。
左上の黄色と緑色のプッシュSWで時分を設定します。
LCD表示の下のバーは、秒の変化を表示したものです。

如何ですか、これ以上簡略化が出来ない程にシンプルにしました。

著作権表示 copyright notice

このページは稲崎様の閉鎖したHPのコピーで、著作権は稲崎様にあります。詳細
This page is a copy of Mr. Inasaki's closed website, and the copyright is held by him.Details