Step 4: Time keeping
Measure how inexact your arduino is:
As said earlier, the arduino will have a small time error, this error depends on the crystal oscillator and will be different for every arduino, to measure how much my arduino clock differed from the correct time, I programmed it to print out the time ( the hour, minute and second variables) via serial. I then let it run for a long time (Over night and more) and compared the arduino time with a clock I knew was exact, at the start and the end of my measuring period. Divide the time difference with the time the test took to calculate the error each hour. I found that my arduino is about 0.4 seconds to fast every hour. I used exacttimenow.com to get exact time, but if you have a watch you know is very exact, feel free to use that instead.
The code I used to keep the time is an adaptation of some code I found on the arduino forums. I rewrote it with if-statements instead of division and modulo, to see if there would be any speed difference and found that the if-version is more than 15 times faster (although both are still quite fast, more info about the test here).
Since I want the other stuff in my main loop (like checking the touch sensor, checking for button presses, etc.) to happen as often as possible, I used the faster version.
Every time the clock function is called it adds the time in milliseconds since last it was called to a variable m, when one second has passed (m>999) the second variable is increased by one and m is reset. When the seconds variable reaches 60, the minute variable will be increased by one, and seconds will be set to zero. The same thing happens with the minutes variable; when it reaches 60, add 1 to hours and reset minutes. The hour variable will be reset when it reaches 24.
To compensate that my arduino is 0.4 seconds faster evey hour, I decrease the seconds with two seconds every fifth hour.
The clock() function:
// CLOCK VARIABLES:
#define MAX_MILLIS_VALUE 34359738
unsigned long current_millis_value = 0;
unsigned long previous_millis_value = 0;
unsigned long m = 0;
int seconds = 0;
int minutes = 0;
int hours = 0;
current_millis_value = millis();
if (current_millis_value < previous_millis_value) // if millis overflows
m += MAX_MILLIS_VALUE - previous_millis_value + current_millis_value;
else // if millis has not overflown
m += current_millis_value - previous_millis_value;
m = m-1000;
if (seconds>59) // if seconds == 60
seconds = 0;
if (minutes>59) // if minutes == 60
minutes = 0;
if(hours%5==0) // adjust the time with -2 seconds every 5th hour.
seconds = seconds - 2; // this will cause seconds to be -2,
// therefore seconds can't be unsigned.
if (hours>23) // if hours == 24
hours = 0;
previous_millis_value = current_millis_value;