Hello. I am new to Arduino and decided to create date and time on display from scratch. Of course I could use some built-in libraries, but the point is not that. Now when the program is finished I want to set clock precision. For now in TinkerCad I see about 1 second decline after the first twenty minutes of clock run interval (I compare it to online stopwatch). Also I use 1 second delay every minute to let display clear and highlight, but I don't know what is the real time of it in reality. What should I do? How can I make the clock work with more precision? Here is the link to my tinkercad project: Login | Tinkercad
What is the point of having a simulation act as an accurate real time clock?
To make an accurate clock, you need an accurate time base. Out of the box, Arduinos don't have accurate time bases, so they aren't much better than a simulation.
Aside: don't confuse precision with accuracy. The terms have different meanings.
Please share what is the purpose of this project. Is it for educational purpose? The Real clock usually shall preserve time when power disconnected. I would suggest shield with RTC chip and backup battery. Like this: shield
jremington, frpr666, thank you for your replies. It's for educational purposes and as a part of present I wanted to create and as a future robot module as well. I just wonder what I should do to make a real clock like I have on a computer, for example. Is that actually possible?
For Arduino, buy a DS3231 RTC module (which provides the accurate time base) and connect it according to one of the many on line tutorials. It is a very popular project!
If you code a clock just relying on the speed of the code and the use of delay(), you won't get much accuracy.
It is possible to code a clock that will be as accurate as the clock oscillator that runs the microprocessor, that is the element that makes it go at a certain speed.
That method will result in a more consistent clock, but it may be consistently fast or slow. There are methods simple as well as not so simple that can compensate for the inherent slow or fastness of that oscillator.
Some Arduinos have better clocks than others.
All very possible and a certain kind of fun. Google and ask for help if you find you like the idea but can't catch enough clues about the path you will have chosen.
By far the easiest is to use an RTC as has been suggested. They are very accurate out if the box.
a7
For now I passed the project from TinkerCad to Arduino IDE with LCD1602 display and just delay((long)60 * 1000) function is quite precise for already half an hour. So, may be, it will stay so for a longer period of time. And I will regard RTC as an option in case I will have to. Thank you all very much for your replies.
You would be better off using millis() for timing, delay() does not take into account the time it takes for all the other code in your sketch.
david_2018, thank you for your reply. Ok, I will do that after my attempt with delay() is completed in reality. At the moment the clock has been working with 9V battery and Arduino and I will wait for tomorrow to see the results.
While it is true there are ways to improve a software clock, which I will call what you have done, there are also rude hacks.
Since the operations the sketch will perform are exactly the same every day, you could look to see how far off you are at, say three AM in the morning and just fix it.
You might be 22 seconds fast or 15 seconds slow, but that will be fairly consistent enough, varying mostly with temperature.
So,if you can live with the error if it got fixed once a day, think about that.
Of course we all want you to do it in more complicate ways. Anything based on the build in oscillator dictating the timing will eventually have some kind of error correcting mechanism- the slick ones might be adding or subtracting tenths of seconds very more frequently than once a day.
Either explicitly or in effect do to the counting algorithm used.
I did a software clock that received the time of day at irregular and sometimes infrequent intervals, but it used any new perfect time it learned about to adjust its effective speed.
Very nicely accurate.
a7
I submit it would be better to delete "complicated" and insert "sensible". Installing a DS3231 RTC and getting it right first time is not complicated and beats the hell out of fartarsing about trying write compensations into a software clock - and all to save about $3.50. I also submit the OP already knows all he needs to know about software clocks, and only needs to know that using an RTC is cheap, obvious, and lot simpler than he seems to think it is.
I also note that nobody wants to point out the real villain - Arduino's software clock has no temperature compensation, and writing software to compensate for the vaguaries of the weather is probably not such a great idea.
Thank you all for your replies. I have used RTC DS1302 and the problem was actually solved. But how accurate it will be and for how long? What does it really depend on and to what online clock I can compare it to as to an etalon of time? They promise accuracy of about plus or minus 2 minutes per year. Is that actually true? How may I achieve any better results?
Hello there. Though I use RTC library for DS1302 I noticed some inaccuracies after three hours of testing (about 1 second) and at the very start the second time I tried to make some tests I got 1 second again. Would you, please, tell me are there any factors that may influence it anyhow? What major steps I should fulfill to make it absolutely precise for at least one day? Any tricks, better RTC libraries or anything else which may change it to better precision? They promised 2 minutes per year error, but I had already had one second after three hours which does not fit to that evaluation.
What etalon should I use to test it properly? Maybe, it's etalon itself which gives that error?
Hello fixer_84
Take a search engine of your choice and ask the WWW for 'Accuracy / deviation of DS1302 and DS1307' to collect some data to be sorted out to get the needed information.
Have a nice day and enjoy coding in C++.
paulpaulson, thank you very much for your reply. I will definitely look through those parameters to make my own evaluation and compare it according to the present results. Have a nice day, too.
A RTC module for time projects was what I did a decade ago. I now use an ESP8266 WiFi board for that. No more setting of the time, or changing the time every half a year for daylight savings.
ESP8266 software has built-in code for time. You just have to tell it which timeserver you want to get the time from, and where on the planet you live, for GMT offset and daylight savings.
The ESP has a good enough crystal clock to keep time between NTP updates.
You still can add a RTC for those portable projects, what a laptop and cellphone also do.
Leo..
The Arduino preprocessor has trouble with your sketch. If I set the value of 'time' and 'd_count' in setup(), then the preprocessor accepts it.
#include <LiquidCrystal_I2C.h>
const int N = 6;
const int M = 7;
const int SIZE = 12;
const int LIMIT = 365;
const int YEAR = 2023;
String days[M] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
int month[SIZE] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int shift[SIZE] = { 6, 2, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
int minutes = 0;
int curr;
int d_count;
String time;
LiquidCrystal_I2C lcd(0x27, 16, 2); // Address = 0x27
void setup() {
//Serial.begin(115200);
lcd.init();
lcd.backlight();
d_count = dateToDays("30-07-2023"); // Any date for year 2023
time = "00:00"; // Any time from 00:00 to 23:59
}
void loop() {
lcd.clear();
curr = timeToMin(time) + minutes;
if (curr / 60 == 24) {
minutes = 0;
time = "00:00";
curr = timeToMin(time);
d_count++;
}
if (d_count > LIMIT) {
lcd.clear();
lcd.print("HAPPY NEW YEAR!");
} else {
printDateAndTime(d_count, curr);
printWeekday(d_count);
}
minutes++;
delay((long)60 * 1000); //Update display every minute
}
int getDay(int num) {
int sum = 0;
for (int i = 0; i < SIZE; i++) {
sum += month[i];
if (num <= sum) {
sum -= month[i];
break;
}
}
return (num - sum);
}
int getMonth(int num) {
int sum, m_index;
sum = m_index = 0;
for (int i = 0; i < SIZE; i++) {
sum += month[i];
if (num <= sum) {
m_index = i;
break;
}
}
return m_index + 1;
}
String getHour(int h) {
String hh;
if (h < 10) {
hh = "0" + String(h);
} else {
hh = String(h);
}
return hh;
}
String getMinute(int m) {
String mm;
if (m < 10) {
mm = "0" + String(m);
} else {
mm = String(m);
}
return mm;
}
String getDate(int num) {
String dd, mm;
int d = getDay(num);
int m = getMonth(num);
if (d < 10) {
dd = "0" + String(d);
} else {
dd = String(d);
}
if (m < 10) {
mm = "0" + String(m);
} else {
mm = String(m);
}
String dt = (dd + "-" + mm + "-" + YEAR);
return dt;
}
String getWeekDay(int n) {
int mat[SIZE][N][M] = { 0 };
int d = getDay(n);
int m = getMonth(n);
int index, count;
for (int k = 0; k < SIZE; k++) {
count = 0;
bool flag = false;
for (int i = 0; i < N; i++) {
for (int j = (i == 0 ? shift[k] : 0); j < M; j++) {
count++;
mat[k][i][j] = count;
if (count == month[k]) {
flag = true;
break;
}
}
if (flag) {
break;
}
}
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (mat[m - 1][i][j] == d) {
index = j;
break;
}
}
}
return days[index];
}
//Output date and time
void printDateAndTime(int n, int curr) {
lcd.setCursor(0, 0);
lcd.print(getDate(n));
lcd.print(" ");
lcd.print(getHour(curr / 60));
lcd.print(":");
lcd.print(getMinute(curr % 60));
}
void printWeekday(int n) {
lcd.setCursor(0, 1);
lcd.print(getWeekDay(n));
}
//Turn time into minutes
int timeToMin(String str) {
String h, m;
h = str.substring(0, 2);
m = str.substring(3, 5);
return h.toInt() * 60 + m.toInt();
}
//Turn date into days
int dateToDays(String str) {
int d, m, sum;
d = str.substring(0, 2).toInt();
m = str.substring(3, 5).toInt();
sum = 0;
for (int i = 0; i < m - 1; i++) {
sum += month[i];
}
return (sum + d);
}
Using a delay() is not code that can be maintained. If you add something or a new version of the compiler is used, then it might change.
Using a millis() timer is exactly as accurate as the 16MHz resonator/crystal. The Arduino Leonardo (and Micro) have a crystal. Some clones have a crystal. That is good. Many boards have a resonator, that is not good enough.
unsigned long previousMillis;
const unsigned long interval = 1000;
void loop()
{
unsigned long currentMillis = millis();
if(currentMillis - previousMillis >= interval)
{
previousMillis += interval; // for a accurate millis timer
// code that runs once per second
...
}
}
Never use the DS1302, it is not reliable.
The DS3231 is very good, unless you buy a cheap module that has a reject DS3231 or counterfeit DS3231 and the rechargeable battery will be overcharged when used with 5V.
The reject DS3231 is still better than a DS1307 though ![]()
The DS1307 is good, unless you buy a cheap module that has a crystal that stops working at freezing temperatures or the cheap crystal is unstable.
Koepel, thank you for your reply. I have already ordered DS3231 for the same reason (it's more reliable as others and has got good ppm). As soon as I get it I will make a test on its accuracy to confirm that. Suddenly I reliazied it's a bad idea to write my own modules as I have not enough knowledge yet to do that. There is a plenty of built-in libraries that can manage to do that with much less code (memory consumption is only 32kB for Arduino UNO which I use, though there are ones that have 1Mb maximum such Arduino Nano 33 BLE). And thank you all again for your support.
There are time libraries that are known to work, so you don't have to worry if you did it right.
Good old Arduino time libraries:
TimeLib: https://github.com/PaulStoffregen/Time
Adafruit RTClib: https://github.com/adafruit/RTClib
Some processors have a RTC inside the processor. For some of those is a Arduino library available.
The standard 'C' time library was not compatible with Arduino in the past, but I think that it is compatible now.
If a board has internet connection (ESP32, Raspberry Pi Pico W), then it can retrieve the time from a time server, as Wawa wrote in post #18.
There are enough good options.