RTC running fast

Anyone have any experience with a DS1307 running a little fast? I set the clock then a week later it is about 20 seconds fast, the next week it will be about 40 seconds fast. Any idea how to slow it down a bit?

#include <TimeLib.h>
#include <Wire.h>

#define DS1307_I2C_ADDRESS 0x68

byte decToBcd(byte val)
  {
    return((val/10*16) + (val%10)); 
  }
byte bcdToDec(byte val)
  {
    return((val/16*10) + (val%16));
  }

void setup() //runs once
{
  Wire.begin();             
  Serial.begin(9600);        
  //setDS1307time(00,37,20,4,25,01,17); //set DS1307 Time&Date: seconds, minutes, hours, day, date, month, year; comment out after setting and re-upload

void setDS1307time(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year)  
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0);
  Wire.write(decToBcd(second));
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));
  Wire.write(decToBcd(dayOfWeek));
  Wire.write(decToBcd(dayOfMonth));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.endTransmission();
}

void readDS1307time(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year)
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0); 
  Wire.endTransmission(); 
  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);  //requesting 7 bytes from DS1307 beginning at register 00h
  *second = bcdToDec(Wire. read() & 0x7f);
  *minute = bcdToDec(Wire. read());
  *hour = bcdToDec(Wire. read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire. read());
  *dayOfMonth = bcdToDec(Wire. read());
  *month = bcdToDec(Wire. read());
  *year = bcdToDec(Wire. read());
}

