Go Down

Topic: Simplest way of timekeeping? (Read 1 time) previous topic - next topic

oddbloke

Evening all!

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?

Thanks in advance for any advice,

Kris.

AWOL

Quote
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.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Onions

If you can find an atomic clock decoder cheaply, I'd definately buy it :D . 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.

Onions.
My website: http://www.harryrabbit.co.uk/electronics/home.html Up and running now! (Feel free to look round!) :D

oddbloke

#3
Jan 01, 2012, 01:22 am Last Edit: Jan 02, 2012, 08:51 am by CrossRoads Reason: 1

Quote
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.

Code: [Select]

#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;
       }
     }
   }
 }
}



Jack Christensen

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.
MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

oddbloke


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.


Thanks for your comment - yes, I should have mentioned that I'm using an Uno.

I think the most straightforward thing to try next will be a 1307.

Cheers!

CrossRoads

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

KirAsh4

Or the much cheaper DS1337, which does come in DIP form.  It's I2C though, not SPI.

CrossRoads

DS133 needs a crystal and I2C pullup resistors, which I was suggesting could be avoided.
Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

CrossRoads

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

Code: [Select]

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

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

robtillaart


@Crossroads

typo or intentional?

Code: [Select]
  currentmillis = micros(); // read the time.

@oddbloke:
Quote
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.

Rob Tillaart

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

CrossRoads

Rob Tillaart,
Not a typo - I had a millis based example that I changed to be micros based instead, didn't bother changing all the variable names.

I let this run for 5 hours the other day, fully expecting to see some drift away - and every time I checked the seconds were right in sync.
Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Jack Christensen

CrossRoads, is there a crystal or resonator on the Duemilanove?
MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

CrossRoads

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

stoopkid

I've found the DS1307 with a resonator and the RTClib library to be very noob friendly...

Go Up