Arduino Forum

Topics => Science and Measurement => Topic started by: kdecker on Mar 07, 2011, 05:22 pm

Title: Keeping accurate time
Post by: kdecker on Mar 07, 2011, 05:22 pm
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.
Title: Re: Keeping accurate time
Post by: RuggedCircuits on Mar 07, 2011, 05:29 pm
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: [Select]

uint32_t lastTime;

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


--
The Gadget Shield (http://ruggedcircuits.com/html/gadget_shield.html): accelerometer, RGB LED, IR transmit/receive, speaker, microphone, light sensor, potentiometer, pushbuttons
Title: Re: Keeping accurate time
Post by: robtillaart on Mar 07, 2011, 06:56 pm

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.





Title: Re: Keeping accurate time
Post by: kdecker on Mar 07, 2011, 08:44 pm
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.
Title: Re: Keeping accurate time
Post by: robtillaart on Mar 07, 2011, 09:39 pm
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
Title: Re: Keeping accurate time
Post by: johnwasser on Mar 07, 2011, 10:59 pm
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".
Title: Re: Keeping accurate time
Post by: udoklein on Mar 07, 2011, 11:58 pm
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.
Title: Re: Keeping accurate time
Post by: MarkT on Mar 08, 2011, 12:37 am
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.
Title: Re: Keeping accurate time
Post by: MarkT on Mar 08, 2011, 02:00 am
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:
(http://www.chaos.org.uk/~markt/fine-pix/2011-03/2011-03-08-crystalize-Uno/before.jpg)

Then I desoldered the resonator and the unnecesary resistor:
(http://www.chaos.org.uk/~markt/fine-pix/2011-03/2011-03-08-crystalize-Uno/desoldered.jpg)

Had some 22pF SM caps (0805 size, about the smallest I like to solder :)
(http://www.chaos.org.uk/~markt/fine-pix/2011-03/2011-03-08-crystalize-Uno/caps.jpg)

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:
(http://www.chaos.org.uk/~markt/fine-pix/2011-03/2011-03-08-crystalize-Uno/new-crystal.jpg)

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 ;)
Title: Re: Keeping accurate time
Post by: Simpson_Jr on Mar 08, 2011, 12:55 pm
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  :*



Title: Re: Keeping accurate time
Post by: westfw on Mar 09, 2011, 08:54 am
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]
Title: Re: Keeping accurate time
Post by: kdecker on Mar 09, 2011, 07:40 pm
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.
Title: Re: Keeping accurate time
Post by: borref on Mar 09, 2011, 08:58 pm

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.
Title: Re: Keeping accurate time
Post by: johnwasser on Mar 10, 2011, 12:27 pm

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.
Title: Re: Keeping accurate time
Post by: JChristensen on Mar 17, 2011, 10:58 pm
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.
Title: Re: Keeping accurate time
Post by: WillR on Mar 18, 2011, 03:40 pm
Easiest way is the external clock.

Check here:
http://arduino.cc/forum/index.php/topic,51802.0.html

I reworked the time and DS1307 libraries to add some functions which should help. Using the internet or your PC as a time reference is the best solution -- not the cheapest. The only other solution is a radio chip for WWV/CHU or equivalent.
Title: Re: Keeping accurate time
Post by: kdecker on Apr 08, 2011, 12:04 am
Well here's the latest. I purchased the Sparkfun DS3234 breakout board to keep accurate time. I have it wired as follows:

Pin 13 to CLK on the RTC
Pin 12 to MISO
Pin 11 to MOSI
pin 8 to SS.

Using the example code below, I tried MODE1 and MODE3 and both result in the following being displayed in the Serial output display:

45/25/165 18:85:85

or

0/0/0 0:0:0

The example code is from the Sparkfun web site for the RTC. Any ideas?

Thanks.
--------------------------

#include <SPI.h>
const int  cs=8; //chip select

void setup() {
  Serial.begin(9600);
  RTC_init();
  //day(1-31), month(1-12), year(0-99), hour(0-23), minute(0-59), second(0-59)
  SetTimeDate(11,12,13,14,15,16);
}

void loop() {
  Serial.println(ReadTimeDate());
  delay(1000);
}
//=====================================
int RTC_init(){
     pinMode(cs,OUTPUT); // chip select
     // start the SPI library:
     SPI.begin();
     SPI.setBitOrder(MSBFIRST);
     SPI.setDataMode(SPI_MODE1); // both mode 1 & 3 should work
     //set control register
     digitalWrite(cs, LOW); 
     SPI.transfer(0x8E);
     SPI.transfer(0x60); //60= disable Osciallator and Battery SQ wave @1hz, temp compensation, Alarms disabled
     digitalWrite(cs, HIGH);
     delay(10);
}
//=====================================
int SetTimeDate(int d, int mo, int y, int h, int mi, int s){
   int TimeDate [7]={s,mi,h,0,d,mo,y};
   for(int i=0; i<=6;i++){
      if(i==3)
         i++;
      int b= TimeDate/10;
      int a= TimeDate-b*10;
      if(i==2){
         if (b==2)
            b=B00000010;
         else if (b==1)
            b=B00000001;
      }   
      TimeDate= a+(b<<4);
       
      digitalWrite(cs, LOW);
      SPI.transfer(i+0x80);
      SPI.transfer(TimeDate);       
      digitalWrite(cs, HIGH);
  }
}
//=====================================
String ReadTimeDate(){
   String temp;
   int TimeDate [7]; //second,minute,hour,null,day,month,year      
   for(int i=0; i<=6;i++){
      if(i==3)
         i++;
      digitalWrite(cs, LOW);
      SPI.transfer(i+0x00);
      unsigned int n = SPI.transfer(0x00);       
      digitalWrite(cs, HIGH);
      int a=n & B00001111;   
      if(i==2){   
         int b=(n & B00110000)>>4; //24 hour mode
         if(b==B00000010)
            b=20;       
         else if(b==B00000001)
            b=10;
         TimeDate=a+b;
      }
      else if(i==4){
         int b=(n & B00110000)>>4;
         TimeDate=a+b*10;
      }
      else if(i==5){
         int b=(n & B00010000)>>4;
         TimeDate=a+b*10;
      }
      else if(i==6){
         int b=(n & B11110000)>>4;
         TimeDate=a+b*10;
      }
      else{   
         int b=(n & B01110000)>>4;
         TimeDate=a+b*10;   
         }
   }
   temp.concat(TimeDate[4]);
   temp.concat("/") ;
   temp.concat(TimeDate[5]);
   temp.concat("/") ;
   temp.concat(TimeDate[6]);
   temp.concat("     ") ;
   temp.concat(TimeDate[2]);
   temp.concat(":") ;
   temp.concat(TimeDate[1]);
   temp.concat(":") ;
   temp.concat(TimeDate[0]);
  return(temp);
}
Title: Re: Keeping accurate time
Post by: johnwasser on Apr 08, 2011, 02:36 am
You have to mark code as code (put 'code' in square brackets before it and '/code' in square brackets after it) otherwise all the square brackets get stripped.

Look like you got your date and time register addresses reversed:

00 = Seconds
01 = Minutes
02 = Hours
03 = Day of the week
04 = Day
05 = Month
06 = Year


Well here's the latest. I purchased the Sparkfun DS3234 breakout board to keep accurate time. I have it wired as follows:

Pin 13 to CLK on the RTC
Pin 12 to MISO
Pin 11 to MOSI
pin 8 to SS.

Using the example code below, I tried MODE1 and MODE3 and both result in the following being displayed in the Serial output display:

45/25/165 18:85:85

or

0/0/0 0:0:0

The example code is from the Sparkfun web site for the RTC. Any ideas?

Thanks.
--------------------------
Code: [Select]

#include <SPI.h>
const int  cs=8; //chip select

void setup() {
  Serial.begin(9600);
  RTC_init();
  //day(1-31), month(1-12), year(0-99), hour(0-23), minute(0-59), second(0-59)
  SetTimeDate(11,12,13,14,15,16);
}

void loop() {
  Serial.println(ReadTimeDate());
  delay(1000);
}
//=====================================
int RTC_init(){
  pinMode(cs,OUTPUT); // chip select
  // start the SPI library:
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE1); // both mode 1 & 3 should work
  //set control register
  digitalWrite(cs, LOW); 
  SPI.transfer(0x8E);
  SPI.transfer(0x60); //60= disable Osciallator and Battery SQ wave @1hz, temp compensation, Alarms disabled
  digitalWrite(cs, HIGH);
  delay(10);
}
//=====================================
int SetTimeDate(int d, int mo, int y, int h, int mi, int s){
int TimeDate [7]={s,mi,h,0,d,mo,y};
for(int i=0; i<=6;i++){
if(i==3)
i++;
int b= TimeDate[i]/10;
int a= TimeDate[i]-b*10;
if(i==2){
if (b==2)
b=B00000010;
else if (b==1)
b=B00000001;
}
TimeDate[i]= a+(b<<4);
 
digitalWrite(cs, LOW);
SPI.transfer(i+0x80);
SPI.transfer(TimeDate[i]);       
digitalWrite(cs, HIGH);
  }
}
//=====================================
String ReadTimeDate(){
String temp;
int TimeDate [7]; //second,minute,hour,null,day,month,year
for(int i=0; i<=6;i++){
if(i==3)
i++;
digitalWrite(cs, LOW);
SPI.transfer(i+0x00);
unsigned int n = SPI.transfer(0x00);       
digitalWrite(cs, HIGH);
int a=n & B00001111;   
if(i==2){
int b=(n & B00110000)>>4; //24 hour mode
if(b==B00000010)
b=20;       
else if(b==B00000001)
b=10;
TimeDate[i]=a+b;
}
else if(i==4){
int b=(n & B00110000)>>4;
TimeDate[i]=a+b*10;
}
else if(i==5){
int b=(n & B00010000)>>4;
TimeDate[i]=a+b*10;
}
else if(i==6){
int b=(n & B11110000)>>4;
TimeDate[i]=a+b*10;
}
else{
int b=(n & B01110000)>>4;
TimeDate[i]=a+b*10;
}
}
temp.concat(TimeDate[4]);
temp.concat("/") ;
temp.concat(TimeDate[5]);
temp.concat("/") ;
temp.concat(TimeDate[6]);
temp.concat("     ") ;
temp.concat(TimeDate[2]);
temp.concat(":") ;
temp.concat(TimeDate[1]);
temp.concat(":") ;
temp.concat(TimeDate[0]);
  return(temp);
}
[/code
[/quote]
Title: Re: Keeping accurate time
Post by: kdecker on Apr 08, 2011, 04:02 pm
Oh thanks John. Didn't know I could do that with the code snippet. I'll do that next time and thanks for the response on the registers. I'll take a look at that.

Title: Re: Keeping accurate time
Post by: johnwasser on Apr 08, 2011, 04:28 pm

Oh thanks John. Didn't know I could do that with the code snippet. I'll do that next time and thanks for the response on the registers. I'll take a look at that.


My mistake.  I didn't notice that you re-ordered the values between the function arguments and the array.

I have read in various places that when you use the SPI library you are supposed to set the hardware Slave Select line (D10) to an output.  It sounds like a strange requirement but couldn't hurt to try.  Just put it in setup().
Title: Re: Keeping accurate time
Post by: retrolefty on Apr 08, 2011, 04:38 pm
Quote
I have read in various places that when you use the SPI library you are supposed to set the hardware Slave Select line (D10) to an output.  It sounds like a strange requirement but couldn't hurt to try.  Just put it in setup().


Actually the other way around. If pin 10 (SS) is set to be an input then the SPI hardware will setup to be as a SPI slave device. Defining it (SS pin 10) as a output is required for the master device so that it's SPI hardware will setup to be a master. This is true even if the master is using other pin(s) as slave select outputs, pin 10 must be setup as an output pin in the master device even if it's not being used by the master. The slave must only use it's pin 10 as the slave select line.

Lefty

Title: Re: Keeping accurate time
Post by: kdecker on Apr 08, 2011, 08:01 pm
I changed SS to pin 10 and changed the code accordingly as:
Code: [Select]

const int  cs=10; //chip select
.
.
.
int RTC_init(){
 pinMode(cs,OUTPUT); // chip select
.
.
.

Same result. Still only returns zeros.
Title: Re: Keeping accurate time
Post by: retrolefty on Apr 08, 2011, 08:22 pm

I changed SS to pin 10 and changed the code accordingly as:
Code: [Select]

const int  cs=10; //chip select
.
.
.
int RTC_init(){
 pinMode(cs,OUTPUT); // chip select
.
.
.

Same result. Still only returns zeros.


The pinMode should probably happen before the call to RTC_init as that then initilizes the SPI which looks at pinmode for pin 10 to decide to be master or slave.

Lefty

Title: Re: Keeping accurate time
Post by: kdecker on Apr 08, 2011, 09:29 pm
The pinMode() statement is the first thing that happens in the init so that should make sure it is set before the rest of the SPI initialization. Here's the whole thing as it looks right now. My apologies for not understanding all the detail around this code. It's the sample code from the Sparkfun web site for the RTC. I've left a request for info on that site as well. Thanks everyone for all your help.

Code: [Select]
#include <SPI.h>
const int  cs=10; //chip select

void setup() {
  Serial.begin(9600);
 
  RTC_init();
  //day(1-31), month(1-12), year(0-99), hour(0-23), minute(0-59), second(0-59)
  SetTimeDate(05,04,11,18,21,16);
}

void loop() {
  Serial.println(ReadTimeDate());
  delay(1000);
}
//=====================================
int RTC_init(){
          pinMode(cs,OUTPUT); // chip select
          // start the SPI library:
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE3); // both mode 1 & 3 should work
  //set control register
  digitalWrite(cs, LOW); 
          SPI.transfer(0x8E);
  SPI.transfer(0x60); //60= disable Osciallator and Battery SQ wave @1hz, temp compensation, Alarms disabled
  digitalWrite(cs, HIGH);
  delay(10);
}
//=====================================
int SetTimeDate(int d, int mo, int y, int h, int mi, int s){
int TimeDate [7]={s,mi,h,0,d,mo,y};
for(int i=0; i<=6;i++){
if(i==3)
i++;
int b= TimeDate[i]/10;
int a= TimeDate[i]-b*10;
if(i==2){
if (b==2)
b=B00000010;
else if (b==1)
b=B00000001;
}
TimeDate[i]= a+(b<<4);
 
digitalWrite(cs, LOW);
SPI.transfer(i+0x80);
SPI.transfer(TimeDate[i]);
digitalWrite(cs, HIGH);
  }
}
//=====================================
String ReadTimeDate(){
String temp;
int TimeDate [7]; //second,minute,hour,null,day,month,year
for(int i=0; i<=6;i++){
if(i==3)
i++;
      digitalWrite(cs, LOW);
                SPI.transfer(i+0x00);
unsigned int n = SPI.transfer(0x00);       
digitalWrite(cs, HIGH);
int a=n & B00001111;   
if(i==2){
int b=(n & B00110000)>>4; //24 hour mode
if(b==B00000010)
b=20;       
else if(b==B00000001)
b=10;
TimeDate[i]=a+b;
}
else if(i==4){
int b=(n & B00110000)>>4;
TimeDate[i]=a+b*10;
}
else if(i==5){
int b=(n & B00010000)>>4;
TimeDate[i]=a+b*10;
}
else if(i==6){
int b=(n & B11110000)>>4;
TimeDate[i]=a+b*10;
}
else{
int b=(n & B01110000)>>4;
TimeDate[i]=a+b*10;
}
}
temp.concat(TimeDate[4]);
temp.concat("/") ;
temp.concat(TimeDate[5]);
temp.concat("/") ;
temp.concat(TimeDate[6]);
temp.concat("     ") ;
temp.concat(TimeDate[2]);
temp.concat(":") ;
temp.concat(TimeDate[1]);
temp.concat(":") ;
temp.concat(TimeDate[0]);
  return(temp);
}
Title: Re: Keeping accurate time
Post by: johnwasser on Apr 09, 2011, 01:57 am
Try the slowest clock speed:  SPI.setClockDivider(SPI_CLOCK_DIV128);

If that helps you can reduce the divider to see how fast you can go before it fails.  :)
Title: Re: Keeping accurate time
Post by: kdecker on Apr 09, 2011, 05:22 pm
No joy. I put SPI.setClockDivider(SPI_CLOCK_DIV128); in the init routine but it didn't change anything. I'm starting to wonder if the RTC itself is defective.
Title: Re: Keeping accurate time
Post by: kdecker on Apr 25, 2011, 08:16 pm
Finally determined that the RTC was bad. Got a new one, wired it up, and it is working fine.
Title: Re: Keeping accurate time
Post by: wbphelps on May 17, 2011, 01:18 am

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


By any chance to you have a part # for the crystal?

Thanks,
William
Title: Re: Keeping accurate time
Post by: dcb on Jun 10, 2011, 05:47 am
sorry to hear the uno went ceramic.

Yah, unless you have a software glitch, the basic processor can keep perfect time with the crystal, the same way the rtc module keeps time with ITS OWN crystal.    As long as the period is consistent, you can make any necessary adjustments to convert to wall time.  If it is off by a fixed amount, that is trivial to fix in software (in fact I think the timer library already has an adjustment for it http://www.arduino.cc/playground/Code/Time )

I cannot think of any application where I would bother with an rtc instead of putting the crystal directly on the cpu and calibrating/validating it to real time.   There might be one but it has never been on my todo.

here is a 10ppm 16mhz crystal http://www.mouser.com/ProductDetail/TXC-Corporation/9C-16000MEEJ-T/?qs=sGAEpiMZZMsBj6bBr9Q9aWUu9Vmt5DeoFlToalzCQFw%3d , if you want more precision.  I've only messed with the 50ppm fox crystals.

Title: Re: Keeping accurate time
Post by: robtillaart on Jun 10, 2011, 08:14 am
5) to generate logfiles that need to be processed later ...
Title: Re: Keeping accurate time
Post by: borref on Jun 10, 2011, 08:35 am

1) Keeping accurate date/time without main power supply.
2) The Arduino is NOT a "real-time" system. There are things you can program that could keep the internal millis() or micros() from keeping accurate time.
3) You want to run something for more than 50 days (for millis) or 70 minutes (for micros)
4) You want to actually know what time and/or date it is in the real world.

