??? 01/16/09 12:12 Read: times |
#161555 - its working Responding to: ???'s previous message |
Dear all,
Firstly, sorry for the delayed reply. I was off on leave. Now that I am back things are going quiet smoothly. I found the "bug" in my code. The problems were: * read() was shifting the MSB out. * Device READ ADDRESS was incorrect. I am updating my code for a review. /* A program demonstrating application of DS1307 as a Real Time Clock */ #include <error_funcs.c> /* this has some basic IO and delay functions */ #define SCL P1_6 #define SDA P1_7 #define DS1307_READ_ADDR 0XD1 #define DS1307_WRITE_ADDR 0XD0 #define HIGH 1 #define LOW 0 #define ACK LOW #define NACK HIGH #define ERROR LOW #define SUCCESS HIGH __sbit __at (0x96) P1_6 ; __sbit __at (0x97) P1_7 ; enum time { SECONDS, MINUTES, HOURS, DAY, DATE, MONTH, YEAR, CONTROL }; enum day { SUN, MON, TUE, WED, THU, FRI, SAT }; enum month { JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT = 0x10, /* BCD 10 = 0x10 */ NOV, DEC }; typedef struct time_reg { unsigned char sec; unsigned char min; unsigned char hour; unsigned char day; unsigned char date; unsigned char mon; unsigned char year; } time_t; /* I2C functions */ void start() { /* I2C START condition */ SCL = SDA = HIGH; NOP; SDA = LOW; NOP; SCL = LOW; } void stop() { /* I2C STOP condition */ SDA = LOW; SCL = HIGH; NOP; SDA = HIGH; NOP; SCL = LOW; } unsigned char clock() { /* A subroutine to generate a clock pulse and return the * status of the data bus during the clock period */ unsigned char status = 0; SCL = HIGH; NOP; while(!SCL); /* eliminate ripples */ status = SDA; SCL = LOW; return (status); } unsigned char write(unsigned char byte) { /* I2C WRITE operation, Write a byte on SDA and return the * acknowledgement */ unsigned char mask = 0x80; unsigned char status= ACK; for ( ; mask > 0 ; ) { SDA = (byte & mask) ? ( SET ):( CLEAR ) ; mask >>= 1; clock(); } status = clock(); return (status); /* return the status of SDA line on * the 9th pulse */ } unsigned char read(unsigned char status) { /* I2C READ operation, read one byte from the transmitter and * give ack/nack to it */ unsigned char byte = 0; unsigned char count; for ( count = 0; count < 8; count++ ) { byte <<= 1; /* 1 */ byte |= clock(); /* 2 */ /* My mistake was (1) followed (2) so MSB was pushed out during the last iteration and the read values were "NOT BCD but HEX" */ } SDA = status; /* status = 1 :- NACK * status = 0 :- ACK */ clock(); return byte; } /* RTC functions */ unsigned char read_rtc(unsigned char addr) { /* Read a byte from RTC */ unsigned char byte = 0; start(); if ( write(DS1307_WRITE_ADDR) == ACK ) { if ( write(addr) == ACK) { start(); if ( write(DS1307_READ_ADDR) == ACK ) byte = read(NACK); else print_on_lcd("write device read address failed!"); } else print_on_lcd("Write addr to RTC failed"); } else print_on_lcd("RTC is not selected in read()!!!!!"); stop(); return byte; } unsigned char write_rtc(unsigned char addr, unsigned char byte) { /* Write a byte to RTC */ unsigned char status = ERROR; start(); if ( write(DS1307_WRITE_ADDR) == ACK ) { if ( write( addr ) == ACK ) { if ( write( byte ) == ACK ) status = SUCCESS; else print_on_lcd("write byte to RTC failed!!"); } else print_on_lcd("write address failed!!"); } else print_on_lcd("device not selected!!"); stop(); delay_millisec(4); return status; } /* Enable the internal oscillator */ #define init_rtc() if ( write_rtc(CONTROL, 0x00) == ACK ) print_on_lcd("RTC initiated") void time( time_t * new, time_t *old) { /* A function to get time/set RTC time. Time is set to values * refered by 'new'(if its not NULL) and the previous values * are read to 'old' */ if ( old ) { /* read time registers to 'old'*/ old->sec = read_rtc(SECONDS); old->min = read_rtc(MINUTES); old->hour = read_rtc(HOURS); old->day = read_rtc(DAY); old->date = read_rtc(DATE); old->mon = read_rtc(MONTH); old->year = read_rtc(YEAR); } if ( new != NULL ) { /* set timer registers to new values */ write_rtc(SECONDS, new->sec); write_rtc(MINUTES, new->min); write_rtc(HOURS, new->hour); write_rtc(DAY, new->day); write_rtc(DATE, new->date); write_rtc(MONTH, new->mon); write_rtc(YEAR, new->year); } } void show_time() { /* A function to display time on LCD */ unsigned char format[] = "time = HH:MM:SS dt- DT DA:MON:YE"; time_t tm; time( NULL, &tm); /* get time */ /* convert BCD to ASCII */ format[7] = (tm.hour >> 4) + '0'; format[8] = (tm.hour & 0x0F) + '0'; format[10] = (tm.min >> 4) + '0'; format[11] = (tm.min & 0x0F) + '0'; format[13] = (tm.sec >> 4) + '0'; format[14] = (tm.sec & 0x0F) + '0'; /* display AM or PM */ format[15] = (tm.hour & 0x40) ? ( (tm.hour & 0x20)? 'a' :'p' ):(' '); format[20] = (tm.date >> 4) + '0'; format[21] = (tm.date & 0x0F) + '0'; /* get day of the week */ switch (tm.day) { case SUN: format[23] = 'S'; format[24] = 'U'; break; case MON: format[23] = 'M'; format[24] = 'O'; break; case TUE: format[23] = 'T'; format[24] = 'U'; break; case WED: format[23] = 'W'; format[24] = 'E'; break; case THU: format[23] = 'T'; format[24] = 'H'; break; case FRI: format[23] = 'F'; format[24] = 'R'; break; case SAT: format[23] = 'S'; format[24] = 'A'; } /* get month */ switch (tm.mon) { case JAN: format[26] = 'J'; format[27] = 'A'; format[28] = 'N'; break; case FEB: format[26] = 'F'; format[27] = 'E'; format[28] = 'B'; break; case MAR: format[26] = 'M'; format[27] = 'A'; format[28] = 'R'; break; case APR: format[26] = 'A'; format[27] = 'P'; format[28] = 'R'; break; case MAY: format[26] = 'M'; format[27] = 'A'; format[28] = 'Y'; break; case JUN: format[26] = 'J'; format[27] = 'U'; format[28] = 'N'; break; case JUL: format[26] = 'J'; format[27] = 'U'; format[28] = 'L'; break; case AUG: format[26] = 'A'; format[27] = 'U'; format[28] = 'G'; break; case SEP: format[26] = 'S'; format[27] = 'E'; format[28] = 'P'; break; case OCT: format[26] = 'O'; format[27] = 'C'; format[28] = 'T'; break; case NOV: format[26] = 'N'; format[27] = 'O'; format[28] = 'V'; break; case DEC: format[26] = 'D'; format[27] = 'E'; format[28] = 'C'; } format[30] = (tm.year >> 4) + '0'; format[31] = (tm.year & 0x0F) + '0'; print_on_lcd(format); delay_millisec(200); } main() { time_t new = { 0x17, 0x35, 0x13, THU, 0x15, JAN, 0x09}; /* date is: "Thu Jan 15 13:35:17 2009" */ init_lcd(); init_rtc(); time( &new, NULL); /* set time */ while (1) show_time(); /* keep showing time */ } your comments and reviews are welcome. thank you for your suggestions, time and intrest. Best regards, Sarma |
Topic | Author | Date |
DS1307 Memory Read and Write | 01/01/70 00:00 | |
Know your code? | 01/01/70 00:00 | |
Another thing to consider... | 01/01/70 00:00 | |
Pinnacle 52 | 01/01/70 00:00 | |
The RAM is same as ordinary registers. | 01/01/70 00:00 | |
Debugging Strategy | 01/01/70 00:00 | |
Debugging Strategy for DS1307 memory Reading | 01/01/70 00:00 | |
next step | 01/01/70 00:00 | |
Be more specific. | 01/01/70 00:00 | |
a minor correction | 01/01/70 00:00 | |
Which i2c device? | 01/01/70 00:00 | |
another small correction | 01/01/70 00:00 | |
SMBus | 01/01/70 00:00 | |
Which REAL i2c device | 01/01/70 00:00 | |
apples and oranges | 01/01/70 00:00 | |
Sorry Erik | 01/01/70 00:00 | |
as I recall | 01/01/70 00:00 | |
its working![]() | 01/01/70 00:00 |