Arduino Forum

Using Arduino => Networking, Protocols, and Devices => Topic started by: sbright33 on Aug 18, 2012, 04:45 am

Title: DS1307 RTC adjust drift automatically
Post by: sbright33 on Aug 18, 2012, 04:45 am
Didn't know which category to put this in.  I wrote some code to adjust the drift of my RTC.  You only have to set it once.  Mine drifted about 6 seconds per day.  That's not good enough for me.  Now it's less than 0.1 seconds.  This works especially when the clock is powered off.  Not sure how it works during extreme temperatures.  It's simple check it out.  It's only a few lines more than the original example.  You only need to change the first 3 constants, and calculate the 4th constant over time.  Any improvements?  Any ideas how I can adjust the day overflow?  The way it is now you can use since12 for logging.

Code: [Select]

#include "Wire.h"
#define DS1307_ADDRESS 0x68

const int setyearago=1;  //when was the RTC set?
const int setmonth=10;
const int setday=4;
const int spdx100=580;  // secs/day slow error measured over 11 months 580

int second,minute,hour,weekDay,monthDay,month,year;
int errsec,i,j;
long since12,since12wrong;

void ferrsec(){
long t=setyearago*365;
t+=(month-setmonth)*30;
t+=(monthDay-setday);
errsec=t*spdx100/100;
//Serial.println(errsec/60.0);
since12wrong=long(hour)*60*60+minute*60+second;
since12=since12wrong+errsec;
//since12%=(24*60*60); untested and wrong let it overflow
//return;  //skip adjusting
second+=errsec%60;
if(second>=60){
  minute++;
  second-=60;
  }
minute+=errsec/60;
while(minute>=60){
  hour++;  //could overflow past 23
  minute-=60;
  }
if(hour>=24){
  monthDay++;  //still not good enough could overflow monthDay
  hour-=24;
  }
}
void setup(){
  Wire.begin();
  Serial.begin(9600);
}
void loop(){
  printDate();
  delay(1000);
}
byte bcdToDec(byte val){
  return ( (val/16*10) + (val%16) );
}
void printDate(){
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.send(0);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_ADDRESS,7);
  second = bcdToDec(Wire.receive());
  minute = bcdToDec(Wire.receive());
  hour = bcdToDec(Wire.receive() & 0b111111); //24 hour time
  weekDay = bcdToDec(Wire.receive()); //0-6 -> sunday - Saturday
  monthDay = bcdToDec(Wire.receive());
  month = bcdToDec(Wire.receive());
  year = bcdToDec(Wire.receive());
  ferrsec();
  Serial.print(month);
  Serial.print("/");
  Serial.print(monthDay);
  Serial.print("/");
  Serial.print(year);
  Serial.print(" ");
  Serial.print(hour);
  Serial.print(":");
  Serial.print(minute);
  Serial.print(":");
  Serial.println(second);
}
Title: Re: DS1307 RTC adjust drift automatically
Post by: sbright33 on Aug 22, 2012, 01:42 am
Has anyone tried this?  I thought it would be useful for all DS1307 users.  Is there a problem with the code?  Improvements?
Title: Re: DS1307 RTC adjust drift automatically
Post by: BlueJakester on Aug 23, 2012, 04:47 am
OK, in this thread now, thanks. :)

I'd like to give this code a try. Can you give me more directions please?  

Say I set my ds1307 to the correct time right now. How would I set the first three params of your sketch before uploading? Like this maybe?

Thanks!

const int setyearago=0;  //when was the RTC set?
const int setmonth=8;
const int setday=22;
Title: Re: DS1307 RTC adjust drift automatically
Post by: sbright33 on Aug 24, 2012, 05:33 am
You got it.  The 4th constant is a little tricky.  You have to calculate it!  Using your old original sketches to read time, measure how far off it is from the PC time today, and again in 10 days.  Let's say it's 45 seconds slower than it was today.  Divide by the number of days (10), then multiply by 100.  The answer is 450.  That's what you put for spdx100.  That stands for Secs/day x 100 that it is slow.  -450 if it's faster after 10 days running.  Let me know!  The error seems consistent to me, so now there is much less error per day.
Title: Re: DS1307 RTC adjust drift automatically
Post by: Constantin on Aug 24, 2012, 05:54 am
Nice work.

I imagine the DS1307 drift is going to be quite dependent on temperature. But as long as the temperature is relatively constant, you should be good to go.

Some day I'll try to do something similar with an Arduino, a radio receiver for the US time signal and the Chronodot... and then create a auto-correct function for the aging trim in the DS3231.
Title: Re: DS1307 RTC adjust drift automatically
Post by: BlueJakester on Aug 24, 2012, 01:35 pm
Let me know!  The error seems consistent to me, so now there is much less error per day.

OK, I'll setup the clock and load the sketch this weekend. It will be at least 10 days plus a few more to monitor results before I post back to this thread with my results, but I will.

Thanks for writing and sharing this code!

