Pages: [1] 2 3 4   Go Down
Author Topic: Keeping accurate time  (Read 17255 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am using the following code to display a digital clock using my arduino uno:

#include <Time.h> 
#include <LiquidCrystal.h>

#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by Unix time_t as ten ASCII digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message
#define TIME_REQUEST  7    // ASCII bell character requests a time sync message

// T1262347200  //noon Jan 1 2010
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int clockSet = 0;

void setup() 
{
  Serial.begin(9600);
  lcd.begin(16, 2);
 }

void loop()
{   
  if(clockSet == 0)
  {
    if(Serial.available() )
    {
      processSyncMessage();
      clockSet = 1;
    }
  }
  digitalClockDisplay(); 
  delay(1000);
}

void digitalClockDisplay()
{
  lcd.setCursor(1,0);
  lcd.print(hour());
  lcdPrintDigits(minute());
  lcdPrintDigits(second());
}

void lcdPrintDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  lcd.print(":");
  if(digits < 10)
    lcd.print('0');
  lcd.print(digits);
}
void processSyncMessage() {
  // if time sync available from serial port, update time and return true
  while(Serial.available() >=  TIME_MSG_LEN ){  // time message consists of header & 10 ASCII digits
    char c = Serial.read() ;
    Serial.print(c); 
    if( c == TIME_HEADER ) {       
      time_t pctime = 0;
      for(int i=0; i < TIME_MSG_LEN -1; i++){   
        c = Serial.read();         
        if( c >= '0' && c <= '9'){   
          pctime = (10 * pctime) + (c - '0') ; // convert digits to a number   
        }
      }   
      setTime(pctime);   // Sync Arduino clock to the time received on the serial port
    } 
  }
}


Most of this is out of the example code for the time.h library. The problem is the clock loses about 2 minutes each day (i.e. it is 2 minutes slower than my computer clock). Any ideas on why this might be? I have cut down the code as much as I can such that it only calls processSyncMessage once (the first time I send the time to the arduino). I thought maybe executing processSyncMessage every time through the loop was slowing it down but that doesn't seem to be the case. Maybe I should change the delay to delayMicroseconds()?

Thanks.
Logged

0
Offline Offline
Faraday Member
**
Karma: 16
Posts: 2857
ruggedcircuits.com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

It could be your LCD printing code is just taking about 1ms or so. Then, your delay() function is not 1000ms from the last delay, it's 1000ms from the the last delay plus LCD time.

Try just using millis() directly instead of delay(). Something like (warning...untested code):

Code:
uint32_t lastTime;

void loop(void)
{
  if ((millis() - lastTime) >= 1000) {
    lastTime += 1000;
    digitalClockDisplay();
  }
  ......
}

--
The Gadget Shield: accelerometer, RGB LED, IR transmit/receive, speaker, microphone, light sensor, potentiometer, pushbuttons
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


A better accuracy can be obtained by using a RealTimeClock like the DS1307.

Further you can speed up the connection with the PC by using a higher baudrate Serial.begin(115200); that way it takes less time.





Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the great suggestions. I would like the arduino to run standalone (i.e. not connected to any computer), otherwise I would definitely use the RealTimeClock. I will try the idea of checking the time it takes to write to the display. I was kind of thinking in that direction.
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
standalone
Is the Arduino connected to the internet (ethernetshield) ?
If yes you can use the NTP to sync time
If not you may use a DCF77 signal (or similar) to get accurate time 

- http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1232018156
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 201
Posts: 8706
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Without an external precision clock your Arduino time measurement will only be as accurate as the processor clock.  Perhaps a high-precision 16MHz crystal instead of the standard one would help.

It looks like 10ppm (parts per million) is the best you can get off the shelf.  That's a little better than a second a day accuracy.  You can get such crystals for under $1.  Search Google Shopping for "16 MHz crystal 10ppm".
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

0
Offline Offline
Faraday Member
**
Karma: 23
Posts: 3470
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

A 10ppm crystall will not give 10ppm accurarcy unless ALL other parameters will fit. Especially the load caps may get it much further out of tune than you would expect. Careless board layout and unstable power conditions will not improve things.
HIt is possible (but not easy) to compensate for frequency offset as well as temperature. However it is very much easier to use a DS3231 (e.g. a Chrono Dot) or to go for a time normal like DCF77 or GPS though.
In case of extraordinary precision requirements have a look at used Trimble Thunderbold Modules at Ebay.
Logged

Check out my experiments http://blog.blinkenlight.net

0
Offline Offline
Shannon Member
****
Karma: 200
Posts: 11718
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The Uno, unlike the Duemilanove, doesn't use a crystal to clock the microcontroller - you can't rely on millis()/micros() being better than 0.1% accurate or whatever performance ceramic resonators have...  This is very unfortunate.  It is possible to replace the resonator since the board has pads for a standard crystal and load capacitors but you'll need a steady hand and a solder-sucker to clear the thru-holes.

A quick experiment on my Uno showed the resonator frequency being pulled 0.05% (500ppm) just by putting a finger on it.  Only 4.5ppm on the Duemilanove's crystal/caps.
Logged

