Go Down

Topic: Who needs a Software Real Time Clock? (Read 13357 times) previous topic - next topic

mem

May 19, 2008, 06:42 pm Last Edit: May 19, 2008, 06:43 pm by mem Reason: 1
I was a little surprised not to get any response for a library that gives date and time functionality to an arduino without the use of a real time clock. It was mentioned in this thread http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210889307#8 as a way of bypassing the millis rollover problem for sketches that need a way of manipulating and/or displaying times in units of seconds or more.

I was wondering if the cost and effort of integrating a separate real time clock is really no barrier to people that want this kind of functionality so no point in a 'Software Real Time Clock'.

Here are the advantages and disadvantages as I see them of both approaches, I would appreciate hearing your view on the relative merits of a software only solution.

The main advantages of software only solution is that there is no hardware to buy or integrate, everything runs on the Arduino. The main advantage of an external clock board is that it will keep the correct time even if the Arduino resets (the arduino soft solution needs to be synchronized, typically via a time message on the serial port.)

Here is the functionality in the DateTime library that I am using on the arduino. It is built on the standard time_t (an unsigned long) that is the number of seconds since midnight Jan 1 1970  (aka unix time).

[font=monospace]void sync(time_t time);  // set the internal clock to the given time
time_t now(); // return the current time as seconds since midnight Jan 1 1970
boolean available();  // refreshes the Date and Time properties and returns true if clock synced
// date and time properties updated using the timer0 overflow interrupt  
byte Hour;
byte Minute;
byte Second;
byte Day;
byte DayofWeek; // Sunday is day 0
byte Month; // Jan is month 0
byte Year;  // the Year minus 1900

// optional utility functions to convert to and from time components (hrs, secs, days, years etc) to time_t  

// extracts time components from time_t
void localTime(time_t *timep,byte *psec,byte *pmin,byte *phour,byte *pday,byte *pwday,byte *pmonth,byte *pyear);

// returns time_t from components
time_t makeTime(uint8_t sec, uint8_t min, uint8_t hour, uint8_t day, uint8_t month, int year );
[/font]


It takes more time to properly document something like this then it does to code it so I would like to hear views on the usefulness or otherwise of this before embarking on writing an article for the playground and posting the code there.

mellis

This sounds like it would be a useful library.  Can it be built on top of the millis() function?

mem

Quote
This sounds like it would be a useful library.  Can it be built on top of the millis() function?


Hi David,
Yes, it was designed to be driven from millis.
What is the latest thinking on the best way to avoid the overflow problems?




Digger450

I would absolutely be interested in this library!  I don't have a specific application at the moment, but I can see this would be very useful.

mellis

mem: I'm planning to stick with the solution that I implemented and posted to the other thread, unless someone comes up with a better implementation.

paulb

Just want to put in my two cents that the real time clock library is a great idea, and really useful for long running projects.

Like you say though the battery backed clock is much more of a set it and forget type of operation, and without an LCD for reboot warnings and setting the time, the utility of a software clock would be somewhat less.

EEPROM write for persistent (but not absolutely accurate time)? I have a feeling that most people using the library are going to care about keeping things relatively accurate over periods of weeks or months and bit of drift isn't too much of a concern.

Paul

mem

Quote
Just want to put in my two cents that the real time clock library is a great idea, and really useful for long running projects.

Like you say though the battery backed clock is much more of a set it and forget type of operation, and without an LCD for reboot warnings and setting the time, the utility of a software clock would be somewhat less.

EEPROM write for persistent (but not absolutely accurate time)? I have a feeling that most people using the library are going to care about keeping things relatively accurate over periods of weeks or months and bit of drift isn't too much of a concern.

Paul

Persisting the time through a reset/power down cycle  is something I had not thought of. It's a really good idea but a problem with using EEPROM to hold the previous value is that I think a single EEPROM address updated once per minute would wear in a few months.  I wonder if it would be unrealistically selfish to reserve up to half the EEPROM for this purpose so that memory locations could be spread around?

mem

The write-up and code for the software DateTime library is now in the playground:
http://www.arduino.cc/playground/Code/DateTime


Jonen

First off, I really like the ability to control the time using arduino whitout the use of any RTC...
However I would like to have the ability to correct the time, for instance you know your arduino run 3sec fast in 48 hours, then the library correct the time, ider by adding one sec every 16 hour or something... This feature would be really useful when creating a clock that don't have any connection to the outside world and needs to keep time really acurate over long time...

/Jon

mem

#9
Jul 07, 2008, 03:50 pm Last Edit: Jul 07, 2008, 03:54 pm by mem Reason: 1
Quote
First off, I really like the ability to control the time using arduino whitout the use of any RTC...
However I would like to have the ability to correct the time, for instance you know your arduino run 3sec fast in 48 hours, then the library correct the time, ider by adding one sec every 16 hour or something... This feature would be really useful when creating a clock that don't have any connection to the outside world and needs to keep time really acurate over long time...

/Jon


Hi Jon, would a method like this do what you want?

void setTimeAdjust(int adjSecsPerDay); // number of seconds per day added/subtracted to correct time

example usage:

 SetTmeAdjust(1);  // this will add 1 second per day by adding 1 millisecond every 86.4 seconds
 SetTmeAdjust(4);  // this will add 4 second per day by adding 1 millisecond every 21.6 seconds

 SetTmeAdjust(-1);  // this will subtract 1 second per day by subtracting 1 millisecond every 86.4 seconds
 SetTmeAdjust(-4);  // this will subtract 4 second per day by subtracting 1 millisecond every 21.6 seconds

