CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

DS3231 High Precision I2C RTC Driver

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
sshahryiar



Joined: 05 May 2010
Posts: 94
Location: Dhaka, Bangladesh

View user's profile Send private message Send e-mail Visit poster's website

DS3231 High Precision I2C RTC Driver
PostPosted: Wed Apr 10, 2013 10:28 pm     Reply with quote

DS3231.h

Code:
#define DS3231_Address              0x68           
                                                 
#define DS3231_Read_addr            ((DS3231_Address << 1) | 0x01)
#define DS3231_Write_addr           ((DS3231_Address << 1) & 0xFE)
                                           
#define secondREG                   0x00
#define minuteREG                   0x01
#define hourREG                     0x02
#define dayREG                      0x03
#define dateREG                     0x04                             
#define monthREG                    0x05                           
#define yearREG                     0x06                   
#define alarm1secREG                0x07       
#define alarm1minREG                0x08
#define alarm1hrREG                 0x09           
#define alarm1dateREG               0x0A 
#define alarm2minREG                0x0B   
#define alarm2hrREG                 0x0C
#define alarm2dateREG               0x0D
#define controlREG                  0x0E
#define statusREG                   0x0F
#define ageoffsetREG                0x10
#define tempMSBREG                  0x11
#define tempLSBREG                  0x12
                                 
#define _24_hour_format             0
#define _12_hour_format             1
#define am                          0
#define pm                          1

                                                               
unsigned char bcd_to_decimal(unsigned char d);
unsigned char decimal_to_bcd(unsigned char d);                     
unsigned char DS3231_Read(unsigned char address);
void DS3231_Write(unsigned char address, unsigned char value);
void DS3231_init(); 
void getTime(unsigned char &p3, unsigned char &p2, unsigned char &p1, short &p0, short hour_format); 
void getDate(unsigned char &p4, unsigned char &p3, unsigned char &p2, unsigned char &p1);   
void setTime(unsigned char hSet, unsigned char mSet, unsigned char sSet, short am_pm_state, short hour_format);
void setDate(unsigned char daySet, unsigned char dateSet, unsigned char monthSet, unsigned char yearSet);   
float getTemp();


DS3231.c

Code:
#include "DS3231.h"                                                       
                                                                 
                                                         
unsigned char bcd_to_decimal(unsigned char d)               
{                                                                                         
         return ((d & 0x0F) + (((d & 0xF0) >> 4) * 10));
}                               
                                                             

unsigned char decimal_to_bcd(unsigned char d)
{
         return (((d / 10) << 4) & 0xF0) | ((d % 10) & 0x0F);
}                                                   
                                       
                 
unsigned char DS3231_Read(unsigned char address)
{                                     
         unsigned char value = 0;
         I2C_start();                                                     
         I2C_write(DS3231_Write_addr);     
         I2C_write(address);           
         I2C_start();                 
         I2C_write(DS3231_Read_addr);   
         value = I2C_read(0);                     
         I2C_stop();                 
         return value;
}                     


void DS3231_Write(unsigned char address, unsigned char value)   

         I2C_start();                 
         I2C_write(DS3231_Write_addr);
         I2C_write(address);
         I2C_write(value);   
         I2C_stop();



void DS3231_init()
{                                   
         DS3231_Write(controlREG, 0x00); 
         DS3231_Write(statusREG, 0x08);
}                       


