ENGLISH 简体中文 日本語 한국어  


アプリケーションノート3300

I²Cシリアルリアルタイムクロックをマイクロコントローラに接続する方法

要約:このアプリケーションノートでは、ダラスのI²Cインタフェースリアルタイムクロックのための一般的なハードウェア構成とソフトウェア例について説明します。この例は、BCDの日時フォーマットを使用するRTC専用に記述したものです。


ピン配置

説明

このアプリケーションノートでは、ダラスのI²Cシリアルインタフェースリアルタイムクロック(RTC)のための一般的なハードウェア構成と基本的な通信ソフトウェア例について説明します。取り上げたデバイスはBCDフォーマットのI²Cクロック:DS1307、DS1337、DS1338、DS1339、及びDS1340です。回路を変更してCLK入力端子にディジタルクロック信号(32,768Hz、8,192Hz、60Hz、または50Hz)を供給すれば、DS1375も使用することができます。この例で使用するマイクロコントローラはDS2250であり、ソフトウェア例はC言語で記述しています。

回路図を図1に示します。この回路図は、DS1340の接続を示しています。他のRTCは修正を必要とする場合があります。例えば、DS1337では、バッテリバックアップ入力を追加の割り込み出力に置き換えます。低電圧バージョンのRTCでは、DS2250/DS5000を適切な低電圧マイクロコントローラに置き換えることが必要となります。図2は、ソフトウェアのリスト出力です。#define命令は、該当するデバイスのためのコードを条件付きでコンパイルするために使用します。ここに示す例はDS1307用です。コードをコンパイルする前に、DS1307の#defineステートメントを正しいデバイスに置き換える必要があります。

図1. DS1340マイクロコントローラの回路図
大きな画像を見る

図1. DS1340マイクロコントローラの回路図

図2. ソフトウェアのリスト出力
/********************************************************************/
/* DEMO1307.c                                                       */
/* program example for DS1307, DS1337/38/39/40                      */
/********************************************************************/
#include <stdio.h>		/* Prototypes for I/O functions       */
#include <DS5000.h>		/* Register declarations for DS5000   */
/***************************** Defines *****************************/
#define	ACK	0
#define	NACK	1
#define	ADDRTC	0xd0	/* I²C slave address */
#define	DS1307	/* compile directive, modify as required */
/************************* bit definitions *************************/
sbit scl = P0^0;        	/* I²C pin definitions */
sbit sda = P0^1;
sbit sqw = P3^2;		/* pin function depends upon device */

/* General Notes: Define one device to compile options for that device. */
/* Will not compile correctly if no device is defined.  Not all options */
/* for each device are supported.  There is no error checking for data  */
/* entry.  Defines may not remove all code that is not relevant to the  */
/* device. This example was written for an 8051-type micro, the DS2250/ */
/* DS5000.  The program must be modified to work properly on typical    */
/* 8051 variants (i.e. assign I²C bus to unused port pins).  This       */
/* program is for example only and is not supported by Dallas Maxim     */