If we maintain a count of seconds, we can easily keep track of time for more than 100 years irrespective of millis/micros overflow. Tracking real-time is also no show stopper as it is just a matter of setting initial time as will be required for a RTC as well. Real-time accuracy is a property of the oscillator and not unique to RTC. It is also possible to operate a timer (timer2 on AtMega328) independent of the main clock from a separate external crystal.

The main benefit of using a RTC chip as I see it is low power battery operation. A dime-size coin cell battery will keep a DS1307 ticking for 10 years. You can even use the RTC without a crystal as a low cost I2C NVRAM chip to preserve accumulators/state/preferences across microcontroller power cycles or add the crystal to get both time keeping and data retention.
Title: Re: Keeping accurate time
Post by: westfw on Jun 10, 2011, 09:14 am
The better RTC chips have built-in temperature compensation, making them more accurate than a normal (microprocessor) crystal oscillator.
Title: Re: Keeping accurate time
Post by: dcb on Jun 10, 2011, 02:21 pm
Yes but the point is that an rtc is essentially a processor too.  Insisting that a cpu cannot keep accurate time is 100% false/incorrect, it is merely a function of the quality of the oscillator, and there are processing strategies that can assist too if it is really important (i.e. read a thermistor).  

And it is far simpler to read a variable from memory and format it, than to figure out how to communicate with a time processor, i.e. DS1306 (and format the results).