void getTime(unsigned char &p3, unsigned char &p2, unsigned char &p1, short &p0, short hour_format)
{                       
         unsigned char tmp = 0;
         p1 = DS3231_Read(secondREG);
         p1 = bcd_to_decimal(p1);
         p2 = DS3231_Read(minuteREG);
         p2 = bcd_to_decimal(p2);
         switch(hour_format)
         {                                             
                  case 1:         
                  {         
                           tmp = DS3231_Read(hourREG);
                           tmp &= 0x20;
                           p0 = (short)(tmp >> 5);             
                           p3 = (0x1F & DS3231_Read(hourREG));
                           p3 = bcd_to_decimal(p3);                           
                           break;     
                  }   
                  default:
                  {
                           p3 = (0x3F & DS3231_Read(hourREG));           
                           p3 = bcd_to_decimal(p3);   
                           break;     
                  }
         } 
}                                 
                                                     
                               
void getDate(unsigned char &p4, unsigned char &p3, unsigned char &p2, unsigned char &p1)
{
         p1 = DS3231_Read(yearREG);
         p1 = bcd_to_decimal(p1);                 
         p2 = (0x1F & DS3231_Read(monthREG));
         p2 = bcd_to_decimal(p2);                               
         p3 = (0x3F & DS3231_Read(dateREG));
         p3 = bcd_to_decimal(p3);   
         p4 = (0x07 & DS3231_Read(dayREG));   
         p4 = bcd_to_decimal(p4);                   
}

                                                   
void setTime(unsigned char hSet, unsigned char mSet, unsigned char sSet, short am_pm_state, short hour_format) 
{                                                                                                             
         unsigned char tmp = 0;
         DS3231_Write(secondREG, (decimal_to_bcd(sSet)));
         DS3231_Write(minuteREG, (decimal_to_bcd(mSet)));       
         switch(hour_format)
         {
                  case 1:
                  {       
                           switch(am_pm_state)
                           {
                                    case 1:
                                    {           
                                             tmp = 0x60;
                                             break;
                                    }
                                    default:
                                    {   
                                             tmp = 0x40;
                                             break;
                                    }
                           }                           
                           DS3231_Write(hourREG, ((tmp | (0x1F & (decimal_to_bcd(hSet))))));                   
                           break;
                  }                                             
                 
                  default:
                  {
                           DS3231_Write(hourREG, (0x3F & (decimal_to_bcd(hSet))));
                           break;
                  } 
         }   
}                                                 

                                   
void setDate(unsigned char daySet, unsigned char dateSet, unsigned char monthSet, unsigned char yearSet)
{         
         DS3231_Write(dayREG, (decimal_to_bcd(daySet)));           
         DS3231_Write(dateREG, (decimal_to_bcd(dateSet))); 
         DS3231_Write(monthREG, (decimal_to_bcd(monthSet)));
         DS3231_Write(yearREG, (decimal_to_bcd(yearSet)));   
}

                               
float getTemp()                                                 
{
         register float t = 0.0;
         unsigned char lowByte = 0;
         signed char highByte = 0;
         lowByte = DS3231_Read(tempLSBREG);
         highByte = DS3231_Read(tempMSBREG); 
         lowByte >>= 6;                 
         lowByte &= 0x03;     
         t = ((float)lowByte); 
         t *= 0.25;     
         t += highByte;         
         return t;
                                     
}

_________________
https://www.facebook.com/MicroArena

SShahryiar
zamzam23



Joined: 25 Aug 2010
Posts: 47

View user's profile Send private message

PostPosted: Sat Jan 31, 2015 5:22 am     Reply with quote

thanks for the library.

can you send to us a example code for how we can use this library?
sshahryiar



Joined: 05 May 2010
Posts: 94
Location: Dhaka, Bangladesh

View user's profile Send private message Send e-mail Visit poster's website

Example Code
PostPosted: Sat Jan 31, 2015 7:00 am     Reply with quote

Code:

#include <16F877A.h>


#device *= 16

                                                                     
#fuses NOWDT, HS, PROTECT, CPD, NOWRT, BROWNOUT, NODEBUG, NOLVP, PUT
                   
                       
#use delay (clock = 10MHz)           
#use I2C(Master, SDA = pin_C4, SCL = pin_C3)
                                 
                               
#define rowA      pin_B6                 
#define rowB      pin_B5
#define rowC      pin_B4
#define rowD      pin_B3

#define col1      !input(pin_B2)   
#define col2      !input(pin_B1)   
#define col3      !input(pin_B0)

#define dly_1     2000
#define dly_2      300
                           

#include "lcd.c"             
#include "DS3231.c"   
                               
                           
unsigned char s = 10;                   
unsigned char min = 10;             
unsigned char hr = 10;   
unsigned char dy = 1;   
unsigned char dt = 31;             
unsigned char mt = 12;                   
unsigned char yr = 99;
short hr_format = _12_hour_format;
short am_pm = 1;                                                     
                                   
                                     
void setup();   
unsigned char getKbd();       
unsigned char getParameter(unsigned char p , unsigned char max, unsigned char min, unsigned char x_pos, unsigned char y_pos);
unsigned char makeNumber(unsigned char _10thDigit, unsigned char _1stDigit);   
void settings(); 
unsigned char setDay(unsigned char dayValue, unsigned char x_pos, unsigned char y_pos);
void showDay(unsigned char day_val, unsigned char x_pos, unsigned char y_pos); 
void showParameters();
                                                                     
                                                                       
void main()           
{                               
         setup();
         setTime(hr, min, s, am_pm, hr_format); 
         setDate(dy, dt, mt, yr);                   
         while(TRUE)                                 
         {                                   
                  getTime(hr, min, s, am_pm, hr_format);
                  getDate(dy, dt, mt, yr);   
                  if(getKbd() == 0x0A)
                  {               
                           settings(); 
                  }
                  showParameters();             
         };                               
}                                             

                           
void setup()             
{   
         disable_interrupts(global);     
         setup_comparator(NC_NC_NC_NC);
         setup_ADC(ADC_off);                       
         setup_ADC_ports(no_analogs);
         setup_timer_0(0 | 0| 0); 
         setup_timer_1(T1_disabled);
         setup_timer_2(T2_disabled, 255, 1);
         set_timer0(0);
         set_timer1(0);
         set_timer2(0);
         setup_SPI(SPI_disabled | SPI_SS_disabled);
         setup_PSP(PSP_disabled);   
         setup_CCP1(CCP_off);
         setup_CCP2(CCP_off);
         set_tris_B(0x0F);   
         port_B_pullups(TRUE);
         DS3231_init();
         lcd_init();         
         lcd_putc("\f");
}                             
                               