Jake
Title: Re: DS1307 RTC adjust drift automatically
Post by: sbright33 on Aug 24, 2012, 03:48 pm
You could guess after 2 days.  I also wrote some code which is related to this.  It uses GPS to measure and calibrate millis() and the Arduino clock within hours, no need to wait 100 days.  So long as you keep it inside where the temperature is 60-80 degrees it is easy to obtain accuracy of 1ppm, which is about 1 seconds every 11 days.  Or even 10ppm with some effort which is 1 second every 100 days, or 3 seconds per year.  The only hardware you need for this code is GPS.  I also have code which uses Wifly to do the same thing with NIST server.

If you've got the time, I can help you keep it!
Title: Re: DS1307 RTC adjust drift automatically
Post by: BlueJakester on Aug 24, 2012, 03:51 pm
Sounds good. I need to put the ds1307 on a breadboard this weekend and set the time. I'll let you know how it goes.

Thanks!
Title: Re: DS1307 RTC adjust drift automatically
Post by: Constantin on Aug 24, 2012, 04:33 pm

...Or even 10ppm with some effort which is 1 second every 100 days, or 3 seconds per year....


Pardon my ignorance. I thought lower PPMs were better than higher PPMs re: clock drift. Why would an increase to 10PPM drift be preferable to 1PPM? Did you perhaps mean 0.1PPM or 100PPB?

I thought the whole point of adjusting the aging trim in the DS1307 or DS3201 was to minimize the clock drift.
Title: Re: DS1307 RTC adjust drift automatically
Post by: sbright33 on Aug 24, 2012, 08:31 pm
Of course my mistake 0.1ppm
Title: Re: DS1307 RTC adjust drift automatically
Post by: BlueJakester on Aug 27, 2012, 04:29 pm
sbright,

I have my cheap ds1307 setup. I'll be installing your code either tonight or tomorrow and will let you know how it works out.

Jake
Title: Re: DS1307 RTC adjust drift automatically
Post by: Constantin on Aug 27, 2012, 07:57 pm
Looks like I'll have to use a GPS receiver since sourcing the radio-based receivers appears difficult, plus I get the benefit of a GPS system, if I want it. The breakout board from adafruit appears enticing, it'll be interesting to see to what extent trimming the oscillator will work. What is the minimum time you think you need to trim with reasonable perfection? For something as accurate as the DS3231, I figured I'd need at least a month.
Title: Re: DS1307 RTC adjust drift automatically
Post by: sbright33 on Aug 27, 2012, 09:57 pm
Using PPS pin you can measure 1us drift each second.  So you get 1ppm in about...
1 second!

It makes more sense to wait 20 minutes and use 1ms drift method instead.

http://arduino.cc/forum/index.php/topic,120288
Title: Re: DS1307 RTC adjust drift automatically
Post by: BlueJakester on Aug 28, 2012, 03:44 am
Sbright,

I have your code installed and it appears to be working :D  I'll monitor it for a few days.

Thanks,
Jeff
Title: Re: DS1307 RTC adjust drift automatically
Post by: howardlim on Nov 11, 2012, 02:25 pm
Hi Guys,

I have modified the Time and DS1307RTC Libraries to do drift correction and store the drift info in the RTC battery backed memory. I've also included an Arduino sketch to do the RTC time setting and drift calibration. Take a look at the link below if you're interested.

Howard

http://limchonghan.wordpress.com/driftcorrectedds1307/ (http://limchonghan.wordpress.com/driftcorrectedds1307/)
Title: Re: DS1307 RTC adjust drift automatically
Post by: PriSim on Dec 25, 2016, 06:00 am
Code posted here about drifting of ds1307 is dead ! anybody have that code please share

http://limchonghan.wordpress.com/driftcorrectedds1307/
Title: Re: DS1307 RTC adjust drift automatically
Post by: gion86 on Dec 26, 2016, 05:52 pm
I saved it few years ago... and still have it  ;D

Here 
Project https://github.com/gion86/PlantLight (https://github.com/gion86/PlantLight)
Library https://github.com/gion86/DS1307_RTC (https://github.com/gion86/DS1307_RTC)
I made a little project with that code, slightly modified: it's working pretty well once you get the drift correction for you clock/oscillator...
Title: Re: DS1307 RTC adjust drift automatically
Post by: PriSim on Dec 31, 2016, 05:51 pm
@gion86

Thanks for sharing the code !

Can you please explain these 2 lines of code!

Code: [Select]

di.DriftDays = 1000;     // valid value 0 to 65,535
di.DriftSeconds = 2725;  // fine tune this until your RTC sync with your reference time, valid value -32,768 to 32,767


also how to calculate these values , if my clock is 6 sec/day fast.

Please explain any other code lines related to correction !
Title: Re: DS1307 RTC adjust drift automatically
Post by: gion86 on Jan 02, 2017, 07:18 pm
The variable DriftSeconds holds the "quantity" of second your clock is going to drift in DriftDays days. So if you clock is 6 sec/day fast you have to set:

Code: [Select]

di.DriftDays = 1;
di.DriftSeconds = 6;  


If you clock was slow by 6 it should be (signed):

Code: [Select]

di.DriftDays = 1;
di.DriftSeconds = -6;  


If you a have a not integer number of seconds you can multiply both variable by the same factor. So for example if you have 25.67 sec/day:

Code: [Select]

di.DriftDays = 100;
di.DriftSeconds = 2567;  


In the internal of the library those 2 variables will be divided by each other:

Code: [Select]
 
float driftCorrection = float(rtcTime - driftInfo.DriftStart);
driftCorrection /= float(SECS_PER_DAY * driftInfo.DriftDays);
driftCorrection *= float(driftInfo.DriftSeconds);


In driftCorrection you will have the floating point number of seconds per day of you drift, which is then used to calculate the current time:

Code: [Select]
 
// due to conversion of driftCorrection to long, accuracy of time returned is +/- 0.5sec
time_t curTime = rtcTime - long(driftCorrection);


I have to make clear that this is not my code, but I took it from the blog post above
http://limchonghan.wordpress.com/driftcorrectedds1307/ (http://limchonghan.wordpress.com/driftcorrectedds1307/). But I have tested and I'm using in a project so I can say that is working. ;)
Title: Re: DS1307 RTC adjust drift automatically
Post by: marthinius on Jul 28, 2020, 12:21 pm
I'm trying to run the above code, but unsuccessfully.

Code: [Select]


sketch_jul28a:34: error: 'tmDriftInfo' does not name a type

 tmDriftInfo di;


sketch_jul28a.ino: In function 'void setup()':

sketch_jul28a:48: error: 'di' was not declared in this scope

   di = RTC.read_DriftInfo();


sketch_jul28a:48: error: 'class DS1307RTC' has no member named 'read_DriftInfo'

   di = RTC.read_DriftInfo();

sketch_jul28a:51: error: 'class DS1307RTC' has no member named 'write_DriftInfo'

   RTC.write_DriftInfo(di); // once you're happy with the drift setting you only have to read the DriftInfo and pass it to now2() or now3() function to get your drift corrected time

sketch_jul28a.ino: In function 'void loop()':

sketch_jul28a:59: error: 'di' was not declared in this scope

   LcdDisplayDateTime(now3(di));

sketch_jul28a:59: error: 'now3' was not declared in this scope

   LcdDisplayDateTime(now3(di));

sketch_jul28a.ino: In function 'void processSerialCommand()':

sketch_jul28a:142: error: 'tmDriftInfo' was not declared in this scope

         tmDriftInfo diUpdate = RTC.read_DriftInfo();  // update DriftInfo in RTC

sketch_jul28a:143: error: 'diUpdate' was not declared in this scope

         diUpdate.DriftStart = newTime;

sketch_jul28a:144: error: 'class DS1307RTC' has no member named 'write_DriftInfo'

         RTC.write_DriftInfo(diUpdate);

sketch_jul28a:151: error: 'tmDriftInfo' was not declared in this scope

       tmDriftInfo diRead = RTC.read_DriftInfo();

sketch_jul28a:152: error: 'diRead' was not declared in this scope

       if (diRead.DriftStart == 0 | diRead.DriftDays == 0 | diRead.DriftSeconds == 0) {

sketch_jul28a:158: error: 'diRead' was not declared in this scope

       SerialDisplayDateTime(diRead.DriftStart); Serial.println();

exit status 1
'tmDriftInfo' does not name a type


Title: Re: DS1307 RTC adjust drift automatically
Post by: gion86 on Aug 03, 2020, 07:47 pm
You have to include the library in your project.
How are you compiling? With the Arduino IDE?
Title: Re: DS1307 RTC adjust drift automatically
Post by: Nick_Pyner on Aug 04, 2020, 03:52 am
I'm trying to run the above code, but unsuccessfully.
You will note that this thread is pretty old, and I suspect rather pointless even when it was current. Inaccuracies in the DS1307 were down to lack of temperature compensation as much as hardware drift. If your fix does not provide temperature compensation, you are probably on a futile venture, which may explain why the original code is hard to find. In the meantime the price of the DS3231 has come down to much the same as the DS1307, and doesn't need all this stuff. If you need to be serious about clock accuracy, you might look at that.
Title: Re: DS1307 RTC adjust drift automatically
Post by: gion86 on Aug 04, 2020, 06:50 pm
Yes Nick_Pyner is right.
Newer models offer a clock with temperature compensated oscillator and that makes the difference.
I have switched to a Maxim DS3232 clock, and used this library which is very usefull:

https://github.com/JChristensen/DS3232RTC (https://github.com/JChristensen/DS3232RTC)

Maybe we should close this thread...
Title: Re: DS1307 RTC adjust drift automatically
Post by: Nick_Pyner on Aug 05, 2020, 02:50 am
Most definitely. It was a dumb thread in 2012.

I might point out that, if you just want to tell the time, the 3231 will run with DS1307 code. No changes required. I don't use any library, but this probably applies with libraries as well.