They work the same way, oh look, a crystal is also needed for the rtc (duh):
(http://static.flickr.com/143/322692077_a13d387a58.jpg)

Responses 1-5 are a matter of implementation.  I could see a couple situations why a developer might like an RTC if they are plugging and unplugging things a lot, and reprogramming the cpu, but for a clock with set buttons on it (and most clocks reset on unplugging anyway, so this is feature creep), no need.


EDIT:  The frustrating thing though is the abundance of ceramic resonators.  Arduino was crystal driven when I got involved, and the ceramic resonators and onboard oscillator designs really murdered the idea of onboard timekeeping for the masses, and everybody and their brother wants to build a clock.  So buy an arduino with a crystal if you care about having a semblance of accuracy, or mod it like MarkT, thumbs up there!  http://arduino.cc/forum/index.php/topic,54621.msg391290.html#msg391290 , but if you have a crystal, and are building a clock, the time library was meant just for you, no extra hardware required.

re: uno, they put a crystal on the bleeding com chip, but not the main chip?!?  Sorry guys, but wtf?  You could have even shared the com chip crystal with the main chip if you just wanted to save a few cents:
http://www.youtube.com/watch?v=eDu_SrhP5-M

Title: Re: Keeping accurate time
Post by: dcb on Jun 10, 2011, 06:45 pm
...OTOH, the main Arduino controller chip was never intended for precision timekeeping


You joined last february, you are talking out your ass, "never intended", stfu.  The main chip is at the heart of may a precision timepiece.
Title: Re: Keeping accurate time
Post by: dcb on Jun 10, 2011, 06:51 pm
people who make up bullcrap statements will be called on it, it isn't personal.  Please try to stick to facts and not dabble in fantasy.
Title: Re: Keeping accurate time
Post by: dcb on Jun 10, 2011, 07:02 pm
more bullcrap from a newbie who claims to know what the original intent of the atmega was in regards to timekeeping.  I cannot help that you are full of crap, that is your problem, deal with it.
Title: Re: Keeping accurate time
Post by: dcb on Jun 10, 2011, 07:55 pm
your post count and registration date must have gotten hosed then (speaking of bad timekeeping).  Still it is microcontrollers and logic what make possible small and accurate clocks that can make adjustments, combined with decent oscillators.  But to be in the ballpark you do not need to pimp rtc modules. Use the library, tell vendors to not cut corners on oscillators so you can have a decent timepiece in your arduino by itself.
Title: Re: Keeping accurate time
Post by: MarkT on Jun 12, 2011, 04:38 am


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


By any chance to you have a part # for the crystal?

Thanks,
William


Just a standard 16MHz crystal I think - there are different suppliers and different grades but most are 50ppm or better.
Title: Re: Keeping accurate time
Post by: udoklein on Jul 01, 2011, 04:07 pm
You have to have proper load capacitance otherwise you may be off >100ppm. The datasheets contain the formula for proper matching of crystal load capacitance and the caps.
Title: Re: Keeping accurate time
Post by: gerg on Jul 13, 2011, 04:35 pm
I saw this got pretty heated but I'm chiming in anyways. The original question was about making a clock. The simple fact is, the common resonator absolutely stinks for any reliable time reference over time. Furthermore, a simple MCU with a resonator makes for horrible accuracy. The drift alone is typically extremely noteworthy. And that completely ignores that the MCU only knows a relative time since last power up and not an absolute time reference.

This is why RTCs are so popular. Not only do they tend to have an absolute time reference, they tend to also be reasonably accurate (moreso than a simple resonator), take care of details like days, weeks, months, and especially leap years, and have extremely low power requirements to maintain time without external power. Even better, even cheap RTCs tend to have some form of modest calibration when installed according to their datasheet and more expensive units are both calibrated and actively compensated.

Frankly, creating anything other than the most simpletons of clocks without an RTC is highly questionable, unless its the trip than matters moreso than the destination.

I also read others talking about slamming time corrections from an external source. Be warned this also has some potential issues. If your application is dependent on alarms, relative time, and especially delays, its a great way to either miss them (if using poorly written software), potentially create alarm cascades (if using properly written software), or completely screw up fixed delays. Frequently, SNTP is what people incorrectly refer to when they mention NTP. There is a difference. A good implementation of time management which accommodates for drift will do so via tick interpolation over a finite period of time as well as rejection and error when skew is too large; typically based on accuracy requirements. So for example, if we have 100 ticks of error, it should be slowly interpolated over something like five seconds, minimizing the imposed error over those five seconds. Otherwise, simply slamming in 100 ticks over a 1 tick duration, may cause a cascade of alarms to fire, not to mention completely throw off all relative time measurements by 100 ticks (sleeping for 200 ticks just woke up 100 ticks short). And on real time systems, an alarm cascade can really screw things up royally.

Long story short, any clock should seriously consider even a modest RTC; especially when CPU clocking is a resonator. They have lots of advantages, especially where simple resonators are in use. I have created systems which managed clock skew and distributed time references (SNTP & NTP) for P25 digital radio systems (http://en.wikipedia.org/wiki/P25). If you want to point at my low post count, I'll happily laugh in your face. Bluntly, proper time management is a surprisingly deep and complex subject with lots of subtleties waiting to whack the unprepared. Be extremely wary of anyone who attempts to trivialize time management, especially when their sole reference is a resonator. That's not to say CPU counters are without merit, but they can be deceptively alluring for the ignorant.
Title: Re: Keeping accurate time
Post by: mem on Jul 13, 2011, 05:34 pm
Quote
creating anything other than the most simpletons of clocks without an RTC is highly questionable, unless its the trip than matters more than the destination.


I agree with that, but point out that a high proportion of the Arduino projects one sees are more about the trip rather than the destination.

At Maker Faire I saw an LED clock that displayed time in base 12 on a charlieplexed 9 by 14 LED grid. However accurate or not that clock may be, the maker was more interested in the fun of getting it to work then using it to tell accurate time.
Title: Re: Keeping accurate time
Post by: robtillaart on Jul 13, 2011, 06:30 pm
@gerg]
Thanks for this wisdom, you are right that SNTP and NTP are used mixed. I do too - I'm guilty :) -

(S)NTP is most used for synchronizing RTC's (or a software datetime lib) in Arduinoland. All RTC (but one)  I know can be set up to 1 second precision, so in practice NTP and SNTP have "too much" precision for them. It would be nice if the millis() or micros() could be set according to the decimal part but unfortunately this is not possible on an Arduino AFAIK. OK one can create NTPmillis() and NTPmicros() that uses an offset or a hardware timer or ...  So in Arduinoland the decimal part of (S)NTP is mostly dropped, and yes sometimes it is used for rounding to which second is nearest. IN fact 99% of the Arduino sketches would just need the Time protocol (RFC868).

The Arduino has little resources and I assume that adjusting gradually for the drift for an Arduino is possible but it would take quite a bit of the resources leaving little room for the main sketch. (please let someone prove me wrong by building an Arduino NTP server library :)

The one second precision of the RTC mentioned before also means - from observing the apps discussed at the forum - that the RTC is seldom (never?) used for high precision timing, in Arduino context most people use millis() and micros() for this. The time of the RTC is mostly used for display and logging, and yes also for low precision timing like switching on/off the light of an aquarium or so. I see two different kind of clocks working side by side each for their specific purpose. And I think it is not bad.



Title: Re: Keeping accurate time
Post by: gerg on Jul 13, 2011, 07:10 pm
Please keep in mind I was speaking in generalities. I was purposely trying not to be overly specific. Some of my comments need not necessarily apply to the typical Arduino user. An example of this is one thread slamming in a new time while another thread is sleeping. Concurrency is not likely a typical Arduino user's concern. Though is possible if done via an ISR.


(S)NTP is most used for synchronizing RTC's (or a software datetime lib) in Arduinoland. All RTC (but one)  I know can be set up to 1 second precision, so in practice NTP and SNTP have "too much" precision for them. It would be nice if the millis() or micros() could be set according to the decimal part but unfortunately this is not possible on an Arduino AFAIK. OK one can create NTPmillis() and NTPmicros() that uses an offset or a hardware timer or ...  So in Arduinoland the decimal part of (S)NTP is mostly dropped, and yes sometimes it is used for rounding to which second is nearest. IN fact 99% of the Arduino sketches would just need the Time protocol (RFC868).

The Arduino has little resources and I assume that adjusting gradually for the drift for an Arduino is possible but it would take quite a bit of the resources leaving little room for the main sketch. (please let someone prove me wrong by building an Arduino NTP server library :)

The one second precision of the RTC mentioned before also means - from observing the apps discussed at the forum - that the RTC is seldom (never?) used for high precision timing, in Arduino context most people use millis() and micros() for this. The time of the RTC is mostly used for display and logging, and yes also for low precision timing like switching on/off the light of an aquarium or so. I see two different kind of clocks working side by side each for their specific purpose. And I think it is not bad.


I agree. Let's not lose track of the fact accuracy and precision is always relative to the purpose and requirements. For most people, accuracy to within a minute per year is acceptable for a wall clock. Whereas, accuracy to +- >2 minutes per week is pretty iffy. Still, for an electronics experiment its likely not a problem at all. For a clock beside the bed, its likely okay for the unemployed or soon to be, by the end of the year.  :smiley-eek-blue:

Generally RTCs are a reference source of some type. This may include a square wave generator or simply periodic fetching of absolute time whereby interpolation is then used to synchronize CPU timers. As (IIRC) dbc said, there really isn't anything special about RTCs. He's right you can do it on common, non-specialized hardware if your tolerances allow and you use a clocking source which provides the required precision, and then take the time to calibrate and compensate with temp and so on. But then again, RTCs are so cheap, reliable, persistent with low power requirements, frequently with wake on interrupt (frequently allowing for additional power savings), typically fairly accurate, sometimes even highly precise, and all too often completely mitigate a whole slew of subtle software time management bugs, they become really hard to overlook - especially when no other external absolute time reference is readily available (time, sntp, ntp, etc). Whooo! That's a mouthful.

IMOHO, part of the confusion here people are conflating time with timers. Relative timers are easily possible without absolute time. Absolute timers require absolute time. Time, SNTP, NTP, and RTCs are all common sources for obtaining an absolute time reference. So the question becomes, assuming the easy path, do you require absolute time or relative timers; or both. IMOHO, if you require absolute time, your solution needs to include one or more of Time, SNTP, NTP, or an RTC. Again, you're requirements will guide, if not dictate.

Like with most engineering tasks, this is no different. Define your requirements. Understand the problem domain. Craft a solution. My primary purpose for chiming is is that many people don't define their requirements and frequently when they do, time is such a simple construct we all know, so its frequently falsely understood the domain is mastered. As such, crafting a faulty solution is all too easy.

As I've pointed out in another thread, time is subtly hard to get right. As long as you don't underestimate its complexities and truly define your requirements, you'll likely be okay. Otherwise, expect a bumpy road and lessons learned.

Title: Re: Keeping accurate time
Post by: retrolefty on Jul 13, 2011, 08:29 pm
Quote
As I've pointed out in another thread, time is subtly hard to get right. As long as you don't underestimate its complexities and truly define your requirements, you'll likely be okay. Otherwise, expect a bumpy road and lessons learned.


I agree. "Accuracy" is a term that is vastly undefined and relies on too many unstated assumptions to be useful in most conversations. Unless you are in marketing where there is much to gained by riding on those unstated assumptions.  ;)


