I have a need for a "reasonably" accurate timekeeper. By "reasonable", I mean "comparable to any cheapo battery-powered clock".
I want to build a timekeeping circuit for a novelty clock - it only needs to display seconds, and then drive a few other electronic bits at the beginning of every minute.
I've done some tests with millis(), but it seems there's a noticeable drift after only a couple of hours so I suspect it wouldn't be suitable to be left running for weeks.
I'd be interested to know what other techniques people might recommend - is there a good solution that can be supported by the Arduino, or would I be better off buying a separate RTC module? Or just go nuts and install an atomic clock decoder?
If you can find an atomic clock decoder cheaply, I'd definately buy it . Or, you could buy a GPS module and extract the time (atomic clock accuracy) from that. On the other hand, you could do what I did and buy a DS1307 IC or module of eBay, or somewhere else, download a library for it and use that. It is easy to do, and gives decent accuracy.
I've done some tests with millis(), but it seems there's a noticeable drift after only a couple of hours
Could be your code is at fault.
But sadly, we can't see it.
#include <LiquidCrystal.h>
int g_iHour;
int g_iMin;
int g_iSec;
unsigned long g_uLastTick;
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup()
{
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
lcd.print("Simple LCD Clock");
g_iHour = 0;
g_iMin = 0;
g_iSec = 0;
g_uLastTick = millis();
}
void loop()
{
// compose a string of the current time, then print it ...
char text[20];
sprintf(text, "%02d:%02d:%02d", g_iHour, g_iMin, g_iSec);
lcd.setCursor(4, 1);
lcd.print(text);
// (note that this is quite wasteful - we only need to update the screen every second,
// or when a button is pressed)
// has it been more than a second since the last update?
if (millis() >= (g_uLastTick + 1000))
{
// yes
g_uLastTick += 1000;
g_iSec++;
if (g_iSec > 59)
{
g_iSec = 0;
g_iMin++;
if (g_iMin > 59)
{
g_iMin = 0;
g_iHour++;
if (g_iHour > 23)
{
g_iHour = 0;
}
}
}
}
}
You don't say what board is being used but most Unos, etc., use a ceramic resonator for the system clock, which will typically have a frequency tolerance on the order of ±0.5%. Changing to a crystal (say, ±20ppm) might be simplest, but if you're not in a position to do that, then I'd try a DS1307 RTC. DS1307 breakout boards can be had for under $10, some will plug directly into the headers on an Arduino Uno.
Lately I've been experimenting with running an ATmega328P on the internal oscillator, and connecting a 32.768kHz crystal which acts as a clock source for Timer/Counter2. A simple RTC can then be implemented in software. Fairly straightforward, keeps decent time.
Could also run a straight sketch.
I ran this one on a Duemilanove against the official US time here for 5 hours and it stayed in sync the whole time. http://www.time.gov/timezone.cgi?Eastern/d/-5/java
unsigned long currentmillis = 0;
unsigned long previousmillis = 0;
unsigned long interval = 10000;
byte ones_seconds = 0;
byte prior_seconds = 0;
byte tens_seconds = 0;
byte ones_minutes = 0;
byte tens_minutes = 0;
byte tenths = 0;
byte hundredths= 0;
void setup()
{
Serial.begin(57600);
}
void loop()
{
currentmillis = micros(); // read the time.
while (currentmillis - previousmillis >= interval) // 10 milliseconds have gone by
{
hundredths = hundredths +1;
if (hundredths == 10){
hundredths = 0;
tenths = tenths +1;
}
if (tenths == 10){
tenths = 0;
ones_seconds = ones_seconds +1;
}
if (ones_seconds == 10){
ones_seconds = 0;
tens_seconds = tens_seconds +1;
}
if (tens_seconds == 6){
tens_seconds = 0;
ones_minutes = ones_minutes +1;
}
if (ones_minutes == 10){
ones_minutes = 0;
tens_minutes = tens_minutes +1;
}
if (tens_minutes == 6){
tens_minutes = 0;
}
previousmillis = previousmillis + interval; // save the time for the next comparison
}
// counters are all updated now,
if (prior_seconds != ones_seconds){
Serial.print (tens_minutes, DEC);
Serial.print (" ");
Serial.print (ones_minutes, DEC);
Serial.print (" : ");
Serial.print (tens_seconds, DEC);
Serial.print (" ");
Serial.println (ones_seconds, DEC);
prior_seconds = ones_seconds;
}
} // end void loop
I have a need for a "reasonably" accurate timekeeper.
We have seen "clocks" on this forum that used the amount of light to detect morning midday and evening to get the right timing to feed chicken, an error of 30 minutes was no problem, so reasonable is project dependable.
So, can you specify reasonable? What is the maximum error that is acceptable?
1 second per minute, hour, day, week, month, year?
Or maybe you can tell more about the project itself so we can think about what is needed.
To complete the list of proposed solutions: you can add an ethernet shield and use NTP (network Time Protocol) to request time from an Atomic clock.