3

I programmed Arduino UNO R3 to trigger a relay once every 24 hours from the moment it is powered on

I calculated milliseconds and used the function delay()

24 hours * 60 minutes each hour * 60 second every minute * 1000 milliseconds every second

so i used :

delay(86400000)

86 million and 400 thousands milliseconds

and currently i'm still testing it... Will this work? If not Is there a better built-in function/library or even external library to do it?

the relay trigger doesn't have to be very accurate at the very exact time each day I don't need it to be very accurate, It can shift few minutes every few months or so, thats okay with me

But how about after few months or years of use ? Will it shift the timing much ? I read somewhere about using millis() function and others use RTC (Real Time Clock) module

I don't want to use RTC module Looking for a programmatical solution... OR if my previous method using the delay() will work for such a very high number of millisecond ?

Thank you

  • 2
    “Few minutes every few months” is about 20 ppm. You can expect close to 1,000 ppm clock drift on the Uno. Even if you calibrate out the drift, frequency wander will likely defeat your calibration to worse than 20 ppm in a day or so. You really need an RTC for meeting your accuracy requirement. See Arduino clock frequency accuracy for a detailed experimental analysis on the frequency stability of the Arduino (the Uno has a resonator similar to the one on the Pro Mini). – Edgar Bonet Sep 2 at 20:36
  • So, No programmatical solution, it must be a hardware solution for this, by using an RTC external module or maybe by making my own pcb circuit installing a crystal oscillator on it and connecting it to the arduino digital pin output ? And the link you posted is very useful thank you, I'm going to read it. I don't want to use an RTC so i don't have to change the battery every while, Or can i just connect the battery socket to the arduino 3.3v dc power pin? Thank you very much Edgar, Greatly Appreciated – Felix0004 Sep 4 at 8:51
  • 1
    The 3.3V pin of the Uno is a power output, you cannot power your Arduino through it. If you replace the Arduino by a bare ATmega on your own PCB, you can replace the resonator by a 16 MHz crystal oscillator. It may still drift too much, but the drift rate will be consistent and you can calibrate it out. Alternatively, clock the ATmega off its internal RC oscillator, and plug a clock crystal into the TOSC pins of its asynchronous timer. Used this way, the asynchronous timer is like an RTC built into the ATmega. – Edgar Bonet Sep 4 at 9:27
  • Thank you Edgar for your very informative inputs, contributions and your very kind help. I will research your idea more deeply and try to apply it practically soon. and yes the 3.3 v arduino pin is power output i mean to use it to power the RTC module not to power the arduino, I found a local supply that have 3 different models of RTC modules, PCF8523, DS1307 and DS3231 and DS1302 IC only and DS1307 8 dip package IC, I made some research and found that DS3231 is the most accurate with high precision because it has temperature sensor that adjust any timing drift/shift periodically – Felix0004 Sep 5 at 8:40
3

Yes, the delay() will work, as will other methods based on the millis() counter. However, delay() will make it impossible to do something else in the meantime.

Look up Blink without delay for an example of how to accomplish such a delay while being able to do other things in your code while waiting.

Casting

When dealing with large numbers such as your 24-hour delay, make sure to explicitly cast those numbers as unsigned long, or expressing them with the "UL" extension (like for example 86400000UL). This explicitly tells C++ to expect an "unsigned long" (which in Arduino Uno terms is a 32-bit unsigned number).

In your case (with such an obviously large number), the compiler will automatically choose the right type. In other cases (for example, if you change the expression to 24*60*60*1000), the compiler will not automatically generate an unsigned long and you need to force it by changing the first part of the expression to an unsigned long: 24UL*60*60*1000 or, alternatively (unsigned long) 24*60*60*1000.

Accuracy

The accuracy of the timing will be dependent on the type of oscillator on your particular Arduino board. Many Arduinos or their clones use a Ceramic Oscillator that generally have an accuracy of about 0.1 to 0.5%, meaning a possible deviation of 43 seconds per day and as such maybe too inaccurate for your purposes. If your Arduino has a Crystal oscillator, it will be much more accurate (to something like 150ppm, meaning a maximum deviation of about 1 second per day under normal conditions).