Lefty


Title: Re: Keeping accurate time
Post by: robtillaart on Jul 14, 2011, 12:15 am
Quote
time is subtly hard to get right

Yeah definitely hard, I did some research upon the NTP protocol and the work of Mills years ago. To my suprise (then) the NTP uses statistics to handle latencies of the network and the server. For me that looked like "the first signs of some variant of the Heisenberg principle"  ;)

I recall that Mills started to investigate NTP for intersolar communication (one time ref per solar system, NASA) to synchronize satellite data. Depending on the relative speed of things he needed to compensate for relativistic effects.

Definitely hard.
Title: Re: Keeping accurate time
Post by: dcb on Mar 25, 2012, 03:59 pm
...
Frankly, creating anything other than the most simpletons of clocks without an RTC is highly questionable, unless its the trip than matters moreso than the destination...


Frankly, building a development board with an irregular heartbeat (resonator) to save a dime is highly questionable to me.
Title: Re: Keeping accurate time
Post by: udoklein on Mar 25, 2012, 07:40 pm
A crystal will be usually ~10 ppm of the mark. So dedicated RTCs are still much better. A resonator will startup faster.

If you insist on precision timing without giving any details on how much accuracy you really need run your Arduino from an external clock and use a PLL to sync it with something like a Trimble Thunderbolt (can be bought for cheap from *bay). If this will not give enought precision then you have an issue ;)
Title: Re: Keeping accurate time
Post by: Constantin on Mar 30, 2012, 04:14 pm
I have had great luck / happiness with the DS3231. Great chip, well-documented, easy to interface with, and even a couple of libraries to choose from. In the end though I wrote my own reading / bit-shifting routines since some of the libraries I dealt with didn't do that part perfectly for all the variables that the DS3231 supports. No big deal, there are plenty of examples out there that pointed me in the right direction.

