1. You can now buy finished microcontroller project from us, Check out the Store for the complete list of projects.
  2. Need a custom project, Send us some details about your project. So that we can quote the price for it.

DS1307 NVRAM access

Discussion in 'Electronic Projects Design/Ideas/Reviews' started by Sarma, Jan 8, 2009.

  1. Sarma

    Sarma New Member

    Likes Received:
    0
    Trophy Points:
    0
    hi there,

    I am working with ds1307 RTC, My routines for I2C start, stop read and write conditions are working. I am not able to write/read to the NVRAM of RTC. can any one suggest me how to debug these errors?

    Thanks in advance.
  2. Binu

    Binu Administrator

    Likes Received:
    135
    Trophy Points:
    63
    Are you using assembly language or any other.
    if assembly then you can check the Automatic college bell project, in which i have stored a value on the RAM.
    But it is not NVRAM, its RAM. It keeps the value until the main power or battery backup is provided.
  3. Sarma

    Sarma New Member

    Likes Received:
    0
    Trophy Points:
    0
    No, I am using C language. my controller is P89C668HBA and compiler is SDCC. for debugging I am checking the status of SDA line during each clock pulse(SCL = high). The write_to_memory() is working fine but read_from_memory() is always reading 0.
  4. Binu

    Binu Administrator

    Likes Received:
    135
    Trophy Points:
    63
    How do you say the writing is working fine, did you load any values on the clock register. post the code here so that we can help you.
  5. Sarma

    Sarma New Member

    Likes Received:
    0
    Trophy Points:
    0
    Sorry Binu for a delayed reply.
    I was off on leave.
    I have found these problems in my code.

    * read() function was pushing MSBit out
    * READ DEVICE ADDRESS was wrong

    Now that I have fixed them, my code is working.
    I am leaving my code here for a review. This code is for P89C668HBA controller and on SDCC compiler

    /* 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 the MSBit was pushed out in the last iteration*/
    }
    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 */
    }



    Comments and reviews are welcome

    best regards,
    Sarma
Loading...

Share This Page

Loading...