Pages: 1 [2] 3   Go Down
Author Topic: Clock with Arduino  (Read 6687 times)
0 Members and 1 Guest are viewing this topic.
Italy
Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I don't think I loose ms on each loop. Let's see the first code I post:
Code:
 current_millis_value = millis();
  m += current_millis_value - previous_millis_value;
  seconds += m / 1000;
  m = m % 1000;
  minutes += seconds / 60;
  seconds = seconds % 60;
  hours += minutes / 60;
  minutes = minutes % 60;
  hours = hours % 24;
  previous_millis_value = current_millis_value;
If you think about it, you will notice that m is a "cumulative-ms" variable. On every loop, I increase seconds by m / 1000, but then I do m = m % 1000 in order to not loose left-over ms... Right?
Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6255
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Joe, you are quite right that its not your code that  is causing time errors but I remain surprised that your crystal is so inaccurate.  I have just completed a test using a third arduino board (as I mentioned, two other boards were tested to be accurate to within a few seconds per day measured over many days) to see if I could reproduce the kind of results you posted.

My test on the third board has been running for over 7 and a half hours and the arduino is within on second of internet checked atomic time. So I am not sure why your results are so different to mine, and why they seem to be outside the spec for a 30ppm crystal.
« Last Edit: July 07, 2008, 02:19:01 pm by mem » Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6255
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Joe, update on the arduino time test:  My test has been running for over 24 hours with the arduino clock remaining within two seconds of an external time reference over that period. Thats three different boards verified as keeping time within about 2 secs per day.


Is your board using a resonator instead of a crystal?
Logged

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

Quote
Is your board using a resonator instead of a crystal?
Umh, I don't know... Mine is an Arduino Diecimila...
Logged

0
Offline Offline
Newbie
*
Karma: 1
Posts: 41
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Quote
Do you know what the specs say for the accuracy of the crystal used on Arduinos?
No, I don't know. I've only measured time difference with a stopwatch, looking at Arduino and an atomic clock via internet. I can be a little imprecise, but over 6 hours of measuring, results are clear:
Code:
0h       0.00s
1h      -0.70s
2h      -1.10s
3h      -1.60s
4h      -2.00s
5h      -2.40s
6h      -3.00s
7h      -3.50s

This morning I read result of the overflow test from my Arduino EEPROM. It's exactly the value you calculate: 34359737 before overflow, 0 after overflow. So I will use:
Code:
#define MAX_MILLIS_VALUE 34359738
...
if (current_millis_value < previous_millis_value)
     m += MAX_MILLIS_VALUE - previous_millis_value + current_millis_value;
else m += current_millis_value - previous_millis_value;
On the simpler overflow (from 34359737 to 0):
MAX_MILLIS_VALUE - previous_millis_value + current_millis_value = 34359738 - 34359737 + 0 = 1
1 millisecond is elapsed.
Thank you Ben!  smiley-wink

Nice post indeed. I though I could understand the question in snap... no way  smiley-wink
Question is: why nobody uses the modulo function in order to have a smooth constant elapsed time calculation? Kind of:

elapsed_time=(max_counts+this_tick-last_tick)%max_counts ?

Am I misleading?

Logged

Austin, TX USA
Offline Offline
God Member
*****
Karma: 4
Posts: 997
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Joker,

The express you propose,

elapsed_time = (max_counts + this_tick - last_tick) % max_counts;

is indeed more succinct and readable than the equivalent

if (this_tick < last_tick)
  elapsed_time = max_counts + this_tick - last_tick;
else
  elapsed_time = this_tick - last_tick;


However, I think you'll find that many programmers opt for the latter for the simple reason that in most computer architectures the modulus operation is much more costly in terms of CPU consumption.

Cheers,

Mikal
« Last Edit: September 08, 2008, 10:58:12 am by mikalhart » Logged

0
Offline Offline
Newbie
*
Karma: 1
Posts: 41
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I see, thanks for the hint.
See, I am still from the memory greedy VB.NET, and I have to get used to smaller environments (that I love anyway); takes me back to the early 80's and HP1000 running progs in 32K!  :o

How many ticks for a mod?
Logged

0
Offline Offline
Newbie
*
Karma: 1
Posts: 41
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the example.
Finally, I jumped out the frying pan (millis function  :-/ ) into the fire (Timers  smiley-razz). It took me a little time  :smiley before being confortable about them, but it's OK now and find them muuuuch more handy: now I can really control time accuracy and forget about roll-overs, changes in versions, etc. And they are accurate: heavily tested on functions generators http://forums.adafruit.com/viewtopic.php?f=25&t=14149  smiley-wink
« Last Edit: February 08, 2010, 03:48:30 am by joker » Logged

Madison, WI
Offline Offline
Newbie
*
Karma: 0
Posts: 48
Exploring Electrons. . .
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Alright, things aren't working so hot :-(

