摘要:本應用筆記提供了Dallas I2C接口實時時鐘的通用硬件配置和軟件例程。本例程適用于采用BCD碼時間和日期格式的RTC。
引腳配置
示意圖如圖1所示,圖中給出了DS1340的連接方式。對于其它型號的RTC,可能需要修改電路。例如:DS1337,用中斷輸出替代了備用電池輸入端。對于低電壓RTC,需要用適當的低電壓微控制器替代DS2250/DS5000。圖2給出了軟件清單。#定義說明用來表示特定器件有條件的編譯代碼。本例程用于DS1307。編譯代碼之前,用于DS1307的#定義說明應該用正確的器件代替。
放大圖形
圖1. DS1340和微控制器電路示意圖
圖2. 軟件清單
引腳配置
說明
本應用筆記描述了Dallas I2C串行接口實時時鐘(RTC)的通用硬件配置,并提供了基本通信軟件例程。這些器件包括BCD格式的I2C時鐘:DS1307、DS1337、DS1338、DS1339和DS1340。如果對電路進行某些修改,為CLK輸入引腳提供數字時鐘信號(32,768Hz、8,192Hz、60Hz或50Hz),還可支持DS1375。本范例中使用了DS2250微控制器,軟件為C語言程序。示意圖如圖1所示,圖中給出了DS1340的連接方式。對于其它型號的RTC,可能需要修改電路。例如:DS1337,用中斷輸出替代了備用電池輸入端。對于低電壓RTC,需要用適當的低電壓微控制器替代DS2250/DS5000。圖2給出了軟件清單。#定義說明用來表示特定器件有條件的編譯代碼。本例程用于DS1307。編譯代碼之前,用于DS1307的#定義說明應該用正確的器件代替。
放大圖形
圖1. DS1340和微控制器電路示意圖
圖2. 軟件清單
/********************************************************************/ /* DEMO1307.c */ /* program example for DS1307, DS1337/38/39/40 */ /********************************************************************/ #include/* Prototypes for I/O functions */ #include /* Register declarations for DS5000 */ /***************************** Defines *****************************/ #define ACK 0 #define NACK 1 #define ADDRTC 0xd0 /* I2C slave address */ #define DS1307 /* compile directive, modify as required */ /************************* bit definitions *************************/ sbit scl = P0^0; /* I2C 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 I2C bus to unused port pins). This */ /* program is for example only and is not supported by Dallas Maxim */ void I2C_start(); void I2C_stop(); void I2C_write(unsigned char d); uchar I2C_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 I2C_start() /* ----------------------------------------------- */ { sda = 1; scl = 1; /* Initiate start condition */ sda = 0; } void I2C_stop() /* ----------------------------------------------- */ { sda = 0; sda = 0; sda = 0; sda = 0; /* Initiate stop condition */ scl = 1; scl = 1; sda = 1; } void I2C_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 I2C_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); I2C_start(); I2C_write(ADDRTC); I2C_write(Add); I2C_start(); I2C_write(ADDRTC | 1); printf("%2bx", I2C_read(NACK) ); I2C_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 */ I2C_start(); I2C_write(ADDRTC); I2C_write(Add); I2C_write(Data); I2C_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; I2C_start(); /* The following Enables the Oscillator */ I2C_write(ADDRTC); /* address the part to write */ I2C_write(0x00); /* position the address pointer to 0 */ I2C_write(0x00); /* write 0 to the seconds register, clear the CH bit */ I2C_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); I2C_start(); I2C_write(ADDRTC); /* write slave address + write */ I2C_write(0x00); /* write register address, 1st clock register */ I2C_write(sec); I2C_write(min); I2C_write(hr); I2C_write(dy); I2C_write(dt); I2C_write(mn); I2C_write(yr); #if defined DS1307 || defined DS1338 { I2C_write(0x10); /* enable sqwe, 1Hz output */ } #elif defined DS1337 || defined DS1339 { I2C_start(); I2C_write(ADDRTC); /* write slave address + write */ I2C_write(0x0e); /* write register address, control register */ I2C_write(0x20); /* enable osc, bbsqi */ I2C_write(0); /* clear OSF, alarm flags */ /* could enable trickle charger here */ } #elif defined DS1340 { I2C_write(0x10); /* enable sqwe, 1Hz output */ I2C_start(); /* address pointer wraps at 7, so point to flag register */ I2C_write(ADDRTC); /* write slave address + write */ I2C_write(0x09); /* write register address, control register */ I2C_write(0); /* clear OSF */ } #endif I2C_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 */ { I2C_start(); I2C_write(ADDRTC); /* write slave address + write */ I2C_write(0x00); /* write register address, 1st clock register */ I2C_start(); I2C_write(ADDRTC | 1); /* write slave address + read */ Sec = I2C_read(ACK); /* starts w/last address stored in register pointer */ Min = I2C_read(ACK); Hrs = I2C_read(ACK); Day = I2C_read(ACK); Dte = I2C_read(ACK); Mon = I2C_read(ACK); Yr = I2C_read(NACK); I2C_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; I2C_start(); I2C_write(ADDRTC); /* write slave address + write */ I2C_write(0x08); /* write register address, 1st RAM location */ for (j = 0; j < 56; j++) /* write until the pointer wraps around */ { I2C_write(Data); } I2C_stop(); } void burstramread() /* ----------------------------------------- */ { uchar j; I2C_start(); I2C_write(ADDRTC); /* write slave address + write */ I2C_write(8); /* write register address, 1st RAM location -1*/ I2C_start(); I2C_write(ADDRTC | 1); /* write slave address + read */ for (j = 0; j < 56; j++) { if(!(j % 16)) printf(" %02bX ", j); printf("%02bX ", I2C_read(ACK) ); } I2C_read(NACK); I2C_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; I2C_start(); I2C_write(ADDRTC); /* write slave address + write */ I2C_write(7); /* write register address */ I2C_write(Sec); I2C_write(Min); I2C_write(Hr); I2C_write(DyDt); I2C_start(); I2C_write(ADDRTC); /* write slave address + write */ I2C_write(0x0e); /* write register address */ I2C_write(5); /* enable interrupts, alarm 1 */ I2C_stop(); } void alrm_read() /* ----- read alarm registers ------ */ { uchar Sec, Min, Hr, DyDt; I2C_start(); I2C_write(ADDRTC); /* write slave address + write */ I2C_write(7); /* write register address */ I2C_start(); I2C_write(ADDRTC | 1); /* write slave address + read */ Sec = I2C_read(ACK); Min = I2C_read(ACK); Hr = I2C_read(ACK); DyDt = I2C_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; } I2C_start(); I2C_write(ADDRTC); /* write slave address + write */ I2C_write(TC); /* write register address */ I2C_write(val | 0xa0); /* enable trickle charger per user input */ I2C_stop(); } else { I2C_start(); I2C_write(ADDRTC); /* write slave address + write */ I2C_write(TC); /* write register address */ I2C_write(0); /* disable trickle charger */ I2C_stop(); } I2C_start(); I2C_write(ADDRTC); /* write slave address + write */ I2C_write(TC); /* write register address */ I2C_start(); I2C_write(ADDRTC | 1); /* write slave address + read */ printf(" Trickle Charger: %02bx", I2C_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; } } }
評論
查看更多