Accurate Clock Just Using an Arduino

An accurate clock with date displayed on a 16x2 LCD using just the Arduino, the display and few buttons. No RTC module required.

Feb 25, 2021

•

58657 views

•

32 respects

Components and supplies

3

Tactile Switch, Top Actuated

1

Arduino Nano R3

1

Alphanumeric LCD, 16 x 2

1

Trimmer Potentiometer, 10 kohm

1

Jumper wires

Project description

Code

Clock programme

arduino

Accurate clock with date just using and Arduino

Processing timer testing script

processing

This is the script for Processing that will read the milliseconds sent from the Arduino and compare it to the elapsed milliseconds in processing.

Arduino timer program

arduino

This program sends the number of elapsed milliseconds to the serial port evert 2 seconds.

Processing timer testing script

processing

This is the script for Processing that will read the milliseconds sent from the Arduino and compare it to the elapsed milliseconds in processing.

Clock programme

arduino

Accurate clock with date just using and Arduino

Arduino timer program

arduino

This program sends the number of elapsed milliseconds to the serial port evert 2 seconds.

Downloadable files

Clock LCD 16x2 Breadboard

Clock LCD 16x2 Breadboard

Clock LCD 16x2 Breadboard

Clock LCD 16x2 Breadboard

Clock LCD 16x2 Schematic

Clock LCD 16x2 Schematic

Comments

Only logged in users can leave comments

bossje

9 months ago

Do you have a solution for leap years?

PietBos

8 months ago

Abandoned the project, so nou further use

itsfirepepper

a year ago

this is a perfect design and I love it because I don't have a RTC and I don't plan to get any anytime soon

orenji_san

2 years ago

How are the 6 parts of the code sent to the Arduino? are all joined in to a single file and sent that way?

Anonymous user

2 years ago

not sure if i've understood this or not. are you using the pc clock to correct the arduino time?

paulsb

2 years ago

Hi, No. The link to the PC is only an initial process to calculate the amount by which the Arduino clock is out. Either running fast or slow. That value is entered as the initial setting of the speedCorrection variable. The clock then runs independently making this speed correct adjustment each hour.

Anonymous user

2 years ago

Hi, I Have Successfully Adjusted The Time And Date But Can't Adjust The Year. Please Help Me Out. I Am Making This In TinkerCAD. (I Am Also Running A LED Dot Matrix Clock So I Can't Make It Now)

paulsb

2 years ago

Hi, Difficult to advise without more information. When you say you cannot set the year, what is happening? Are you just not seeing the option or is it showing and you cannot change it? Did you type in the code or copy and paste it? I would check the code to make sure there is not an error in it. Paul

Anonymous user

2 years ago

Umm, I Simulated It, I Felt Lazy To Make It In Real Life. ( I Copy Pasted The Code In TinkerCAD)

Anonymous user

2 years ago

Hi, which parts of code i do need to replace if I have LCD shield with KEYPAD. ? I was desperately looked for the watch like this for several years. And I still have 3 spare butons, the 6th button RESET is not defined here. Buttons defined: (where i would like to have your 3 butons). pls help :) int rk=analogRead(0); //UNO //DUE if(rk<50) {MINUTE_BUTTON;} //50 //75 else if(rk<195) {HOUR_BUTTON;} //195 //295 else if(rk<380) { ;} //380 //575 else if(rk<555) {MODE_BUTTON;} //555 //840 else if(rk<790) { ;} //790 //1023 //RESET NOT DEFINED

paulsb

2 years ago

Hi Sorry I am not really sure what you are asking. If it is to code the buttons then I think all you need do is replace the test for WHICHEVER_BUTTON == LOW with a test to achieve recognition of your button. E.g. for MODE_BUTTON replace if (digitalRead(MODE_BUTTON) == LOW) { ... } with if ((rk < 555) && (rk > 379)){ ... } But I have not used this display so I cannot check if that is right. Paul

Anonymous user

2 years ago

greetings sir, I really appreciate your projects, how can I add AM or PM function automatically in this clock could you tell me, please ??