I'm running this code:
Code:
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

unsigned long current_millis_value = 0;
unsigned long previous_millis_value = 0;
unsigned long m = 0;
unsigned int seconds = 0;
unsigned int minutes = 0;
unsigned int hours = 0;

void setup()
{
  lcd.begin(2, 16);
  lcd.clear();
}
void loop()
{
  cli();
  current_millis_value = millis();
  sei();
  m += current_millis_value - previous_millis_value;
  seconds += m / 1000;
  m = m % 1000;
  minutes += seconds / 60;
  seconds = seconds % 60;
  hours += minutes / 60;
  minutes = minutes % 60;
  hours = hours % 24;
  previous_millis_value = current_millis_value;
  lcd.clear();
  lcd.print("t:");
  lcd.print(hours);
  lcd.print(":");
  lcd.print(minutes);
  lcd.print(":");
  lcd.print(seconds);
  
  delay(150);
}

on a Duemilanove and am able to watch the Arduino run too slowly (loses 1/2 a second in the first minute).  Anyone have any thoughts?  Are there delays/interrupts in the LCD library?

I just need a timer that counts up accurately when some event is true, it only needs to run for about an hour max so the overflow isn't an issue at all for me.  Is there a better/more precise way to be doing this?  I've dug through the code and stripped it down to what you see, there isn't much left except for the LCD screen writes that could be losing/taking time but I shouldn't matter how long the program since that's all accounted for.

Any thoughts?   >smiley-sad
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 610
Posts: 48993
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

More questions than answers, really. Why are disabling interrupts before calling millis?

Why are you calling delay?

There are more efficient ways of computing new values for minutes and hours. minutes only needs to be updated if seconds has reached 60. An if test (if seconds == 60) and two assignments (seconds = 0; minutes++;) is faster than the call to the modulo function. The same hold true for hours. hours only needs to change when minutes equals 60. hours can be reset to 0 faster using an if test than a modulo function call, too.
« Last Edit: February 09, 2010, 06:05:18 am by PaulS » Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6255
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

perhaps try something like this:

Code:
void loop()
{
  while( millis() - previous_millis_value >= 1000){      
    elapsedSeconds++;
    previous_millis_value += 1000;      
  }
  seconds = elapsedSeconds % 60;
  minutes = (elapsedSeconds / 60) % 60;
  hours =  elapsedSeconds / 3600;  
}
Logged

Madison, WI
Offline Offline
Newbie
*
Karma: 0
Posts: 48
Exploring Electrons. . .
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Why are disabling interrupts before calling millis?

That's covered further up this thread, someone suggested that an interrupt would corrupt data from the millis call, doesn't seem to have any effect in my testing.

Quote
Why are you calling delay?

Delay is so the screen flicker on the LCD display isn't terrible.  If you run it any faster than 150 milliseconds it starts to blend things together (when the milliseconds readout is running, which isn't in this code).

Quote
There are more efficient ways of computing new values for minutes and hours.

I agree that when possible the most efficient path to the objective should be used, but fundamentally does it matter in this loop losing time?  Since the loop is just counting up how many milliseconds have iterated between loops and adding it to a value I don't think it has any effect on the loss of time (which is what I'm worried about before beginning to optimize anything).

Quote
mem says: perhaps try something like this: . . .

I ran this, after about 3 minutes the Arduino was off by exactly a second, it again is running too slowly.


The only way this could be happening is if the millis() call isn't returning the correct time, which is a function directly of the processor crystal right? Can anyone else test this code (mem's) and see if they're having similar results?  I'll run this code on a mega later today and see if I have similar issues or if things clear up; until then any other ideas?

Thanks everyone for help!
« Last Edit: February 09, 2010, 09:21:41 am by Waterppk » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 610
Posts: 48993
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I ran this, after about 3 minutes the Arduino was off by exactly a second, it again is running too slowly.

Compared to what?
Logged

Madison, WI
Offline Offline
Newbie
*
Karma: 0
Posts: 48
Exploring Electrons. . .
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

It's now been running for:
33 minutes 43 seconds
clock time,
arduino says:
33 minutes 30 seconds

I'm using a stopwatch for comparison, I previously tested the stopwatch against http://www.time.gov/timezone.cgi?Central/d/-6/java for ~8 hours without losing a second, so for now the stopwatch is much more accurate than the Arduino  smiley-wink
Logged

Madison, WI
Offline Offline
Newbie
*
Karma: 0
Posts: 48
Exploring Electrons. . .
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Alright, I switched over to using Serial.print and watching on the console and it's running spot on at 4 minutes.

I'll figure out who wrote the LCD library and follow up with them, obviously there's something in that library messing up a timing routine.

Thanks for your help guys.
Logged

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