Clock running behind over time

I am building a watch based off the Hello World example wiring (minus the potentiometer) and I added some neat binary patterns in the background to give it some flare, you know? Anyways, I didn't want to make an if statement with millis() 32 times for every binary digit, so i made the decals run on a delay between each digit change for 6 seconds, then repeated it 10 times. However when i checked back on my watch around a half hour later, it was running 45 seconds behind! I checked through my code multiple times but couldn't find a timing inconsistency. Please help!

My code (sorry it's only partially documented):

// include the library code:
#include <LiquidCrystal.h>

// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
int Minute = 8;
int Ten = 4;
int Hour = 5;
int Hour2 = 0;
bool ap = false;
long binary;
byte Line[8] = {
  0b00100,
  0b00100,
  0b00100,
  0b00100,
  0b00100,
  0b00100,
  0b00100,
  0b00100
            
};

void setup() {
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  randomSeed(analogRead(0));
}

void loop() {

//=======This part writes all the info down
     lcd.setCursor(6, 0);
  // print the number of seconds since reset:
  lcd.print(millis() / 1000);
  lcd.setCursor(6, 0);
  lcd.print(Hour2);
  lcd.setCursor(7, 0);
  lcd.print(Hour);
  lcd.setCursor(8, 0);
  lcd.print(Ten);
  lcd.setCursor(9, 0);
  lcd.print(Minute);
  lcd.setCursor(7, 1);
  lcd.createChar(0, Line);
  lcd.setCursor(5, 0);
  lcd.write(byte(0));
  lcd.setCursor(5, 1);
  lcd.write(byte(0));
  lcd.setCursor(10, 0);
  lcd.write(byte(0));
  lcd.setCursor(10, 1);
  lcd.write(byte(0));
  lcd.setCursor(7, 1);
  if (ap == true) lcd.print("AM");
  if (ap == false) lcd.print("PM");

//=======Adds one minute

Minute = Minute + 1;

//=======Binary Decals / Timer
for(int i = 0; i < 10; i++)
{
  delay(250);
  binary = random(0, 2);
  lcd.setCursor(15, 1);
  lcd.print(binary);
  binary = random(0, 2);
  lcd.setCursor(15, 0);
  lcd.print(binary);
  delay(250);
  binary = random(0, 2);
  lcd.setCursor(14, 1);
  lcd.print(binary);
  binary = random(0, 2);
  lcd.setCursor(14, 0);
  lcd.print(binary);
  delay(250);
  binary = random(0, 2);
  lcd.setCursor(13, 1);
  lcd.print(binary);
  binary = random(0, 2);
  lcd.setCursor(13, 0);
  lcd.print(binary);
  delay(250);
  binary = random(0, 2);
  lcd.setCursor(12, 1);
  lcd.print(binary);
  binary = random(0, 2);
  lcd.setCursor(12, 0);
  lcd.print(binary);
  delay(250);
  binary = random(0, 2);
  lcd.setCursor(11, 1);
  lcd.print(binary);
  binary = random(0, 2);
  lcd.setCursor(11, 0);
  lcd.print(binary);
  delay(250);


  binary = random(0, 2);
  lcd.setCursor(4, 1);
  lcd.print(binary);
  binary = random(0, 2);
  lcd.setCursor(4, 0);
  lcd.print(binary);
  delay(250);
  binary = random(0, 2);
  lcd.setCursor(3, 1);
  lcd.print(binary);
  binary = random(0, 2);
  lcd.setCursor(3, 0);
  lcd.print(binary);
  delay(250);
  binary = random(0, 2);
  lcd.setCursor(2, 1);
  lcd.print(binary);
  binary = random(0, 2);
  lcd.setCursor(2, 0);
  lcd.print(binary);
  delay(250);
  binary = random(0, 2);
  lcd.setCursor(1, 1);
  lcd.print(binary);
  binary = random(0, 2);
  lcd.setCursor(1, 0);
  lcd.print(binary);
  delay(250);
  binary = random(0, 2);
  lcd.setCursor(0, 1);
  lcd.print(binary);
  binary = random(0, 2);
  lcd.setCursor(0, 0);
  lcd.print(binary);
  delay(250);

  lcd.setCursor(15, 1);
  lcd.print(" ");
  lcd.setCursor(15, 0);
  lcd.print(" ");
  delay(250);
  lcd.setCursor(14, 1);
  lcd.print(" ");
  lcd.setCursor(14, 0);
  lcd.print(" ");
  delay(250);
  lcd.setCursor(13, 1);
  lcd.print(" ");
  lcd.setCursor(13, 0);
  lcd.print(" ");
  delay(250);
  lcd.setCursor(12, 1);
  lcd.print(" ");
  lcd.setCursor(12, 0);
  lcd.print(" ");
  delay(250);
  lcd.setCursor(11, 1);
  lcd.print(" ");
  lcd.setCursor(11, 0);
  lcd.print(" ");
  delay(250);
  
  lcd.setCursor(4, 1);
  lcd.print(" ");
  lcd.setCursor(4, 0);
  lcd.print(" ");
  delay(250);
  lcd.setCursor(3, 1);
  lcd.print(" ");
  lcd.setCursor(3, 0);
  lcd.print(" ");
  delay(250);
  lcd.setCursor(2, 1);
  lcd.print(" ");
  lcd.setCursor(2, 0);
  lcd.print(" ");
  delay(250);
  lcd.setCursor(1, 1);
  lcd.print(" ");
  lcd.setCursor(1, 0);
  lcd.print(" ");
  delay(250);
  lcd.setCursor(0, 1);
  lcd.print(" ");
  lcd.setCursor(0, 0);
  lcd.print(" ");
  delay(1000);
}
  




        
    

if (Minute == 10) Ten = Ten + 1;
if (Minute == 10) Minute = 0;

if (Ten == 6) Hour = Hour + 1;
if (Ten == 6) Ten = 0;

if (Hour == 10) Hour2 = Hour2 + 1;
if (Hour == 10) Hour = 0;

  lcd.setCursor(7, 1);
if (ap == true) lcd.print("AM");
if (ap == false) lcd.print("PM");

if (Hour2 == 1 && Hour == 3) {
Minute = 0;
Ten = 0;
Hour = 1;
Hour2 = 0;
ap = !ap;
  lcd.setCursor(7, 1);
if (ap == true) lcd.print("AM");
if (ap == false) lcd.print("PM");

  }
}

This technique won't really work to create a clock.

Using delay() simply pauses all code from running. Each loop you pause for 6 seconds, BUT you also have a lot of other statements running in each loop - these take time... so each loop is actually more than 6 seconds... that is why your clock appears to run slow.

You should check out using millis() - this will be much more accurate if used correctly.

millis() timing tutorials:
Blink without delay().
Beginner's guide to millis().
Several things at a time.

Or ideally, an RTC chip (DS323x) or similar. for long term accuracy.
Using the processor clock will inevitably drift over several hours when compared to a β€˜real’ clock.

sure... if the OP has one lying around :slight_smile:

I see what you tried to do. You tried to make your delays add up to exactly 1 minute, so that the clock would advance after exactly 1 minute.
Your mistake was forgetting that all of the lcd.print commands take time to execute. If your clock spent a total of 45 seconds in lcd.print statements, then that would explain the 45 seconds your clock lost.

There is more than one way to fix your problem.

The lazy way to fix your problem is to change the delay(1000); to a smaller number, maybe something like delay(850); or so, and hope that that is enough to get your clock running at the right speed.

A less lazy way to fix your problem is to use a timekeeping mechanism which I have used in my own clocks. This uses one more variable, which I will call MinuteStart. It will need to be an unsigned long, like this:

unsigned long MinuteStart = 0UL;

It belongs together with your other timekeeping variables, such as Minute and Ten.
Then, you take this line

//=======Adds one minute

Minute = Minute + 1;

and wrap it in something that looks like this:

//=======See if it is time to start a new minute,
//=======and if it is time, then start the new minute

if ((millis() - MinuteStart) >= 60000UL) {
  Minute = Minute + 1;
  MinuteStart = MinuteStart + 60000UL;
}

(You might be wondering what the UL after some of the numbers means. It means unsigned long. An int can only handle numbers up to 32767. An unsigned long can handle numbers from 0 to a little over 4 billion. For doing math with millis(), like we are doing here, we need unsigned long.)

This ↓ calculates the number of milliseconds since the start of the minute.

(millis() - MinuteStart)

This ↓ checks to see if it has been at least 60000 milliseconds since the start of the minute.

if ((millis() - MinuteStart) >= 60000UL)

This ↓ counts one minute (but you already knew that).

  Minute = Minute + 1;

This ↓ sets up MinuteStart for the new minute.

  MinuteStart = MinuteStart + 60000UL;

(Think about it: the start of the new minute should be exactly 60000 milliseconds after the start of the old minute. That's why we increase MinuteStart by 60000.)

One last thing: you should get rid of this

for(int i = 0; i < 10; i++)

because you don't need to count 10 loops. Remember, we don't need to count loops, because we're counting milliseconds. The milliseconds will tell us when it's time to start a new minute.

I hope this all makes sense to you.

1 Like

If you want to make a clock without using an RTC, have a look at the TimeLib library.
It will track time using the millis() counter. It has many API functions to extract various time and date fields.

If you have an RTC you tell TimeLib to use it to synchronize the time so that it recovers after power failures and will also be more accurate time keeping tht solely depending on the system clock used on the Arduino.

--- bill

:+1:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.