unsigned char getKbd()
{
         output_low(rowA);
         output_high(rowB);
         output_high(rowC);
         output_high(rowD);
         if(col1)                         
         { 
                  return 0x01;
         }   
         else if(col2)
         {                   
                  return 0x02;
         }
         else if(col3)
         { 
                  return 0x03;
         } 

         output_low(rowB);
         output_high(rowA);
         output_high(rowC);
         output_high(rowD);
         if(col1)
         { 
                  return 0x04;
         }   
         else if(col2)
         { 
                  return 0x05;
         }
         else if(col3)
         { 
                  return 0x06;
         }

         output_low(rowC);
         output_high(rowA);
         output_high(rowB);
         output_high(rowD);
         if(col1)
         { 
                  return 0x07;
         }   
         else if(col2)
         { 
                  return 0x08;
         }
         else if(col3)
         { 
                  return 0x09;
         }     

         output_low(rowD);
         output_high(rowA);
         output_high(rowB);
         output_high(rowC);
         if(col1)       
         {               
                  return 0x0A;
         }   
         else if(col2)
         { 
                  return 0x00;
         }                               
         else if(col3)         
         { 
                  return 0x0B;
         }
         else
         {
                  return 0x10;
         }
}   

                                 
unsigned char getParameter(unsigned char p , unsigned char max, unsigned char min, unsigned char x_pos, unsigned char y_pos)
{                                   
         short char_pos = 1;
         unsigned char n = 0;                   
         unsigned char n1 = 0;         
         unsigned char n2 = 0;   
         lcd_gotoxy(x_pos, y_pos);
         printf(lcd_putc, "%02u", p);           
         for(;;)                     
         {                 
                  if(getKbd() != 0x10)             
                  {
                           n = getKbd();       
                           if((n >= 0) && (n <= 9))
                           { 
                                    char_pos = ~char_pos; 
                           }
                           delay_ms(dly_2);
                  }             
                  if(!char_pos)   
                  {                                     
                           if((n >= 0) && (n <= 9))
                           {       
                                    n1 = n;
                                    lcd_gotoxy(x_pos, y_pos); 
                                    printf(lcd_putc, "%u", n1);
                           } 
                  }
                  else   
                  {
                           if((n >= 0) && (n <= 9))
                           {               
                                    n2 = n;
                                    lcd_gotoxy((x_pos + 1), y_pos);
                                    printf(lcd_putc, "%u", n2);
                           }         
                  }                                             
                  if(getKbd() == 0x0B)
                  {                                   
                           p = makeNumber(n1, n2);
                           if((p <= max) && (p >= min))
                           {                                             
                                    return p;
                           }
                           else
                           {
                                    return 1;
                           }
                  }
         }                 
}
                                             

unsigned char makeNumber(unsigned char _10thDigit, unsigned char _1stDigit)
{
         return ((_10thDigit * 10) + _1stDigit);
}