Equally fun was writing a routine that turned these values into a float that reflected the microsoft way of tracking time in Excel.
Title: Re: Keeping accurate time
Post by: pito on Mar 31, 2012, 04:48 pm
@Constantin: they claim +/-2ppm/year and 5ppm aging - can you confirm that somehow?? Thnks.
Title: Re: Keeping accurate time
Post by: Constantin on Mar 31, 2012, 11:30 pm

@Constantin: they claim +/-2ppm/year and 5ppm aging - can you confirm that somehow?? Thnks.

Sorry, I hate to be punny but I don't have the time. It's good enough for me...
Title: Re: Keeping accurate time
Post by: fat16lib on Mar 31, 2012, 11:34 pm
I did a number of tests with the DS3231.   2 ppm is reasonable If you power it so the temp compensation is maintained.  I use 5 volts all the time since the rate does vary a bit at different voltages.

I used a gps pps signal to test the chip.  My chips do 1 ppm for short times, a few days.  That's as long as I ran them with the gps clock.

Here is a bit more http://forums.adafruit.com/viewtopic.php?f=19&t=17966&p=92197&hilit=ds3231#p92197 (http://forums.adafruit.com/viewtopic.php?f=19&t=17966&p=92197&hilit=ds3231#p92197)
Title: Re: Keeping accurate time
Post by: pito on Apr 01, 2012, 01:59 pm
@fat16lib: thanks! So you may discipline it via gps and Vcc :).
Title: Re: Keeping accurate time
Post by: Constantin on Apr 01, 2012, 02:03 pm
Using a GPS receiver is about as good as you're going to get... hard to beat atomic clocks that operate under close supervision.
Title: Re: Keeping accurate time
Post by: odometer on Apr 15, 2012, 02:33 am

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