paulsb

2 years ago

Hi Sorry I have not been on here for a while. To show AM/PM you just need to check if iHours is > 12 in ShowTime(). If it is then deduct 12 from it and show it as pm, otherwise show it as am. Here is the replacement ShowTime() code that does this. void ShowTime(unsigned long value) { // Alternative to show am/pm // Update display once a second // or when rolls over midnight String ampm; if ((value > lastTime + 1000) || (value < lastTime)) { lastTime = value; unsigned long iHours; unsigned long iMinutes; unsigned long iSeconds; SplitTime(value, iHours, iMinutes, iSeconds); // Display the time on line 0 lcd.setCursor(0, 0); if (iHours > 12) { iHours = iHours - 12; ampm = "pm"; } else { ampm = "am"; } lcd.print("Time: " + FormatNumber(iHours) + ":" + FormatNumber(iMinutes) + ":" + FormatNumber(iSeconds) + ampm); } }

Anonymous user

2 years ago

I'm new to this and have made an alteration to the ShowTime function to convert the output to 12hr time. While experienced folk could probably acheive this with less code, my solution seems to work fine. Replace the ShowTime() function with the following. void ShowTime(unsigned long value) { // Update display once a second // or when rolls over midnight if ((value > lastTime + 1000) || (value < lastTime)) { String amPm; lastTime = value; unsigned long iHours; unsigned long iMinutes; unsigned long iSeconds; unsigned long theHour; SplitTime(value, iHours, iMinutes, iSeconds); switch (iHours) { case 0: // It's 12 oclock am theHour = 12; amPm = "am"; break; case 1: // It's 1 oclock am theHour = 1; amPm = "am"; break; case 2: // It's 2 oclock am theHour = 2; amPm = "am"; break; case 3: // It's 3 oclock am theHour = 3; amPm = "am"; break; case 4: // It's 4 oclock am theHour = 4; amPm = "am"; break; case 5: // It's 5 oclock am theHour = 5; amPm = "am"; break; case 6: // It's 6 oclock am theHour = 6; amPm = "am"; break; case 7: // It's 7 oclock am theHour = 7; amPm = "am"; break; case 8: // It's 8 oclock am theHour = 8; amPm = "am"; break; case 9: // It's 9 oclock am theHour = 9; amPm = "am"; break; case 10: // It's 10 oclock am theHour = 10; amPm = "am"; break; case 11: // It's 11 oclock am theHour = 11; amPm = "am"; break; case 12: // It's 12 oclock am theHour = 12; amPm = "pm"; break; case 13: // It's 1 oclock pm theHour = 1; amPm = "pm"; break; case 14: // It's 2 oclock pm theHour = 2; amPm = "pm"; break; case 15: // It's 3 oclock pm theHour = 3; amPm = "pm"; break; case 16: // It's 4 oclock pm theHour = 4; amPm = "pm"; break; case 17: // It's 5 oclock pm theHour = 5; amPm = "pm"; break; case 18: // It's 6 oclock pm theHour = 6; amPm = "pm"; break; case 19: // It's 7 oclock pm theHour = 7; amPm = "pm"; break; case 20: // It's 8 oclock pm theHour = 8; amPm = "pm"; break; case 21: // It's 9 oclock pm theHour = 9; amPm = "pm"; break; case 22: // It's 10 oclock pm theHour = 10; amPm = "pm"; break; case 23: // It's 11 oclock pm theHour = 11; amPm = "pm"; break; } // Display the time on line 0 lcd.setCursor(0, 0); lcd.print("Time: " + FormatNumber(theHour) + ":" + FormatNumber(iMinutes) + ":" + FormatNumber(iSeconds)+ "" + amPm); } } I hope this works for you.

Anonymous user

2 years ago

This is very impressive. Thanks for sharing. I presumed (wrongly) that the time lost would be random.

paulsb

2 years ago

Thanks. I have now had the clock running for 2 weeks and it has gained 1 second, taking the reading at the same time each day so at the same point after the speed adjustment is made. I feel his definitely confirms that the internal clock is consistent. I am going to change the speed adjustment by 3 milliseconds to compensates for the gain and hopefully increase the accuracy,

Anonymous user

2 years ago

Hey I was wondering if you could make the SCHEMATICS usable to Arduino Uno R3. You said in components and supplies you could use any Arduino. Thank You So Much

paulsb

2 years ago

Hi. The Uno R3 has a similar pin configuration to the Nano and the labels are the same. Look at the circuit diagram to see the pins that the wires are connected to and simply connect to the same pins on the UNO. Hope this helps.

frenchy22

2 years ago

Hello, Very nice project, but I think that, instead of replacing the millis() function by an interrupt and of rewriting the delay() function, it is possible to take into account the rolling out of the millis() function every 50 days by the following code : [code] unsigned long actualTime, lastTime, elapsedTime; ... actualTime=millis(); if (actualTime < lastTime) // The millis counter has rolled out elapsedTime=0xFFFFFFFFul-lastTime+actualTime; else elapsedTime=actualTime-lastTime; [/code] And you reset the delay when you want by copying actualTime into lastTime.

paulsb

2 years ago

Hi, Many thanks for your suggestions.

paulsb

2 years ago

HI, I have looked further into your suggestion and the issue is the clock speed adjustment and the setting of the actual time. As you cannot amend Mills() you would need to accumulate the speed adjustment to reflect the variation from true milliseconds elapsed. This would eventually exceed the maximum value for the variable - mind you after a very very very long time. As millis() only counts the milliseconds since power up, you would also need to keep track of the time after midnight that the system was powered up to show the real time represented by the elapsed millis() and adjust this when set time is used. This adjustment could possibly be merged with the cumulative speed adjustment, but it becomes messy. I therefore feel that using the interrupt and our own counter is cleaner and simpler.

Anonymous user

2 years ago

How connect the LCD with i2c Connection?

paulsb

2 years ago

Hi, I have not used an LCD with an i2c connection, however there are a number of tutorials showing how to use it with an Arduino. I believe you need to connected the SDA and SCL connections to pins A4 and A5 and use the following libraries: Wire.h LiquidCrystal_I2C.h You also have to find out the address that the LCD is using - again see the tutorials (Common addresses are 0x3F and 0x27.), and initialise it with the correct address, eg for 0x3F: LiquidCrystal_I2C lcd ( 0x3F , 16 , 2 ) ; You may also need to make minor changes to the lcd commands.

Anonymous user

2 years ago

Like you said "it appears that the inaccuracy is consistent" , I can assure you that you are correct. I have a similar clock setup running for 7 years ( Big 7 seg display with arduino). Ever after software correction for lost time, it slows down 10 minutes every 6 months.

Nelson_Lee

2 years ago

Hello. Thanks for sharing your project. I have been studying your code because I wanted to make a project that needs to perform some tasks some days in a week at set times. I am stuck the part of you calculating the Julian date. Can you please share the source or explain how you get the formula of the conversion? I tried googling but what I managed to find doesn't seem to match up to your formula.

Anonymous user

3 years ago

greetings sir, I really appreciate your projects, how can I add AM or PM function automatically in this clock could you tell me, please ??

paulsb

2 years ago

Hi Sorry I have not been on here for a while. To show AM/PM you just need to check if iHours is > 12 in ShowTime(). If it is then deduct 12 from it and show it as pm, otherwise show it as am. Here is the replacement ShowTime() code that does this. void ShowTime(unsigned long value) { // Alternative to show am/pm // Update display once a second // or when rolls over midnight String ampm; if ((value > lastTime + 1000) || (value < lastTime)) { lastTime = value; unsigned long iHours; unsigned long iMinutes; unsigned long iSeconds; SplitTime(value, iHours, iMinutes, iSeconds); // Display the time on line 0 lcd.setCursor(0, 0); if (iHours > 12) { iHours = iHours - 12; ampm = "pm"; } else { ampm = "am"; } lcd.print("Time: " + FormatNumber(iHours) + ":" + FormatNumber(iMinutes) + ":" + FormatNumber(iSeconds) + ampm); } }

willois

2 years ago

I'm new to this and have made an alteration to the ShowTime function to convert the output to 12hr time. While experienced folk could probably acheive this with less code, my solution seems to work fine. Replace the ShowTime() function with the following. void ShowTime(unsigned long value) { // Update display once a second // or when rolls over midnight if ((value > lastTime + 1000) || (value < lastTime)) { String amPm; lastTime = value; unsigned long iHours; unsigned long iMinutes; unsigned long iSeconds; unsigned long theHour; SplitTime(value, iHours, iMinutes, iSeconds); switch (iHours) { case 0: // It's 12 oclock am theHour = 12; amPm = "am"; break; case 1: // It's 1 oclock am theHour = 1; amPm = "am"; break; case 2: // It's 2 oclock am theHour = 2; amPm = "am"; break; case 3: // It's 3 oclock am theHour = 3; amPm = "am"; break; case 4: // It's 4 oclock am theHour = 4; amPm = "am"; break; case 5: // It's 5 oclock am theHour = 5; amPm = "am"; break; case 6: // It's 6 oclock am theHour = 6; amPm = "am"; break; case 7: // It's 7 oclock am theHour = 7; amPm = "am"; break; case 8: // It's 8 oclock am theHour = 8; amPm = "am"; break; case 9: // It's 9 oclock am theHour = 9; amPm = "am"; break; case 10: // It's 10 oclock am theHour = 10; amPm = "am"; break; case 11: // It's 11 oclock am theHour = 11; amPm = "am"; break; case 12: // It's 12 oclock am theHour = 12; amPm = "pm"; break; case 13: // It's 1 oclock pm theHour = 1; amPm = "pm"; break; case 14: // It's 2 oclock pm theHour = 2; amPm = "pm"; break; case 15: // It's 3 oclock pm theHour = 3; amPm = "pm"; break; case 16: // It's 4 oclock pm theHour = 4; amPm = "pm"; break; case 17: // It's 5 oclock pm theHour = 5; amPm = "pm"; break; case 18: // It's 6 oclock pm theHour = 6; amPm = "pm"; break; case 19: // It's 7 oclock pm theHour = 7; amPm = "pm"; break; case 20: // It's 8 oclock pm theHour = 8; amPm = "pm"; break; case 21: // It's 9 oclock pm theHour = 9; amPm = "pm"; break; case 22: // It's 10 oclock pm theHour = 10; amPm = "pm"; break; case 23: // It's 11 oclock pm theHour = 11; amPm = "pm"; break; } // Display the time on line 0 lcd.setCursor(0, 0); lcd.print("Time: " + FormatNumber(theHour) + ":" + FormatNumber(iMinutes) + ":" + FormatNumber(iSeconds)+ "" + amPm); } } I hope this works for you.

Anonymous user

4 years ago

Hi, which parts of code i do need to replace if I have LCD shield with KEYPAD. ? I was desperately looked for the watch like this for several years. And I still have 3 spare butons, the 6th button RESET is not defined here. Buttons defined: (where i would like to have your 3 butons). pls help :) int rk=analogRead(0); //UNO //DUE if(rk<50) {MINUTE_BUTTON;} //50 //75 else if(rk<195) {HOUR_BUTTON;} //195 //295 else if(rk<380) { ;} //380 //575 else if(rk<555) {MODE_BUTTON;} //555 //840 else if(rk<790) { ;} //790 //1023 //RESET NOT DEFINED

paulsb

2 years ago

Hi Sorry I am not really sure what you are asking. If it is to code the buttons then I think all you need do is replace the test for WHICHEVER_BUTTON == LOW with a test to achieve recognition of your button. E.g. for MODE_BUTTON replace if (digitalRead(MODE_BUTTON) == LOW) { ... } with if ((rk < 555) && (rk > 379)){ ... } But I have not used this display so I cannot check if that is right. Paul

Anonymous user

4 years ago

not sure if i've understood this or not. are you using the pc clock to correct the arduino time?

paulsb

2 years ago

Hi, No. The link to the PC is only an initial process to calculate the amount by which the Arduino clock is out. Either running fast or slow. That value is entered as the initial setting of the speedCorrection variable. The clock then runs independently making this speed correct adjustment each hour.

KetanMiyatra

4 years ago

How connect the LCD with i2c Connection?

paulsb

2 years ago

Hi, I have not used an LCD with an i2c connection, however there are a number of tutorials showing how to use it with an Arduino. I believe you need to connected the SDA and SCL connections to pins A4 and A5 and use the following libraries: Wire.h LiquidCrystal_I2C.h You also have to find out the address that the LCD is using - again see the tutorials (Common addresses are 0x3F and 0x27.), and initialise it with the correct address, eg for 0x3F: LiquidCrystal_I2C lcd ( 0x3F , 16 , 2 ) ; You may also need to make minor changes to the lcd commands.

Anonymous user

4 years ago

Hey I was wondering if you could make the SCHEMATICS usable to Arduino Uno R3. You said in components and supplies you could use any Arduino. Thank You So Much

paulsb

2 years ago

Hi. The Uno R3 has a similar pin configuration to the Nano and the labels are the same. Look at the circuit diagram to see the pins that the wires are connected to and simply connect to the same pins on the UNO. Hope this helps.

Anonymous user

4 years ago

This is very impressive. Thanks for sharing. I presumed (wrongly) that the time lost would be random.

paulsb

2 years ago

Thanks. I have now had the clock running for 2 weeks and it has gained 1 second, taking the reading at the same time each day so at the same point after the speed adjustment is made. I feel his definitely confirms that the internal clock is consistent. I am going to change the speed adjustment by 3 milliseconds to compensates for the gain and hopefully increase the accuracy,

Anonymous user

4 years ago

Hi, I Have Successfully Adjusted The Time And Date But Can't Adjust The Year. Please Help Me Out. I Am Making This In TinkerCAD. (I Am Also Running A LED Dot Matrix Clock So I Can't Make It Now)

