I need to delay an action by between 20 to 120 seconds on a esp32. I understand the millis() function can do this but I am unsure how the 49 day roll over works. It is my understanding that there is no telling what the initial value is. It is only used as a reference to compare against. If that assumption is true one could see a roll over at anytime. How is this handled or am I look at this wrong?
millis() rollover for a 20 - 120 seconds interval is NO PROBLEM.
It was discussed and demonstrated hundred times here in this forum.
Use the unsigned subtraction like shown in the "Blink Without Delay" example and it will work.
If you would like to know more about how and why ... search for "millis rollover" - in my opinion everthing was already said and written to that topic.
As long as you use subtraction to determine whether the timing period has elapsed as in
currentTime = millis();
if (currentTime - periodStartTime >= requiredPeriod)
{
//do something
periodStartTime = currentTime;
}
then the rollover to zero will not cause any problem whenever it happens as long as the variables used in the comparison are unsigned
Thanks
The initial value is 0
, and initialization occurs whenever the program is (re-)started. From the language reference for millis()
:
Returns the number of milliseconds passed since the Arduino board began running the current program.
You may be misinterpreting or misremembering. I think the point that was probably being aimed for is that… you never have to care what the value is, or where it starts. All you are exploiting is that it runs alla time counting off milliseconds. And differences between now and then.
Begin timing an interval by grabbing the value of millis(), later determine the elapsed time by subtracting that saved value from the current, new value returned by millis().
Rollover can be ignored until you are trying to handle very long intervals, like 49 days long, or maybe it's half that. In any case, an odd sketch that woukd attempt timing something that long using millis()…
a7
After uploading a sketch into Arduino UNO, the uploaded sketch begins execution. At the same time, a 32-bit (Fig-1) millisCounter with zero intial value starts counting up (on interrupt) every milli-second tick generated by TC0.
Figure-1:
Intial value/count of the milliscounter = 0x00000000 = 0 ms
Maximum value/count of the millisCounter = 0xFFFFFFFF = 4294967295 ms
Full value/count = 0x100000000 = 4294967296 ms
From the above, we observe that the millisCounter undergoes rollover (an event that occurs when millisCounter value turns from all 1s to all 0s) at the end of 4294967296 ms (49 days 17 hrs 2 min 47 sec 296 ms).
The content of millisCounter can be read at any time on-the-fly (without disturbing the counting process) by executing Arduino's millis() function. The millis() function returns an accumulated time (in ms) that has elapsed since the Arduino has started executing the uploaded sketch.
Reading the millisCounter by millis()
function gives the present/current reference time. Reading milliscounter after a while gives a time from which if reference time is subtracted, we get the timeDelay in between.
unsigned long timeDelay = 20000ul; //20-sec timeDelay
unsigned long presentTime = millis();//ref time > 0 can be printed
while(millis() - presentTime < timeDelay)
{
//do something else
}
//20-sec timeDelay has elapsed
The subtraction works fine until you fill up a 32 bit unsigned - 4294967295 ms - which is the famous 49 days 17 hrs 2 min 47 sec 295 ms.
You can’t represent waiting for more than that on an uint32_t
, if you write a literal like 100 days (8 640 000 000 ms) then you go into long long territory but the difference you calculate with millis()
and your start time will still be in unsigned long territory and thus you’ll never meet the condition.
So if you have to wait for more than 49 days, you need to Split the long waits into intervals under 49 days and count them.