| improve this answer | |
  • 1
    Thank you very much StarCat I have arduino uno R3 (revision three) and I see a rectangular crystal on the board, So I guess its as accurate as you described....1 second per day thats around 365 seconds ( 6 minutes) per year...so thats fine. And I will use the UL Unsigned Long extension on my code..better, Even if it works with normal delay() without assigning this data type. I Appreciate your input And the article link you posted about doling multiple things at once while program wait is very helpful, Thank you very much – Felix0004 Sep 2 at 17:00
  • 1
    The "UL" suffix is not needed, as the compiler will pick a data type large enough to hold the value. It is needed though, at least for the first factor, if you want to write an expression like 24UL * 60 * 60 * 1000. – Edgar Bonet Sep 2 at 20:18
  • 2
    @EdgarBonet, That's true of course. My opinion is that explicitly casting, where appropriate, doesn't hurt and will prevent hard to find errors in cases where it's not so clear-cut (like in your example). I've expanded the explanation in the answer. – StarCat Sep 3 at 7:51
  • Update: I tested the project for a full 24 hours from 9:03 PM Wednesday evening since i powered the arduino on to the next day thursday evening and i noticed it shifted/delayed around 3 minutes, cause it triggered the relay at around 9:06 PM (so thats around 3 mins delay) so 3 mins shift * 30 days a month = 90 mins (an hour and a half timing shift each month) I'm going to test it for another 24 hours now and see... – Felix0004 Sep 4 at 8:55
3

delay() takes an unsigned long; I think what you do will work.

When in doubt, you could always do something like this:

for (int hours = 0; hours < 24; hours++) {
  for (int mins = 0; mins < 60; mins++) {    
    for (int secs = 0; secs < 60; secs++) {  
      delay(1000);                                    
    }
  }
}

It will be wildly inaccurate though, because the clock is inaccurate and will also drift with temperature, made worse because a resonator is used instead of a crystal.

You will get nowhere near an accuracy of a few minutes per month this way, whatever "delaying" method you use; the hardware isn't up to it.

| improve this answer | |
  • Thank you very much ocrdu I have arduino uno R3 (revision three) and I see a rectangular crystal on the board, So I guess its more accurate? – Felix0004 Sep 2 at 16:56
  • 2
    As far as I know, the UNO R3 also has a resonator on the board for the CPU, and the crystal is used for the USB timing only. This may be different between revisions of the board. Still, even with a crystal, I doubt you will get the accuracy you want. – ocrdu Sep 2 at 17:10
  • 1
    Well, what I would do is just try it with a time of, say, two hours (or however long you can be bothered to observe the thing), see if it is close enough, and if not, introduce a calibration factor in the code to compensate. Measuring equipment would make this an easier process. If it turns out you can't properly adjust that way because of clock instability, you can always add a precise RTC module. Primitive engineering, maybe, but worth a shot. – ocrdu Sep 2 at 18:51
  • 3
    1. Re “I think what you do will work”: It will. delay() can handle up to ULONG_MAX milliseconds, which is about 49.7 days. 2. Re “introduce a calibration factor”: if the experiment is performed in just a few hours, this will likely work. But then frequency wander will defeat the calibration at longer time scales. You can expect the clock frequency to “random walk” with a typical √t law at time scales longer than a few seconds. – Edgar Bonet Sep 2 at 20:51
  • 1
    @Felix0004: 3 minutes in one day is 3×60÷86400 ≈ 0.002, or 2,000 ppm. Kind of high, but still within the tolerance of a typical ceramic resonator. – Edgar Bonet Sep 4 at 9:26
1

You could try enclosing the Uno in a temperature controlled "oven", say a plastic enclosure with a very low power heater (even a suitable resistor might do) and thermo sensor in with it. It should reduce some of the variation in the crystal frequency.

| improve this answer | |
  • But i can't Apply the heat permanently to the uno, i wanted a permanent solution : ) Thank you JRobert – Felix0004 Sep 4 at 9:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.