Anonymous user

2 years ago

Umm, I Simulated It, I Felt Lazy To Make It In Real Life. ( I Copy Pasted The Code In TinkerCAD)

paulsb

2 years ago

Hi, Difficult to advise without more information. When you say you cannot set the year, what is happening? Are you just not seeing the option or is it showing and you cannot change it? Did you type in the code or copy and paste it? I would check the code to make sure there is not an error in it. Paul

frenchy22

4 years ago

Hello, Very nice project, but I think that, instead of replacing the millis() function by an interrupt and of rewriting the delay() function, it is possible to take into account the rolling out of the millis() function every 50 days by the following code : [code] unsigned long actualTime, lastTime, elapsedTime; ... actualTime=millis(); if (actualTime < lastTime) // The millis counter has rolled out elapsedTime=0xFFFFFFFFul-lastTime+actualTime; else elapsedTime=actualTime-lastTime; [/code] And you reset the delay when you want by copying actualTime into lastTime.

paulsb

2 years ago

Hi, Many thanks for your suggestions.

paulsb

2 years ago

HI, I have looked further into your suggestion and the issue is the clock speed adjustment and the setting of the actual time. As you cannot amend Mills() you would need to accumulate the speed adjustment to reflect the variation from true milliseconds elapsed. This would eventually exceed the maximum value for the variable - mind you after a very very very long time. As millis() only counts the milliseconds since power up, you would also need to keep track of the time after midnight that the system was powered up to show the real time represented by the elapsed millis() and adjust this when set time is used. This adjustment could possibly be merged with the cumulative speed adjustment, but it becomes messy. I therefore feel that using the interrupt and our own counter is cleaner and simpler.

Anonymous user

4 years ago

Like you said "it appears that the inaccuracy is consistent" , I can assure you that you are correct. I have a similar clock setup running for 7 years ( Big 7 seg display with arduino). Ever after software correction for lost time, it slows down 10 minutes every 6 months.