manchester
Offline
Newbie
Karma: 0
Posts: 22
|
 |
« on: October 04, 2012, 05:30:02 am » |
Hi All,
I am having an Arduino Uno Rev.3 connected with an RTC DS1307 and an LCD 2x16. I am displaying the time and date using the RTC on the LCD. After a week I noticed that the time displayed in the LCD and the time in my PC have a difference of a few minutes. For example: PC time --> 11:04:17 and my RTC -->11:01:41 My RTC is not keeping the time as it should be but stays day by day a little behind from the "actual" time. Do you have any ideas on how I can synchronize my RTC with my PC system time?
Many Thanks!
|
|
|
|
|
Logged
|
|
|
|
|
Grand Blanc, MI, USA
Offline
Faraday Member
Karma: 47
Posts: 2575
"We're a proud service of the Lost Electricity Reclamation Agency"
|
 |
« Reply #1 on: October 04, 2012, 06:00:57 am » |
The Time library, http://www.arduino.cc/playground/Code/Time has a Processing sketch that runs on the PC for this purpose. Have not used it myself. I might search the forum a bit too, as this is a question that comes up occasionally and there are likely other solutions available. BTW, if your example is typical of your actual observations, i.e. a 156 second difference in a week's time, that is an unusually large error (258 ppm). I'd expect a DS1307 to be more accurate than that by a factor of ten or more. It might be worth posting your code. (I'm assuming the PC is being kept accurate via NTP, etc.) After a week I noticed that the time displayed in the LCD and the time in my PC have a difference of a few minutes. For example: PC time --> 11:04:17 and my RTC -->11:01:41
|
|
|
|
|
Logged
|
|
|
|
|
Norfolk UK
Offline
Edison Member
Karma: 25
Posts: 1422
|
 |
« Reply #2 on: October 04, 2012, 06:06:17 am » |
I have always found the DS1307 to be a poor keeper of time. The way I improved the timekeeping in a standalone project with no computer connection was to work out how much time the RTC loses per day and then at the midnight hour add to the current RTC time and save it. You could modify this to update hourly instead of daily. //Enumerations const int driftComp = 9; //Seconds to adjust clock by per day to compensate for RTC drift const int delayComp = 500; //Micro seconds to delay clock adjust by (driftComp * 1000) - delayCom = 8.5 seconds per 24 hours
void adjustClock(){ static boolean driftApplied = false;
RTC.readClock(); int h=RTC.getHours();
// RTC Drift compensation if(h == 0) //Is it the midnight hour { if(!driftApplied) { //Have I already done drift compensation int seconds = RTC.getSeconds(); //Get seconds seconds = seconds + driftComp; //Apply drift delay(delayComp); //Apply delay RTC.setSeconds(seconds % 60); //Put seconds RTC.setClock(); //Set clock driftApplied=true; //Signal drift applied } } else{ //Not midnight hour driftApplied = false; //Reset drift applied } }
|
|
|
|
|
Logged
|
|
|
|
|
manchester
Offline
Newbie
Karma: 0
Posts: 22
|
 |
« Reply #3 on: October 04, 2012, 06:27:27 am » |
Thank you Jack and Riva for your answers. Riva because I am quite new to the Arduino. How can I use your code? What I am asking is how can I use void adjustClock() function on my program? My code is a very simple code and i state it below: // Date and time functions using a DS1307 RTC connected via I2C and Wire lib #include <LiquidCrystal.h> #include <Wire.h> #include "RTClib.h" RTC_DS1307 RTC; LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2); void setup () { lcd.begin(16, 2); lcd.clear(); Serial.begin(57600); Wire.begin(); RTC.begin(); if (! RTC.isrunning()) { Serial.println("RTC is NOT running!"); // following line sets the RTC to the date & time this sketch was compiled //RTC.adjust(DateTime(__DATE__, __TIME__)); } } void loop () { DateTime now = RTC.now(); lcd.clear(); // Clear the LCD screen lcd.print("Time: "); if (now.hour() < 10) lcd.print("0"); // Check if we need to add leading zero lcd.print(now.hour(), DEC); // Output current hour lcd.print(":"); if (now.minute() < 10) lcd.print("0"); // Check if we need to add leading zero lcd.print(now.minute(), DEC); // Output current minute lcd.print(":"); if (now.second() < 10) lcd.print("0"); // Check if we need to add leading zero lcd.print(now.second(), DEC); lcd.setCursor(0, 1); lcd.print("Date: "); if (now.day() < 10) lcd.print("0"); // Check if we need to add leading zero lcd.print(now.day(), DEC); // Output current hour lcd.print(":"); if (now.month() < 10) lcd.print("0"); // Check if we need to add leading zero lcd.print(now.month(), DEC); // Output current minute lcd.print(":"); if (now.year() < 10) lcd.print("0"); // Check if we need to add leading zero lcd.print(now.year(), DEC); Serial.println(); delay(1000); lcd.clear(); }
Thank you!!!
|
|
|
|
|
Logged
|
|
|
|
|
Grand Blanc, MI, USA
Offline
Faraday Member
Karma: 47
Posts: 2575
"We're a proud service of the Lost Electricity Reclamation Agency"
|
 |
« Reply #4 on: October 04, 2012, 06:44:02 am » |
Well the code does seem pretty straightforward. DS1307 accuracy is governed by the crystal's accuracy, circuit layout, and temperature. Many crystals used with DS1307s have specs of ±20 or ±30 ppm. My expectation would be for the circuit to operate reasonably close to that. While I don't consider 20-30 ppm to be great accuracy, practically, it's probably OK for many applications, but represents a minimum standard IMHO.
|
|
|
|
|
Logged
|
|
|
|
|
Norfolk UK
Offline
Edison Member
Karma: 25
Posts: 1422
|
 |
« Reply #5 on: October 04, 2012, 06:52:23 am » |
I use a different RTC library to you but I think I have altered your program to suit. You will need to work out the correct driftComp & delayComp values to suit your DS1307. The values you give indicate a 22.286 second loss per day so once every 24 hours (assuming your clock is 24 hour mode) I add 23 seconds and then wait 714 milliseconds = 22.286 and then set the clock. As you have such a large variation you could maybe alter the code to adjust the clock every hour instead. // Date and time functions using a DS1307 RTC connected via I2C and Wire lib #include <LiquidCrystal.h> #include <Wire.h> #include "RTClib.h"
const int driftComp = 23; //Seconds to adjust clock by per day to compensate for RTC drift const int delayComp = 714; //Milliseconds to delay clock adjust by (driftComp * 1000) - delayCom = 8.5 seconds per 24 hours
RTC_DS1307 RTC; LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
void setup () { lcd.begin(16, 2); lcd.clear(); Serial.begin(57600); Wire.begin(); RTC.begin(); if (! RTC.isrunning()) { Serial.println("RTC is NOT running!"); // following line sets the RTC to the date & time this sketch was compiled //RTC.adjust(DateTime(__DATE__, __TIME__)); } }
void loop () { static boolean driftApplied = false; DateTime now = RTC.now(); // RTC Drift compensation if(now.hour == 0) { //Is it the midnight hour if(!driftApplied) { //Have I already done drift compensation int seconds = now.second(); //Get seconds seconds = seconds + driftComp; //Apply drift delay(delayComp); //Subtract delay now.Seconds(second % 60); //Put seconds RTC.adjust(now); //Set clock driftApplied=true; //Signal drift applied } } else{ //Not midnight hour driftApplied = false; //Reset drift applied } lcd.clear(); // Clear the LCD screen lcd.print("Time: "); if (now.hour() < 10) lcd.print("0"); // Check if we need to add leading zero lcd.print(now.hour(), DEC); // Output current hour lcd.print(":"); if (now.minute() < 10) lcd.print("0"); // Check if we need to add leading zero lcd.print(now.minute(), DEC); // Output current minute lcd.print(":"); if (now.second() < 10) lcd.print("0"); // Check if we need to add leading zero lcd.print(now.second(), DEC); lcd.setCursor(0, 1); lcd.print("Date: "); if (now.day() < 10) lcd.print("0"); // Check if we need to add leading zero lcd.print(now.day(), DEC); // Output current hour lcd.print(":"); if (now.month() < 10) lcd.print("0"); // Check if we need to add leading zero lcd.print(now.month(), DEC); // Output current minute lcd.print(":"); if (now.year() < 10) lcd.print("0"); // Check if we need to add leading zero lcd.print(now.year(), DEC); delay(1000); }
|
|
|
|
|
Logged
|
|
|
|
|
Leeds, England
Offline
Full Member
Karma: 6
Posts: 210
Quick, chuck it in the bin before the boss finds out...
|
 |
« Reply #6 on: October 04, 2012, 06:54:41 am » |
In the code that sets the time you will notice __DATE__ and __TIME__. Are you using these to set the time? If so then these are known as preprocessor directives. What happens (in brief) is that the first thing that happens when you start to compile and download your sketch is that these two items are replaced by the current date and time according to your pc. The problem is that then the sketch is compiled and squirted down to the processor, all of which takes time. Hence the RTC ends up several seconds behind the pc.
To get round this you can specify the time you want to set the RTC to:
RTC.adjust(DateTime(__DATE__, "13:00:00"));
If you remove the test to check if the RTC is running and upload the sketch then as soon as you run the Serial Monitor it will set the time to that specified. So using the example above, about thirty seconds before one o'clock I would upload the sketch and then, a couple of seconds before time, start up the Serial Monitor. Don't run the Serial Monitor again otherwise you will reset the time again!
With a little trial and error you should be able to time it just right!
However, setting it right won't stop the time from drifting over a week due to the factors outlined by Jack. If accuracy is important you might wish to consider a DS3232 based module.
|
|
|
|
|
Logged
|
|
|
|
|
Saskatchewan
Offline
Full Member
Karma: 10
Posts: 230
When the going gets weird, the weird turn pro. - Hunter S. Thompson
|
 |
« Reply #7 on: October 04, 2012, 08:33:24 am » |
I have a 1307 in my project and it runs for days and days between getting checked out by me. I only display the time accurate to a minute but it matches my PC whenever I check. I used part of a sample sketch that sets the time by sending Unix time to it via serial. I've only set it the once when I got a battery for it, probably a good month ago. Did I get lucky? 
|
|
|
|
|
Logged
|
|
|
|
|
manchester
Offline
Newbie
Karma: 0
Posts: 22
|
 |
« Reply #8 on: October 04, 2012, 09:55:37 am » |
Thank you all for your help and ideas! Regarding Riva: Thank you for modifying the code. Unfortunately when I am verifying the code I am having an error on line if(now.hour == 0) { //Is it the midnight hour . I changed it to if(now.hour() == 0) { //Is it the midnight hour and now it gives me an error on now.seconds(second % 60); //Put seconds . The error I get is the following: sketch_oct04c.cpp: In function 'void loop()': sketch_oct04c:38: error: 'class DateTime' has no member named 'seconds' sketch_oct04c:38: error: 'second' was not declared in this scope
I have stuck with this error. My code now is : // Date and time functions using a DS1307 RTC connected via I2C and Wire lib #include <LiquidCrystal.h> #include <Wire.h> #include "RTClib.h"
const int driftComp = 23; //Seconds to adjust clock by per day to compensate for RTC drift const int delayComp = 714; //Milliseconds to delay clock adjust by (driftComp * 1000) - delayCom = 8.5 seconds per 24 hours
RTC_DS1307 RTC; LiquidCrystal lcd(8, 7, 5, 4, 3, 2);
void setup () { lcd.begin(16, 2); lcd.clear(); Serial.begin(57600); Wire.begin(); RTC.begin(); if (! RTC.isrunning()) { Serial.println("RTC is NOT running!"); // following line sets the RTC to the date & time this sketch was compiled //RTC.adjust(DateTime(__DATE__, __TIME__)); } }
void loop () { static boolean driftApplied = false; DateTime now = RTC.now(); // RTC Drift compensation if(now.hour() == 0) { //Is it the midnight hour if(!driftApplied) { //Have I already done drift compensation int seconds = now.second(); //Get seconds seconds = seconds + driftComp; //Apply drift delay(delayComp); //Subtract delay now.seconds(second % 60); //Put seconds RTC.adjust(now); //Set clock driftApplied=true; //Signal drift applied } } else{ //Not midnight hour driftApplied = false; //Reset drift applied } lcd.clear(); // Clear the LCD screen lcd.print("Time: "); if (now.hour() < 10) lcd.print("0"); // Check if we need to add leading zero lcd.print(now.hour(), DEC); // Output current hour lcd.print(":"); if (now.minute() < 10) lcd.print("0"); // Check if we need to add leading zero lcd.print(now.minute(), DEC); // Output current minute lcd.print(":"); if (now.second() < 10) lcd.print("0"); // Check if we need to add leading zero lcd.print(now.second(), DEC); lcd.setCursor(0, 1); lcd.print("Date: "); if (now.day() < 10) lcd.print("0"); // Check if we need to add leading zero lcd.print(now.day(), DEC); // Output current hour lcd.print(":"); if (now.month() < 10) lcd.print("0"); // Check if we need to add leading zero lcd.print(now.month(), DEC); // Output current minute lcd.print(":"); if (now.year() < 10) lcd.print("0"); // Check if we need to add leading zero lcd.print(now.year(), DEC); delay(1000); } I have also changed LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2); to LiquidCrystal lcd(8, 7, 5, 4, 3, 2); Regarding Jimmy60: Your way of dealing with the DS1307 sounds very interesting. Could you please sent me your code to have a look? Many Thanks to all of you!
|
|
|
|
|
Logged
|
|
|
|
|
Seattle, WA USA
Offline
Brattain Member
Karma: 336
Posts: 36476
Seattle, WA USA
|
 |
« Reply #9 on: October 04, 2012, 10:03:44 am » |
int seconds = now.second(); //Get seconds seconds = seconds + driftComp; //Apply drift delay(delayComp); //Subtract delay now.seconds(second % 60); //Put seconds
The now.second() call with no argument returns the current value. The same method, with a value, sets the value. The compiler is right, just so you know.
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Tesla Member
Karma: 76
Posts: 6852
Arduino rocks
|
 |
« Reply #10 on: October 04, 2012, 10:17:02 am » |
One possible issue is that _watch_ 32768Hz crystals are designed for the average temperature of a wristwatch (close to body heat for 2/3 of the time). You might find it keeps better time if kept at 30C rather than room temp.
Also crystals are cut for a specific load-capacitance - if the crystal is not designed for the oscillator it will run somewhat out of spec.
|
|
|
|
« Last Edit: October 04, 2012, 10:18:35 am by MarkT »
|
Logged
|
|
|
|
|
Saskatchewan
Offline
Full Member
Karma: 10
Posts: 230
When the going gets weird, the weird turn pro. - Hunter S. Thompson
|
 |
« Reply #11 on: October 04, 2012, 10:38:43 am » |
I'm using the Time.h library I found here: http://www.arduino.cc/playground/Code/timeThe included sample, TimeRTCSet, has the method I used to set it. As far as ambient air temps go my Arduino has spent most of it's running time around 20C or lower. The last week has been closer to 15C. It's in an unheated shop. Time.h includes a DS1307RTC.h, I notice you aren't using Time.h
|
|
|
|
|
Logged
|
|
|
|
|
Norfolk UK
Offline
Edison Member
Karma: 25
Posts: 1422
|
 |
« Reply #12 on: October 04, 2012, 11:14:57 am » |
now.seconds(second % 60); //Put seconds . The error I get is the following: sketch_oct04c.cpp: In function 'void loop()': sketch_oct04c:38: error: 'class DateTime' has no member named 'seconds' sketch_oct04c:38: error: 'second' was not declared in this scope
I have stuck with this error. From the error message try this line instead. now.second(seconds % 60);
|
|
|
|
|
Logged
|
|
|
|
|
Left Coast, CA (USA)
Offline
Brattain Member
Karma: 283
Posts: 15443
Measurement changes behavior
|
 |
« Reply #13 on: October 04, 2012, 12:30:46 pm » |
I have a 1307 in my project and it runs for days and days between getting checked out by me. I only display the time accurate to a minute but it matches my PC whenever I check. I used part of a sample sketch that sets the time by sending Unix time to it via serial. I've only set it the once when I got a battery for it, probably a good month ago. Did I get lucky?  Yes. Accuracy of a 1307 RTC or any RTC for that matter, is based on the accuracy of the crystal and how well it's matched electrically to the chip. Even your PC internal RTC will drift some amount over time and needs to be reset either manually or via some on-line updating method. Some 1307 designs have a small trimmer cap wired to one of the crystal pins and ground to allow a tweeking control to try and get better long term accuracy but even with that temperature changes will effect long term accuracy.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Sr. Member
Karma: 7
Posts: 421
|
 |
« Reply #14 on: October 04, 2012, 01:30:11 pm » |
This story seems appropriate here. The contractor was the dad of someone I used to work with...
A contractor working on a nuclear sub noticed that the ships chronometer was a few minutes off. He set it to WWV, and didn't think any more about it. A few days later he noted that it was off by a few minutes again, this was way out of spec, so he started to get concerned. He set again and kept checking it. A few hours later, the CPO came in, glanced at his wristwatch and reset the chronometer by it.
|
|
|
|
|
Logged
|
|
|
|
|
|