void displayTime()
{
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  readDS1307time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
  lcd.setCursor(0, 0);  
  lcd.print(month, DEC);
  lcd.print("/");
  lcd.print(dayOfMonth, DEC);
  lcd.print("/");
  lcd.print(year, DEC);
  lcd.print(" ");
  lcd.print(hour, DEC);
  lcd.print(":");
  if(minute < 10)
    {
      lcd.print("0");
    }
  lcd.print(minute, DEC);
  lcd.print(":");
  if(second < 10)
    {
      lcd.print("0");
    }
  lcd.print(second, DEC);
  lcd.print(" ");
  switch(dayOfWeek)
    {
      case 1:
        lcd.print("Su ");
        break;
      case 2:
        lcd.print("Mo ");
        break;
      case 3:
        lcd.print("Tu ");
        break;
      case 4:
        lcd.print("We ");
        break;
      case 5:
        lcd.print("Th ");
        break;
      case 6:
        lcd.print("Fr ");
        break;
      case 7:
        lcd.print("Sa ");
        break;
    }

void loop()
{
   displayTime();
}

Thanks for any advice.

dcrash36:
Anyone have any experience with a DS1307 running a little fast? I set the clock then a week later it is about 20 seconds fast, the next week it will be about 40 seconds fast. Any idea how to slow it down a bit?

Thanks for any advice.

moving it away from the Earth's gravitational field would slow it down (according to Einstein).

also, if you search this forum you may see others' observations and comparisons of accuracy to other RTC's like the DS3231.

It sounds pretty normal. The DS1307 has crude or non-existent temperature compensation. It can be pretty good in a nice steady environment and, for a lot of work, that sort of accuracy is not a problem anyway.

The DS3231 is a lot better and only costs about $1-50 more. Beware that the standard module is also a lot bigger, don't ask why, and I found it a lot harder to accommodate.

If you change to a DS3231, there is no need to change the code.

BulldogLowell:
moving it away from the Earth's gravitational field would slow it down (according to Einstein).

Pretty sure it's the other way around.

Time moves slower in a gravitational field, meaning that light travelling out of a gravitational well gets red-shifted. Consequently, a photon that moves out of a gravitational well will lose energy. In one of those "no free lunch" moves that Mother Nature loves so much, the amount of energy lost is exactly equal to the amount of energy that you would otherwise gain by lifting the mass equivalent of that photon out of the well.

Oh - the OP. What everyone else said: you get what you pay for. Making an accurate clock is actually really, really difficult. 40 seconds over a week is one part in 15 thousand. Pretty good, all things considered.

dcrash36:
Anyone have any experience with a DS1307 running a little fast? I set the clock then a week later it is about 20 seconds fast, the next week it will be about 40 seconds fast. Any idea how to slow it down a bit?

Yes.
The "stupid" (but possibly effective) way to do this would be to have code that runs daily at, say 4 A.M. or so. Something like:

// This is "pseudocode", not real code.
// You will have to rewrite it to make it actually run.

if ((hour==4) && (minute==1) && (second==0)) { // run daily at exactly 4:01 A.M.
  delay(3900); // wait 3.9 seconds (that's 2.9 seconds plus 1 second extra)
  setTime(1, 1, 4, ....) // set time to 4:01:01 A.M. (notice the extra second)
  // The extra second in the previous two lines is there for a reason.
  // Otherwise, the time would be set back to exactly 4:01 A.M. (with 0 seconds),
  // which could trigger the time set again, and so on, infinitely, and we don't want that.
}

Just to let you guys know and to help others I thought I'd share my code based on the above suggestions to fix the DS1307 drifting issue. It's a very effective, quick and easy way to fix the problem. By no means a stupid suggestion as it works. Yeah you could just replace the DS1307 with a DS3231 but why spend money when you don't have to?

I built a digital alarm clock based on this Digital Clock by Southern Storm Software which is a great alarm clock with multiple alarms and other user configurable options.

Anyway, with that out of the way I found the module drifted by 7 seconds a day. Fiddling with the crystal, using an external PSU, decoupling capacitors all made no difference. So I saw this topic and added the below code.

     // Start RTC drift compensation

  if (time.hour == 9 && time.minute == 1 && time.second == 0) { // run daily at exactly 9:01 A.M.
  delay(8000); // wait 8.0 seconds (that's 6.0 secs drift plus 1 second then reset seconds to 9:01:01 see below)
  RTCTime newValue;
  newValue.hour = 9;
  newValue.minute = 1;
  newValue.second = 1;
  setTime.setValue(newValue);
  
  // Time drift is approx 7 seconds gain per 24 hours. The extra one second is to prevent the program from being stuck
  // in an endless loop. Formula is time drift <in seconds> + 1 second leeway + set time to 1 min, 1 second past the hour.
  // This will result in the clock being put back 7 seconds at 9:01:01 every morning. Adjust formula accordingly.
  // DS3231 crystal is temperature sensitive so during the summer the gain will slow down. Colder temps = faster speeds.
  // Often cheap Chinese modules use watch crystals which are calibrated at blood temperature not room temperature. 
  // The above code is not perfect but will help to compensate for this problem.
   
} 
    // end RTC drift compensation

I placed this in the main loop after the bit that updates the time based on the RTC's 1Hz signal.

Hope this helps someone.

adrian-smith31:
Yeah you could just replace the DS1307 with a DS3231 but why spend money when you don't have to?

yes, why spend good money after bad?

All your time spent working on adjusting something that ought not have that problem vs the $2.50 I guess. What about when the temperature is different and your crystal needs a different calibration?

I guess the moral of the story is to do your research first.

 if (time.hour == 9 && time.minute == 1 && time.second == 0) { // run daily at exactly 9:01 A.M.
  delay(8000); // wait 8.0 seconds (that's 6.0 secs drift plus 1 second then reset seconds to 9:01:01 see below)
  RTCTime newValue;
  newValue.hour = 9;
  newValue.minute = 1;
  newValue.second = 1;
  setTime.setValue(newValue);

odd choice of time of day to make that adjustment

the FrankenClock in the link is pretty homely, can you show a photo of yours?

Sure here is the attached photo. I used a ready made case off ebay as my attempts at making my own casing looks far from good. Mind this example is far from perfect; I ordered a black case but was sent a white case, then the wrong one... That's ebay for you.

There's an Arduino nano and RTC module mounted to stripboard cut to around the same size as a full size arduino board in there plus the button PCB and LCD. As for the time of day I just went with the original poster's idea but it's probably best done in the middle of the night. I'm usually at work at 9am do it does not matter to me what time of day the correction is done.

I should have done my research first, yeah. I'm done with the DS1307 and will use the 3231 or 3232 in future projects. I couldn't be bothered to swap out the module in my clock so I went with the easy solution. Depending on how it goes that decision may change. At the moment the gain / loss seems to be balancing itself out.

adrian-smith31:
Sure here is the attached photo.

Nice!

I've used homemade foil capacitors to slow down a desk clock. I sandwich some copper foil with tape, solder in parallel with the crystal, and then trim it with scissors a bit at a time to reach the right frequency. I have one of those that I bought for $2 that is now accurate to about 10 seconds a month.

Thanks aarg, that’s what I was looking for!

Well, as this topic has been replied to I thought I'd update on this. With the code modifications the clock has been running since my post in May 2017 and it is only 12 seconds fast. I haven't made any adjustments in that time at all. So if a DS1307's gain can be worked out to the exact second a quick and dirty fix to correct the gain would be code modification.

I've been using the DS3231 since (in other projects) and even they drift by a couple of seconds per month or so. However these are far more preferable than the DS1307 and I've been able to buy them on ebay for only a few UK pounds.