Code: [Select]

uint32_t lastTime;

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



This is actually a very smart way of doing it, because you avoid the problems with millisecond rollover.
I wonder why people seem to think that using the built-in millisecond counter inevitably results in problems at rollover.

Alternatively, I would suggest using the microsecond counter.
Code: [Select]

uint32_t lastTime = 0;
const int oneSecond = 1000000;

void loop(void)
{
  if ((micros() - lastTime) >= oneSecond) {
    lastTime += oneSecond;
    digitalClockDisplay();
  }
  ......
}

This rolls over every 1.2 hours or so, but that is not a problem in this sort of application. Another advantage -- in this application, quite a great one -- is that a clock that runs too fast or too slow is easily adjusted by changing the value of the constant oneSecond. (sort of like the fast/slow lever on a wind-up alarm clock)
Title: Re: Keeping accurate time
Post by: Constantin on Apr 15, 2012, 09:08 pm
"const int oneSecond = 1000000;"

Can this work? I'd like to think you need a long for such a big number. Beyond that, wouldn't one have to use 1000000L?
Title: Re: Keeping accurate time
Post by: odometer on Apr 15, 2012, 09:58 pm

"const int oneSecond = 1000000;"

Can this work? I'd like to think you need a long for such a big number. Beyond that, wouldn't one have to use 1000000L?