There will always be some drift in the crystal frequency so I doubt its realistic to try to get better than 1 second per day without resorting to a more accurate crystal and temperature compensation.

mellis

BTW, I added a link to the DateTime library from the main libraries page: http://www.arduino.cc/en/Reference/Libraries

verstapp

mem>wear out EEPROM.
I wouldn't worry. I had the same worry but others put my fears to rest. See here - http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1214379954
Cheers,

PeterV in Canberra

Jonen

Quote
Quote
First off, I really like the ability to control the time using arduino whitout the use of any RTC...
However I would like to have the ability to correct the time, for instance you know your arduino run 3sec fast in 48 hours, then the library correct the time, ider by adding one sec every 16 hour or something... This feature would be really useful when creating a clock that don't have any connection to the outside world and needs to keep time really acurate over long time...

/Jon


Hi Jon, would a method like this do what you want?

void setTimeAdjust(int adjSecsPerDay); // number of seconds per day added/subtracted to correct time

example usage:

 SetTmeAdjust(1);  // this will add 1 second per day by adding 1 millisecond every 86.4 seconds
 SetTmeAdjust(4);  // this will add 4 second per day by adding 1 millisecond every 21.6 seconds

 SetTmeAdjust(-1);  // this will subtract 1 second per day by subtracting 1 millisecond every 86.4 seconds
 SetTmeAdjust(-4);  // this will subtract 4 second per day by subtracting 1 millisecond every 21.6 seconds

There will always be some drift in the crystal frequency so I doubt its realistic to try to get better than 1 second per day without resorting to a more accurate crystal and temperature compensation.


Yea that method will probably work perfect... Thanks a lot mem :D

/Jon

mem

I am testing the proposed impementation for time adjustment,  there is some code below you can run if you want to test it on your board

Edit the variable adjSeconds to a value appropriate for your board, it is the number of seconds to add or subtract each day.

  int adjSecs = 120; // set this to the number of seconds to adjust per day, positive values speed up clock, negative values slow clock down

Compile and run the sketch (no library necessary).

You can see adjusted and unadjusted time updated every half second in the serial monitor (baud rate is 9600) and compare this to an accurate clock to verify that the adjusted value tracks the correct time.

The technique used here is to add the number of seconds set by adjSecs divided equally over a day. It does this by adding .001 times the value of adjSecs every 86 seconds (there are approx 86 thousand seconds per day)

I will update the DateTime library with an adjTime property (minus debug code) after I have completed testing, please let me know you find any issues.


Note that there is no handling of millis rollover in this code. I am testing using the proposed 0012 code as posted here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210889307/#3

Feel free to implement your favorite technique for handling millis rollover if testing for longer than 9 hours.

Code: [Select]

// sketch to test time adjustment

int adjSeconds = 120; // set this to the number of seconds to adjust per day, positive values speed up clock, negative values slow clock down

// system variables
unsigned long prevMillis = 0;
unsigned long sysTime = 0;  // increments once per second

unsigned long adjustedSysTime = 0;  // increments once per second plus/minus adjsutment
unsigned long adjustedPrevMillis = 0;

void adjTime(unsigned long now){
 // this function adds milliseconds times adjSecs every 86 seconds
 if( now - adjustedPrevMillis >= 1000){
   adjustedPrevMillis += 1000;
   if( (++adjustedSysTime) % 86 == 0)  {        
     adjustedPrevMillis += adjSeconds;
     Serial.print("At adjustedSysTime= ");
     Serial.print(adjustedSysTime,DEC);
     Serial.print(" now= ");
     Serial.print(now,DEC);
     Serial.print(" now - adj=");
     Serial.print(now - adjustedPrevMillis, DEC);
     Serial.print(" adding ");
     Serial.print(adjSeconds,DEC);
     Serial.print(" msecs, adjPrevMs= ");
     Serial.println(adjustedPrevMillis,DEC);        
   }    
 }      
}

void printTime(unsigned long time){

 int second = time % 60;
 int minute = (time / 60) % 60;
 int hours =  (time  / 3600) % 24;

 Serial.print(hours,DEC);
 Serial.print( ":");
 Serial.print(minute,DEC);
 Serial.print(":");
 Serial.print(second,DEC);
}

void setup(){
 Serial.begin(9600);
}

void loop() {
 unsigned long now = millis();
 while( now - prevMillis >= 1000){
   sysTime++;
   prevMillis += 1000;
 }  
 adjTime(now);  
 
 Serial.print("Sys time= ");  
 printTime(sysTime);
 Serial.print(", Adjusted time= ");
 printTime(adjustedSysTime);
 Serial.print(", delta= ");
 Serial.print(sysTime - adjustedSysTime, DEC);
 Serial.println(" seconds");
 delay(500);
}

ytsirk

Quick question,
  I'm using the example sketch found at http://www.arduino.cc/playground/Code/DateTime but am having some strange occurrences.  It works flawlessly for what seems like a random period of time but then stalls, no longer reporting anything or responding to updates. After another seemingly random period of time it starts up again but at a completely different date and time.  It can be updated again at this point but ultimately stalls again later.  Does anyone else see this kind of activity or do I maybe have a hardware problem with my Arduino Diecimila?  It always happens within 30 minutes of a reset.

Go Up