|
|
View previous topic :: View next topic |
Author |
Message |
sshahryiar
Joined: 05 May 2010 Posts: 94 Location: Dhaka, Bangladesh
|
DS3231 High Precision I2C RTC Driver |
Posted: Wed Apr 10, 2013 10:28 pm |
|
|
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
|
|
Posted: Sat Jan 31, 2015 5:22 am |
|
|
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
|
Example Code |
Posted: Sat Jan 31, 2015 7:00 am |
|
|
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
|
Just a simple question about this driver. |
Posted: Fri May 29, 2015 7:33 am |
|
|
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
|
|
|
shehwar
Joined: 29 May 2015 Posts: 7 Location: Lahore
|
No doubts |
Posted: Fri May 29, 2015 3:05 pm |
|
|
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: 1908
|
|
Posted: Fri May 29, 2015 3:20 pm |
|
|
RTCs are only as accurate as the PCB they're mounted on is good. |
|
|
shehwar
Joined: 29 May 2015 Posts: 7 Location: Lahore
|
PCB Design |
Posted: Fri May 29, 2015 3:27 pm |
|
|
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
|
RTC Issues |
Posted: Fri May 29, 2015 6:39 pm |
|
|
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
|
Thank you for all the help. |
Posted: Sun May 31, 2015 5:22 pm |
|
|
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
|
Thanks for everybody's help |
Posted: Wed Jun 24, 2015 2:29 pm |
|
|
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
|
|
|
|
|
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
|