OOPS! (Well, I told you it was untested code.)

Okay, so try:
Code: [Select]

uint32_t lastTime = 0;
const long oneSecond = 1000000L;

void loop(void)
{
  if ((micros() - lastTime) >= oneSecond) {
    lastTime += oneSecond;
    digitalClockDisplay();
  }
  ......
}
Title: Re: Keeping accurate time
Post by: Coding Badly on Apr 16, 2012, 12:48 am

I suspect the compiler is smart enough to know what you intended but, technically, because you are comparing an unsigned value to a signed value the comparison should be extended to 64 bits; which is rather undesirable.  This is probably a better choice...

[font=Courier New]const unsigned long oneSecond = 1000000UL;[/font]
Title: Re: Keeping accurate time
Post by: pentius on Sep 01, 2016, 12:21 am
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.
If you live in a blackout-prone area (like a rural or Third World area) the Arduino's crystal will, if calibrated, make a pretty good fallback oscillator. In that case, you get to figure out how to design the power supply as well as the software. If you go the 60Hz route, be careful not to let the pulses exceed the 5 volts!
Title: Re: Keeping accurate time
Post by: allanhurst on Sep 01, 2016, 10:49 am
A second a day is 11ppm - not that good.

The chip you use for a clock isn't terribly important - the reference frequency, from whatever
source , defines the accuracy. How good do you want to get?