[ I won't respond to messages, use the forum please ]

0
Offline Offline
Shannon Member
****
Karma: 200
Posts: 11718
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In fact I got motivated enough to replace the resonator on my Uno board, partly to see how tricky it was to do.

Here's the board before modding it:


Then I desoldered the resonator and the unnecesary resistor:


Had some 22pF SM caps (0805 size, about the smallest I like to solder smiley


And the crystal - there seemed to be insufficient clearance for the standard 49U package from the caps (they weren't tiny enough!) but I wanted it clear of the bare resonator pads anyway to avoid shorts so its sticking up a little from the board:


Finally at some point I will add a blob of glue from a hot-glue gun to support it better mechanically.  Overall not too fiddly if you have tackled SM components before.  A solder sucker is required to clear the thru-holes for the crystal leads, the tiny resonator and resistor can be heated on alternate sides till it moves and can be pushed off the pads.  Only attempt at your own risk of course smiley-wink
Logged

[ I won't respond to messages, use the forum please ]

Netherlands
Offline Offline
God Member
*****
Karma: 7
Posts: 642
A naughty mind is a joy forever.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

One thing I found out correcting the errors of my 1307, was to keep an eye on my PC's clock.
Standard it's synchronized once a week and it took me a while to notice it was less accurate as my arduino-clock.

Synchronizing it too often per hour with time.windows.com can result in temporary denial of services by the way  smiley-kiss



« Last Edit: March 08, 2011, 07:03:24 am by Simpson_Jr » Logged

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 124
Posts: 6652
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
1) The microcontroller crystal (or ceramic resonator) IS NOT capable of serving as a real-time clock. It was simply never made for that purpose. You will fight with it the rest of your life if you try to do that.
Nonsense.  A crystal oscillator is a crystal oscillator.  Unless you specifically use a higher-precision crystal, carefully match your capacitances, and provide some sort of temperatures compensation, a DS1307 "RTC" chip is not going to be any more accurate than a crystal connected directly to the microcontroller.  (and you COULD use similar care in implementing the microcontroller crystal oscillator.)  (not to say that the RTC chip doesn't have other features.)
(now, there ARE other "RTC modules" that specifically DO attack the accuracy problem, by using fancier RTC chips, or ovens to keep the critical circuitry at a specific temperature, or other mechanisms.   One example is the "ChronoDot": http://macetech.com/store/index.php?main_page=product_info&cPath=5&products_id=8 )

The OP hasn't said how accurate he actually needs, and I don't think we've confirmed or eliminated software bugs as the cause of the original inaccuracies.  You should be able to get better than 5000ppm (0.5%) even with a ceramic resonator, and 100ppm or better with the microcontroller clock controlled by a crystal and millis() (or with a DS1307 based RTC module and different code.)  The "Chronodot" is supposed to be good for about 2.5ppm over a moderate temperature range (and someone has already done the hard parts!)[/color]
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Well this has generated quite a discussion. Thanks to all for your input. The upshot of all this appears to be that using the arduino as a standalone clock is not practical due to the issues described here. I won't pursue that further and will take the advice of getting an RTC module. That seems to be the most expedient path. I'm not terribly concerned about microsecond accuracy over great lengths of time. I just want it to keep time as well as the digital clock on my nightstand. That shouldn't be too difficult I should think. I was just surprised at how inaccurate the arduino's microcontroller clock is. But at least I understand why now.
Logged

Offline Offline
Edison Member
*
Karma: 3
Posts: 1001
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The upshot of all this appears to be that using the arduino as a standalone clock is not practical due to the issues described here. I won't pursue that further and will take the advice of getting an RTC module.
I would add that for a USB connected Arduino, syncing to the PC clock is as good as anything you can buy in terms of RTC. You may have to sync frequently (say every hour or so) to maintain exact time, but this is not much different from reading time off a RTC module at regular intervals.

The two minute delay you observed is mainly due to the software issue pointed out by retrolefty above (the logic is incorrect). Change the program logic in line with his advice and you should be good for a day or so between updates.
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 201
Posts: 8706
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm not terribly concerned about microsecond accuracy over great lengths of time. I just want it to keep time as well as the digital clock on my nightstand.

If your Arduino is powered by an AC outlet (like your clock radio) another source of accurate time is the 60Hz AC power grid.  The long-term accuracy of the 60Hz power is very good.  Possibly even atomic clock good.  I've seen examples somewhere on how to get a nice interrupt from an AC transformer.   Just count the cycles, seconds, minutes, hours, and days.  Put in rules for Daylight Savings Time and you'll never need to set the clock unless you lose AC for a long time.
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 93
Posts: 3968
CODE is a mass noun and should not be used in the plural or with an indefinite article.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I have several DS1307 RTCs, and they work well, but aren't what I would call super accurate.  They can gain or lose a couple seconds per day.  The DS3231 is much better, check out the "Chronodot" breakout board at Adafruit, or Sparkfun has a "dead on" RTC using the DS3234, which accuracy-wise, is the same as the DS3231, but it has an SPI interface rather than an I2C interface.  From a software standpoint, I've found the DS1307 and DS3231 to be interchangeable, i.e. DS1307 software libraries work fine with the DS3231.
Logged

MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

Pages: [1] 2 3 4   Go Up
Jump to: