개요: 이 애플리케이션 노트는 Dallas I²C 인터페이스 실시간 클록(RTC)을 위한 일반적인 하드웨어 구성 및 예제 소프트웨어에 대해 설명한다. 이 예제는 특별히 BCD 시간 및 날짜 형식을 사용하는 RTC를 위해 작성되었다.
핀 배열
설명
이 애플리케이션 노트는 Dallas 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 명령문은 코드를 컴파일하기 전에 정확한 소자로 교체되어야 한다.
For Larger Image그림 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 *****************************/
#defineACK0
#defineNACK1
#defineADDRTC0xd0/* I²C slave address */
#defineDS1307/* 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 */
voidI²C_start();
voidI²C_stop();
voidI²C_write(unsigned char d);
ucharI²C_read(uchar);
voidreadbyte();
voidwritebyte();
voidinitialize();
voiddisp_clk_regs(uchar);
voidburstramwrite(uchar);
voidburstramread();
voidalrm_int();
voidalrm_read();
voidtc_setup();
/* global variables */
ucharsec, 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! */
{
ucharyr, 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();
}
voiddisp_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();
}
voidalrm_int()/* ----- initialize alarm registers ------ */
{
ucharM, 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();
}
voidalrm_read()/* ----- read alarm registers ------ */
{
ucharSec, 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);
}
voidtc_setup()/* ---- trickle charger set up routine ---- */
{
ucharM, val;
#if defined DS1339
#defineTC 0x10/* address for DS1339 trickle charge register */
#else
#defineTC 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)/* ----------------------------------------------------- */
{
ucharM, 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;
}
}
}
관련 부품
APP 3300: Jan 17, 2005
자동 업데이트
관심 분야의 애플리케이션 노트가 나올 때 자동으로 업데이트를 원하십니까? 그렇다면 EE-Mail™을 신청하십시오 .
의견을 보내주세요! 위 내용이 도움이 되셨나요?여러분의 의견을 기다립니다 — Maxim은 보내주신 정정이나 제안사항을 반영하고 있습니다.
이 페이지를 평가하고 의견을 보내주십시오.
다운로드, PDF 형식 (38kB)
AN3300,
AN 3300,
APP3300,
Appnote3300,
Appnote 3300