You can buy 16MHz TCVCXO's good to 0.1ppm over a limited temperature range for about £15.

If you want a lot better, use an off-air reference, as some clocks do, or mains ( whose long term acccuracy is good, but may have significant short-term variations).. we'll leave atomic clocks out of it for now!

regards

Allan.
Title: Re: Keeping accurate time
Post by: dwightthinker on Sep 03, 2016, 05:48 am
A DS3231 is +- 2 mins a year. That is about 4 ppm.
The Mega can only measure 4 us at best.
Even with correction to the drift of the resonator,
one would need to measure for a time length of several
minutes to approach the 4 ppm of the DS3231.
Under normal conditions, I only saw a few us drift every
second, using the DS3231 interrupt to calibrate with.
Most of the other timing errors because of uncertainty
average out over time.
I believe the DS3231 is about as good as is useful with
an arduino.
Using a 0.1ppm TCXO would not be too useful unless
you were talking about time measurement of minutes.
Dwight
Title: Re: Keeping accurate time
Post by: ad2049q on Sep 17, 2016, 07:11 pm
Mine was off by +- 2 parts in 10000 from presumption of software "microseconds" == 1.00000 microseconds and was noticed to be somewhat temperature dependent in how far off.  Room temperature was 15 to 20 C.

Yours seems to be off by 2 parts in 1440 which is even worse.
If you make a measured correction, such as 'count to 10014900 "microseconds" and call that a "second" ' that will lessen your error but still drift according to temperature of the crystal.  You have three options - get ntp time on an internet device such as a raspberry pi, or get a real time clock add-on module as mentioned above, or get the module to pick up the atomic synched radio clock if you are in a region which has one.
Title: Re: Keeping accurate time
Post by: ad2049q on Sep 20, 2016, 11:18 am
Your loop relied on

Code: [Select]

void loop()
  {
  do some stuff;
  delay(1000);
  }

So if it takes any time at all to do some stuff then you'll get behind with respect to 1000 "milliseconds".
Title: Re: Keeping accurate time
Post by: MarkT on Sep 26, 2016, 12:55 pm
If you live in a blackout-prone area (like a rural or Third World area) the Arduino's crystal will, if calibrated, make a pretty good fallback oscillator. In that case, you get to figure out how to design the power supply as well as the software. If you go the 60Hz route, be careful not to let the pulses exceed the 5 volts!
Your Arduino has a crystal?  Clearly not an Uno then, which use inaccurate ceramic oscillator.
Title: Re: Keeping accurate time
Post by: dwightthinker on Sep 26, 2016, 10:23 pm
This rolls over every 1.2 hours or so, but that is not a problem in this sort of application. Another advantage -- in this application, quite a great one -- is that a clock that runs too fast or too slow is easily adjusted by changing the value of the constant oneSecond. (sort of like the fast/slow lever on a wind-up alarm clock)
Actually, there is an interesting discussion going on about millis().
A single tick of millis() is actually 1.024 milliseconds.
It periodically skips a count to keep the error within
+- 1 millisecond.
This has nothing to do with rollover.
One should always use >= or > with millis() but never ==
as it may never actually count that number.
Of course, these boards do use a resonator for the processor.
The crystal on the board is for communications with the USB.
Dwight