void settings()
{
         lcd_putc("\f");
         lcd_gotoxy(8, 2);       
         lcd_putc("Setup");   
         lcd_gotoxy(6, 3);       
         lcd_putc("Parameters");   
         delay_ms(dly_1);
         lcd_putc("\f");
         lcd_gotoxy(5, 1);     
         lcd_putc("Hour Format"); 
         lcd_gotoxy(1, 2);
         lcd_putc("0. 24 Hour Format");
         lcd_gotoxy(1, 3);                       
         lcd_putc("1. 12 Hour Format");
         lcd_gotoxy(1, 4); 
         lcd_putc("Selection: "); 
         while(getKbd() > 1)
         {                         
                  delay_ms(40);
                  hr_format = getKbd();
         }
         lcd_gotoxy(12, 4);
         printf(lcd_putc, "%d", hr_format);
         delay_ms(dly_1);
         lcd_putc("\f");   
         lcd_gotoxy(7, 1);     
         lcd_putc("Set Time");   
         switch(hr_format)   
         {                 
                  case 1:             
                  {
                           lcd_gotoxy(4, 2);                 
                           lcd_putc("00:00:00  AM");             
                           hr = getParameter(hr, 12, 1, 4, 2);   
                           lcd_gotoxy(7, 2);                 
                           lcd_putc("00:00  AM");             
                           min = getParameter(min, 59, 0, 7, 2); 
                           lcd_gotoxy(10, 2);                 
                           lcd_putc("00  AM");             
                           s = getParameter(s, 59, 0, 10, 2);
                           break;
                  }
                  default:                             
                  {
                           lcd_gotoxy(7, 2);                 
                           lcd_putc("00:00:00");
                           hr = getParameter(hr, 23, 0, 7, 2);   
                           lcd_gotoxy(10, 2);                 
                           lcd_putc("00:00");
                           min = getParameter(min, 59, 0, 10, 2);
                           lcd_gotoxy(13, 2);                                 
                           lcd_putc("00");
                           s = getParameter(s, 59, 0, 13, 2); 
                           break;
                  }
         }
         if(hr_format)
         {
                  while(getKbd() > 1)
                  {                         
                           delay_ms(40);
                           am_pm = getKbd();
                  }                     
                  lcd_gotoxy(14, 2);
                  switch(am_pm)         
                  {
                           case 1:                 
                           {
                                    lcd_putc("PM");
                                    break;
                           } 
                           default:
                           {
                                    lcd_putc("AM");
                                    break;
                           }
                  }     
         }                                                     
         lcd_gotoxy(7, 3);     
         lcd_putc("Set Date");
         lcd_gotoxy(6, 4);                 
         lcd_putc("31/12/99 - SUN");
         dt = getParameter(dt, 31, 1, 6, 4);   
         lcd_gotoxy(9, 4);                 
         lcd_putc("12/99 -");
         mt = getParameter(mt, 12, 1, 9, 4);
         lcd_gotoxy(12, 4);                                 
         lcd_putc("99 -");                                 
         yr = getParameter(yr, 99, 0, 12, 4); 
         lcd_gotoxy(17, 4);             
         lcd_putc("SUN");                 
         dy = setDay(dy, 17, 4);
         delay_ms(dly_1);
         setTime(hr, min, s, am_pm, hr_format);                 
         setDate(dy, dt, mt, yr);
         delay_ms(100);
         lcd_putc("\f");     
}


unsigned char setDay(unsigned char dayValue, unsigned char x_pos, unsigned char y_pos)
{         
         unsigned char p = 0;
         for(;;)                           
         {                                   
                  p = getKbd();
                  showDay(dayValue, x_pos, y_pos); 
                  if((p >= 1) && (p <= 7))
                  {
                           dayValue = p;
                  }                                   
                  if(p == 0x0A)
                  {
                           return dayValue;
                  }
         }         
}
                                           

void showDay(unsigned char day_val, unsigned char x_pos, unsigned char y_pos)
{                                             
         lcd_gotoxy(x_pos, y_pos); 
         switch(day_val)
         {
                  case 1:                       
                  {
                           lcd_putc("SUN ");
                           break;
                  }
                  case 2:
                  {
                           lcd_putc("MON ");
                           break;
                  }
                  case 3:
                  {
                           lcd_putc("TUE ");
                           break;
                  }   
                  case 4:
                  {
                           lcd_putc("WED ");
                           break;
                  }
                  case 5:
                  {
                           lcd_putc("THR ");
                           break;
                  } 
                  case 6:
                  {
                           lcd_putc("FRI");
                           break;
                  }
                  case 7:
                  {
                           lcd_putc("SAT");
                           break;
                  }
         }
}   

                 
void showParameters()                                 
{
         lcd_gotoxy(6, 1);
         lcd_putc("DS3231 RTC");             
         lcd_gotoxy(1, 3);                               
         printf(lcd_putc, "Date: %02u/%02u/%02u ", dt, mt, yr);
         showDay(dy, 16, 3);
         lcd_gotoxy(1, 4);                                                       
         printf(lcd_putc, "Temp: %2.2g'C ", getTemp());         
         lcd_gotoxy(1, 2);
         switch(hr_format)
         {                                 
                  case 1:
                  { 
                           switch(am_pm)
                           {
                                    case 1:
                                    {
                                             printf(lcd_putc, "Time: %02u:%02u:%02u PM ", hr, min, s);   
                                             break;   
                                    }                                                                       
                                    default:
                                    {             
                                             printf(lcd_putc, "Time: %02u:%02u:%02u AM ", hr, min, s);   
                                             break;   
                                    }
                           }     
                           break;
                  }             
                  default:
                  {         
                           printf(lcd_putc, "Time: %02u:%02u:%02u     ", hr, min, s);   
                           break;                                 
                  }   
         }   
         delay_ms(600);         
}                                     

_________________
https://www.facebook.com/MicroArena

SShahryiar
shehwar



Joined: 29 May 2015
Posts: 7
Location: Lahore

View user's profile Send private message AIM Address

Just a simple question about this driver.
PostPosted: Fri May 29, 2015 7:33 am     Reply with quote

There are no i2c error checks whether slave responds with an ACK or not.
Aren't they necessary with this particular chip? and one more thing, datasheet for ds3231 (pg 11), 'statusReg' has a busy flag bit.
Shouldn't we check this flag before reading or writing to this chip?
sshahryiar



Joined: 05 May 2010
Posts: 94
Location: Dhaka, Bangladesh

View user's profile Send private message Send e-mail Visit poster's website

DS3231 RTC
PostPosted: Fri May 29, 2015 8:08 am     Reply with quote

Ported the same code for AVR without trouble.... Check this video out:

https://www.youtube.com/watch?v=VCnXEUmuZUo

Also check out the working of the example code given with this post:

https://www.facebook.com/MicroArena/photos/pb.113572212076237.-2207520000.1432908229./350564778376978/?type=3&theater
_________________
https://www.facebook.com/MicroArena

SShahryiar
shehwar



Joined: 29 May 2015
Posts: 7
Location: Lahore

View user's profile Send private message AIM Address

No doubts
PostPosted: Fri May 29, 2015 3:05 pm     Reply with quote

Bro, i have no doubts about your driver but i used it with my DS3231SN, it gave me 2 mins difference in time in just a day. Probably i would be doing something wrong, so im figuring out the solutions/workarounds. Can you tell me what i2c rate did u used? i used it with 400Kbps. Or can you suggest where problem can be?
newguy



Joined: 24 Jun 2004
Posts: 1909

View user's profile Send private message

PostPosted: Fri May 29, 2015 3:20 pm     Reply with quote

RTCs are only as accurate as the PCB they're mounted on is good.
shehwar



Joined: 29 May 2015
Posts: 7
Location: Lahore

View user's profile Send private message AIM Address

PCB Design
PostPosted: Fri May 29, 2015 3:27 pm     Reply with quote

As far as PCB is concerned, i have taken good care in designing with the consultation of datasheet. No signaling tracks are around the RTC and its close to i2c pins of 18f452. SCK and SCL pins are pull-up with 1K. Battery properly mounted and connections. Verified the hardware.
sshahryiar



Joined: 05 May 2010
Posts: 94
Location: Dhaka, Bangladesh

View user's profile Send private message Send e-mail Visit poster's website

RTC Issues
PostPosted: Fri May 29, 2015 6:39 pm     Reply with quote

Bro I used the default I2C data transfer rate of 20kHz.... @ Mr. Shehwar
_________________
https://www.facebook.com/MicroArena

SShahryiar
shehwar



Joined: 29 May 2015
Posts: 7
Location: Lahore

View user's profile Send private message AIM Address

Thank you for all the help.
PostPosted: Sun May 31, 2015 5:22 pm     Reply with quote

I'll try lowering the i2c transfer rate and post the results, may be this can help others aswell.
by the way, thanks.
shehwar



Joined: 29 May 2015
Posts: 7
Location: Lahore

View user's profile Send private message AIM Address

Thanks for everybody's help
PostPosted: Wed Jun 24, 2015 2:29 pm     Reply with quote

Driver runs perfectly with

"#use i2c(Master, SDA=pin_C4, SCL=pin_C3)"

i guess default i2c rate is working fine, raising the rates disturbs the internal operation of the IC.
sshahryiar



Joined: 05 May 2010
Posts: 94
Location: Dhaka, Bangladesh

View user's profile Send private message Send e-mail Visit poster's website

Welcome....
PostPosted: Wed Jun 24, 2015 9:01 pm     Reply with quote

Cool
_________________
https://www.facebook.com/MicroArena

SShahryiar
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group