void	I²C_start();
void	I²C_stop();
void	I²C_write(unsigned char d);
uchar	I²C_read(uchar);
void	readbyte();
void	writebyte();
void	initialize();
void	disp_clk_regs(uchar);
void	burstramwrite(uchar);
void	burstramread();
void	alrm_int();
void	alrm_read();
void	tc_setup();
/* global variables */
uchar	sec, min, hr, dy, dt, mn, yr;
void I²C_start()	/* ----------------------------------------------- */
{
	sda = 1;  scl = 1;	/* Initiate start condition */
	sda = 0;
}
void I²C_stop()		/* ----------------------------------------------- */
{
	sda = 0; sda = 0; sda = 0; sda = 0;	/* Initiate stop condition */
	scl = 1; scl = 1; sda = 1;
}
void I²C_write(uchar d)		/* ----------------------------- */
{
uchar i;

	scl = 0;
	for (i = 1; i <= 8; i++)
	{
		sda = (d >> 7);
		scl = 1;
		d = d << 1;	/* increase scl high time */
		scl = 0;
	}
	sda = 1;	/* Release the sda line */
	scl = 0;
	scl = 1;
	if(sda) printf("Ack bit missing  %02X
",(unsigned int)d);
	scl = 0;
}
uchar I²C_read(uchar b)	/* ----------------------------------- */
{
uchar d, i;

	sda = 1;             /* Let go of sda line */
	scl = 0;
	for (i = 1; i <= 8; i++)	/* read the msb first */
	{
		scl = 1;
		d = d << 1;
		d = d | (unsigned char)sda;
		scl = 0;
	}
	sda = b;          /* Hold sda low for acknowledge */

	scl = 0;
	scl = 1;
	if(b == NACK)	sda = 1;	/* sda = 1 if next cycle is reset */
	scl = 0;

	sda = 1;          /* Release the sda line */
	return d;
}
void readbyte()	/* -- read one byte of data from the specified address -- */
{
uchar Add;
	printf("
ADDRESS: ");	/* Get Address */
	scanf("%bx", &Add);
	I²C_start();
	I²C_write(ADDRTC);
	I²C_write(Add);
	I²C_start();
	I²C_write(ADDRTC | 1);
	printf("%2bx", I²C_read(NACK) );
	I²C_stop();
}
void writebyte()	/* -- write one byte of data to the specified address -- */
{
uchar Add;
uchar Data;
	printf("
Address: ");	/* Get Address */
	scanf("%bx", &Add);
	printf("DATA: ");
	scanf("%bx", &Data);	/* and data */
	I²C_start();
	I²C_write(ADDRTC);
	I²C_write(Add);
	I²C_write(Data);
	I²C_stop();
}
void initialize()	/* -- initialize the time and date using entries from stdin -- */
/* Note: NO error checking is done on the user entries! */
{
uchar	yr, mn, dt, dy, hr, min, sec, day;

	I²C_start();		/* The following Enables the Oscillator */
	I²C_write(ADDRTC);	/* address the part to write */
	I²C_write(0x00);	/* position the address pointer to 0 */
	I²C_write(0x00);	/* write 0 to the seconds register, clear the CH bit */
	I²C_stop();

	printf("
Enter the year (0-99): ");
	scanf("%bx", &yr);
	printf("Enter the month (1-12): ");
	scanf("%bx", &mn);
	printf("Enter the date (1-31): ");
	scanf("%bx", &dt);
	printf("Enter the day (1-7): ");
	scanf("%bx", &dy);
	printf("Enter the hour (1-23): ");
	scanf("%bx", &hr);
	hr = hr & 0x3f;	/* force clock to 24 hour mode */
	printf("Enter the minute (0-59): ");
	scanf("%bx", &min);
	printf("Enter the second (0-59): ");
	scanf("%bx", &sec);

	I²C_start();
	I²C_write(ADDRTC);	/* write slave address + write */
	I²C_write(0x00);	/* write register address, 1st clock register */
	I²C_write(sec);
	I²C_write(min);
	I²C_write(hr);
	I²C_write(dy);
	I²C_write(dt);
	I²C_write(mn);
	I²C_write(yr);

#if defined DS1307 || defined DS1338
{
	I²C_write(0x10);	/* enable sqwe, 1Hz output */
}
#elif defined DS1337 || defined DS1339
{
	I²C_start();
	I²C_write(ADDRTC);	/* write slave address + write */
	I²C_write(0x0e);	/* write register address, control register */
	I²C_write(0x20);	/* enable osc, bbsqi */
	I²C_write(0);		/* clear OSF, alarm flags */
				/* could enable trickle charger here */
}
#elif defined DS1340
{
	I²C_write(0x10);	/* enable sqwe, 1Hz output */
	I²C_start();		/* address pointer wraps at 7, so point to flag register */
	I²C_write(ADDRTC);	/* write slave address + write */
	I²C_write(0x09);	/* write register address, control register */
	I²C_write(0);		/* clear OSF */
}
#endif

	I²C_stop();

}
void	disp_clk_regs(uchar prv_sec)	/* ----------------------------------------- */
{
uchar Sec, Min, Hrs, Dte, Mon, Day, Yr, mil, pm;

	printf("
Yr Mn Dt Dy Hr:Mn:Sc");

	while(!RI)	/* Read & Display Clock Registers */
	{
		I²C_start();
		I²C_write(ADDRTC);	/* write slave address + write */
		I²C_write(0x00);	/* write register address, 1st clock register */
		I²C_start();
		I²C_write(ADDRTC | 1);	/* write slave address + read */
		Sec = I²C_read(ACK);	/* starts w/last address stored in register pointer */
		Min = I²C_read(ACK);
		Hrs = I²C_read(ACK);
		Day = I²C_read(ACK);
		Dte = I²C_read(ACK);
		Mon = I²C_read(ACK);
		Yr  = I²C_read(NACK);
		I²C_stop();
		if(Hrs & 0x40)
			mil = 0;
		else
			mil = 1;

		if(Sec != prv_sec)	/* display every time seconds change */
		{
			if(mil)
			{
				printf("
%02bX/%02bX/%02bX %2bX", Yr, Mon, Dte, Day);
				printf(" %02bX:%02bX:%02bX", Hrs, Min, Sec);
			}
			else
			{
				if(Hrs & 0x20)
					pm = 'A';
				else
					pm = 'P';
				Hrs &= 0x1f;	/* strip mode and am/pm bits */
				printf("
%02bx/%02bx/%02bx %02bx", Yr, (Mon & 0x1f), Dte, Day);
				printf(" %02bx:%02bx:%02bx %cM", Hrs, Min, Sec, pm);
			}
		}
		if(prv_sec == 0xfe)	return;
		prv_sec = Sec;
	}
	RI = 0;  /* Swallow keypress before exiting */
}
void burstramwrite(uchar Data)	/* -------- fill RAM with data -------- */
{
uchar j;

   I²C_start();
	I²C_write(ADDRTC);	/* write slave address + write */
	I²C_write(0x08);	/* write register address, 1st RAM location */
	for (j = 0; j < 56; j++)	/* write until the pointer wraps around */
	{
		I²C_write(Data);
	}
	I²C_stop();
}
void burstramread()		/* ----------------------------------------- */
{
uchar j;

	I²C_start();
	I²C_write(ADDRTC);	/* write slave address + write */
	I²C_write(8);	/* write register address, 1st RAM location -1*/
	I²C_start();
	I²C_write(ADDRTC | 1);	/* write slave address + read */

	for (j = 0; j < 56; j++)
	{
		if(!(j % 16)) printf("
%02bX ", j);
		printf("%02bX ", I²C_read(ACK) );
	}
	I²C_read(NACK);
	I²C_stop();
}
void	alrm_int()	/* ----- initialize alarm registers ------ */
{
uchar	M, Sec, Min, Hr, DyDt;

	printf("
1-Alarm each second
2-Alarm match=sec
3-Alarm match=sec+min");
	printf("
4-Alarm match=sec+min+hr
5-Alarm match=sec+min+hr+date");
	printf("
6-Alarm match=sec+min+hr+day
Enter selection: ");

	M = _getkey();	/* Note-No error checking is done on entries! */

	switch(M)
	{
		case '1':	M = 0xf;	break;
		case '2':	M = 0xe;	break;
		case '3':	M = 0xc;	break;
		case '4':	M = 8;		break;
		case '5':	M = 0;		break;
		case '6':	M = 0x40;	break;
	}
	if(M & 0x40)
	{
		printf("
Enter the day (1-7): ");
		scanf("%bx", &DyDt);
	}
	else
	{
		printf("
Enter the date (1-31): ");
		scanf("%bx", &DyDt);
	}
	printf("Enter the hour (1-23): ");
	scanf("%bx", &Hr);
	printf("Enter the minute (0-59): ");
	scanf("%bx", &Min);
	printf("Enter the second (0-59): ");
	scanf("%bx", &Sec);

	if( (M & 1) )	Sec |= 0x80;
	if( ((M >> 1) & 1) )	Min |= 0x80;
	if( ((M >> 2) & 1) )	Hr |= 0x80;
	if( ((M >> 3) & 1) )	DyDt |= 0x80;
	if(M & 0x40)	DyDt |= 0x40;

	I²C_start();
	I²C_write(ADDRTC);	/* write slave address + write */
	I²C_write(7);		/* write register address */
	I²C_write(Sec);
	I²C_write(Min);
	I²C_write(Hr);
	I²C_write(DyDt);
	I²C_start();
	I²C_write(ADDRTC);	/* write slave address + write */
	I²C_write(0x0e);	/* write register address */
	I²C_write(5);		/* enable interrupts, alarm 1 */
	I²C_stop();
}
void	alrm_read()	/* ----- read alarm registers ------ */
{
uchar	Sec, Min, Hr, DyDt;

	I²C_start();
	I²C_write(ADDRTC);	/* write slave address + write */
	I²C_write(7);		/* write register address */
	I²C_start();
	I²C_write(ADDRTC | 1);	/* write slave address + read */
	Sec = I²C_read(ACK);
	Min = I²C_read(ACK);
	Hr = I²C_read(ACK);
	DyDt = I²C_read(NACK);

	printf("
Alarm 1: %02bx %02bx %02bx %02bx", Sec, Min, Hr, DyDt);
}
void	tc_setup()	/* ---- trickle charger set up routine ---- */
{
uchar	M, val;

#if defined DS1339
	#define	TC 0x10	/* address for DS1339 trickle charge register */
#else
	#define	TC 0x08	/* address for DS1340 trickle charge register */
#endif

	printf("
Enable Trickle Charger (Y/N)? ");
	M = _getkey();

	if(M == 'Y' || M == 'y')
	{
		printf("
1-250 ohm res
2-2K res=sec
3-4K res");

		M = _getkey();	/* Note-No error checking is done on entries! */

		switch(M)
		{
			case '1':	val = 1;	break;
			case '2':	val = 2;	break;
			case '3':	val = 3;	break;
		}
		printf("
1-no diode
2-1 diode");

		M = _getkey();	/* Note-No error checking is done on entries! */

		switch(M)
		{
			case '1':	val += 4;	break;
			case '2':	val += 8;	break;
		}
		I²C_start();
		I²C_write(ADDRTC);		/* write slave address + write */
		I²C_write(TC);		/* write register address */
		I²C_write(val | 0xa0);	/* enable trickle charger per user input */
		I²C_stop();
	}
	else
	{
		I²C_start();
		I²C_write(ADDRTC);		/* write slave address + write */
		I²C_write(TC);		/* write register address */
		I²C_write(0);			/* disable trickle charger */
		I²C_stop();
	}
	I²C_start();
	I²C_write(ADDRTC);		/* write slave address + write */
	I²C_write(TC);		/* write register address */
	I²C_start();
	I²C_write(ADDRTC | 1);	/* write slave address + read */
	printf("
Trickle Charger: %02bx", I²C_read(NACK) );
}
main	(void)	/* ----------------------------------------------------- */
{
uchar	M, M1;

	sqw = 1;	/* set up for read, weak pull-up */

	while (1)
	{
#if defined DS1307
		printf("
DEMO1307 build %s
", __DATE__);
#elif defined DS1337
		printf("
DEMO1337 build %s
", __DATE__);
#elif defined DS1338
		printf("
DEMO1338 build %s
", __DATE__);
#elif defined DS1339
		printf("
DEMO1339 build %s
", __DATE__);
#elif defined DS1340
		printf("
DEMO1340 build %s
", __DATE__);
#endif

		printf("CI Init RTC    CR Read Clock
");
		printf("BR Byte Read   BW Write Byte
");

#if defined DS1337 || defined DS1339	/* only print if part has alarms */
		printf("AI Alarm 1 Int AR Alarm Read
");
#endif
#if defined DS1340 || defined DS1339	/* parts that have trickle charger */
		printf("Tc Trickle charger
");
#endif

#if defined DS1307 || defined DS1338	/* only print if part has RAM */
		printf("RR RAM Read    RW RAM Write
");
#endif

		printf("Enter Menu Selection:");

		M = _getkey();

		switch(M)
		{
			case 'A':
			case 'a':
			printf("
Init or Read: ");
			M1 = _getkey();

			switch(M1)
			{
				case 'I':
				case 'i':	alrm_int(); 	break;

				case 'R':
				case 'r':	alrm_read(); 	break;
			}
			break;

			case 'B':
			case 'b':
			printf("
Read or Write: ");
			M1 = _getkey();

			switch(M1)
			{
				case 'R':
				case 'r':	readbyte(); 	break;

				case 'W':
				case 'w':	writebyte(); 	break;
			}
			break;

			case 'C':
			case 'c':
			printf("\rEnter Clock Routine to run:C");
			M1 = _getkey();

			switch(M1)
			{
				case 'I':
				case 'i':	initialize();	break;

				case 'R':
				case 'r':	disp_clk_regs(0x99);	break;
			}
			break;

			case 'R':
			case 'r':
			printf("\rEnter Ram Routine to run:R");
			M1 = _getkey();

			switch(M1)
			{
				case 'R':
				case 'r':	burstramread();	break;

				case 'W':
				case 'w':	printf("
Enter the data to write: ");
						scanf("%bx", &M1);
						burstramwrite(M1);	break;
			}
			break;

			case 'T':
			case 't':	tc_setup();	break;
		}
	}
}


フィードバックをお寄せください。
内容に満足されましたか、あるいは満足されていませんか?もっと良いページにできると思いますか?あるいは、単なるコメントでも結構です。フィードバックをお待ちしています。—マキシムはお客様からいただく訂正、提案を元に改善していきます。 このページを評価し、フィードバックを送信する。


自動アップデート
お客様が関心のある分野でアプリケーションノートが新規に掲載された際に自動通知Eメールの受信を希望する場合は、EE-Mail™にご登録ください。



その他の情報  APP 3300: Mar 15, 2005
DS1307 64 x 8、シリアル、I²Cリアルタイムクロック フルデータシート
(PDF, 700kB)
無料
サンプル
DS1337 I²Cシリアルリアルタイムクロック フルデータシート
(PDF, 388kB)
無料
サンプル
DS1338 56バイトNV RAM付き、I²C RTC フルデータシート
(PDF, 804kB)
無料
サンプル
DS1339 I²Cシリアルリアルタイムクロック フルデータシート
(PDF, 560kB)
無料
サンプル
DS1340 トリクルチャージャ付I²C RTC フルデータシート
(PDF, 244kB)
無料
サンプル
DS1375 アラーム付き、2線式ディジタル入力RTC フルデータシート
(PDF, 328kB)
無料
サンプル
 

ダウンロード、PDFフォーマットダウンロード、PDFフォーマット (38kB)
 AN3300, AN 3300, APP3300, Appnote3300, Appnote 3300



         


      プライバシーポリシー    法的お知らせ

      Copyright © 2008 by Maxim Integrated Products, Dallas Semiconductor