millis_no_overflow


millis() and the overflow problem

In una precedente guida (https://www.realmeteo.com/arduino-english/millis/) we had seen how with the millis () function, it is possible to create non-blocking delays. We had also said that this function can be affected by an overflow problem, if our arduino is kept on for more than 49 days. This does not mean that the function has a bug, but simply that, in our common way of thinking, we are led to use it in the wrong way, and we do not notice it until after 49 days. But where does this come from, and how to avoid the problem? The first answer is simple, the counter that is automatically incremented every millisecond is a 32-bit register; this means that after 4,294,967,295 milliseconds, corresponding to 1193.05 hours, or 49.7 days, the counter resets and starts from zero.

Since this number is quite high for simple reasoning, I will articulate the description of the problem and the solution by pretending that the register has only 8 bits; in this fictitious case, the counter reaches 255 milliseconds and then starts over from zero.

I make a parenthesis of binary math on 8-bit numbers, where I repeat, the maximum representable number is 255, and then, if I add one, it starts from zero. So, just to give some examples of 8-bit operations, we will have these results: 20 + 10 = 30; 230 + 10 = 240; 245 + 10 = 255; 246 + 10 = 0; 247 + 10 = 1; 248 + 10 = 2; 254 + 10 = 8; 255 + 10 = 9; 0 + 10 = 10 .... but for subtractions it is the same thing, that is 9-10 = 255; 8-10 = 254; 2-10 = 248; 1-10 = 247 etc. etc.

If these things are clear let's start with the description of the problem, and on how to avoid it:
Let's imagine having to generate with Arduino, a 50Hz square wave, or toggle an output, which will be for 10 millieconds to 1 and for 10 milliseconds to 0.

In the following table we have, the flow of milliseconds in the first column, the cycle time in the second, the next goal in the third and fourth, the control operation that we are mistakenly led to do, to create the 10 millisecond delay. At first everything works fine, and every 10 milliseconds the comparison operation reverses the output, generating the square wave at 50Hz. Now let's move towards the nefarious event. At the 250 millisecond we have the last correct toggle, then at 251 we encounter the first problem, an unexpected toggle, and then another at 252, and still others, up to the 255 millisecond
But that's not enough ... a long period follows where there is no I'm toggle, and we arrive at 54 millis on the second lap, where everything falls into place.
So in reality we will have that the toggles are not regular, but only after 49 days !!!!


current millis TimeCycle NextDestination if (millis() >= NextDestination) YES NO
1 10 10 NO - continue
2 10 10 if (2 >= 10) NO - continue
3 10 10 if (3 >= 10) NO - continue
4 10 10 if (4 >= 10) NO - continue
5 10 10 if (5 >= 10) NO - continue
6 10 10 if (6 >= 10) NO - continue
7 10 10 if (7 >= 10) NO - continue
8 10 10 if (8 >= 10) NO - continue
9 10 10 if (9 >= 10) NO - continue
10 10 10 if (10 >= 10) YES - TOGGLE - NextDestination = NextDestination + TimeCycle
11 10 20 if (11 >= 20) NO - continue
12 10 20 if (12 >= 20) NO - continue
13 10 20 if (13 >= 20) NO - continue
14 10 20 if (14 >= 20) NO - continue
15 10 20 if (15 >= 20) NO - continue
16 10 20 if (16 >= 20) NO - continue
17 10 20 if (17 >= 20) NO - continue
18 10 20 if (18 >= 20) NO - continue
19 10 20 if (19 >= 20) NO - continue
20 10 20 if (20 >= 20) YES - TOGGLE - NextDestination = NextDestination + TimeCycle
21 10 30 if (21 >= 30) NO - continue
22 10 30 if (22 >= 30) NO - continue
23 10 30 if (23 >= 30) NO - continue
24 10 30 if (24 >= 30) NO - continue
25 10 30 if (25 >= 30) NO - continue
26 10 30 if (26 >= 30) NO - continue
27 10 30 if (27 >= 30) NO - continue
28 10 30 if (28 >= 30) NO - continue
29 10 30 if (29 >= 30) NO - continue
30 10 30 if (30 >= 30) YES - TOGGLE - NextDestination = NextDestination + TimeCycle
31 10 40 if (31 >= 40) NO - continue
32 10 40 if (32 >= 40) NO - continue
33 10 40 if (33 >= 40) NO - continue
34 10 40 if (34 >= 40) NO - continue
35 10 40 if (35 >= 40) NO - continue
36 10 40 if (36 >= 40) NO - continue
37 10 40 if (37 >= 40) NO - continue
38 10 40 if (38 >= 40) NO - continue
39 10 40 NO - continue
---- ---- ---- ----
241 10 250 if (241 >= 250) NO - continue
242 10 250 if (242 >= 250) NO - continue
243 10 250 if (243 >= 250) NO - continue
244 10 250 if (244 >= 250) NO - continue
245 10 250 if (245 >= 250) NO - continue
246 10 250 if (246 >= 250) NO - continue
247 10 250 if (247 >= 250) NO - continue
248 10 250 if (248 >= 250) NO - continue
249 10 250 if (249 >= 250) NO - continue
250 10 250 if (250 >= 250) YES - TOGGLE - NextDestination = NextDestination +TimeCycle
251 10 4 if (251 >= 4) YES - TOGGLE - NextDestination = NextDestination + TimeCycle
252 10 14 if (252 >= 14) YES - TOGGLE - NextDestination = NextDestination +TimeCycle
253 10 24 if (253 >= 24) YES - TOGGLE - NextDestination = NextDestination +TimeCycle
254 10 34 if (254 >= 34) YES - TOGGLE - NextDestination = NextDestination +TimeCycle
255 10 44 if (255 >= 44) YES - TOGGLE - NextDestination = NextDestination +TimeCycle
0 10 54 if (0 >= 54) NO - continue
1 10 54 if (1 >= 54) NO - continue
2 10 54 if (2 >= 54) NO - continue
3 10 54 if (3 >= 54) NO - continue
4 10 54 if (4 >= 54) NO - continue
5 10 54 if (5 >= 54) NO - continue
6 10 54 if (6 >= 54) NO - continue
7 10 54 if (7 >= 54) NO - continue
8 10 54 if (8 >= 54) NO - continue
9 10 54 if (9 >= 54) NO - continue
10 10 54 if (10 >= 54) NO - continue
11 10 54 if (11 >= 54) NO - continue
12 10 54 if (12 >= 54) NO - continue
13 10 54 if (13 >= 54) NO - continue
14 10 54 if (14 >= 54) NO - continue
15 10 54 if (15 >= 54) NO - continue
16 10 54 if (16 >= 54) NO - continue
17 10 54 if (17 >= 54) NO - continue
18 10 54 if (18 >= 54) NO - continue
19 10 54 if (19 >= 54) NO - continue
20 10 54 if (20 >= 54) NO - continue
21 10 54 if (21 >= 54) NO - continue
22 10 54 if (22 >= 54) NO - continue
23 10 54 if (23 >= 54) NO - continue
---- ---- ---- ----
49 10 54 if (49 >= 54) NO - continue
50 10 54 if (50 >= 54) NO - continue
51 10 54 if (51 >= 54) NO - continue
52 10 54 if (52 >= 54) NO - continue
53 10 54 if (53 >= 54) NO - continue
54 10 54 if (54 >= 54) YES - TOGGLE - NextDestination = NextDestination + TimeCycle
55 10 64 if (55 >= 64) NO - continue
56 10 64 if (56 >= 64) NO - continue
57 10 64 if (57 >= 64) NO - continue
58 10 64 if (58 >= 64) NO - continue
59 10 64 if (59 >= 64) NO - continue
60 10 64 if (60 >= 64) NO - continue
61 10 64 if (61 >= 64) NO - continue
62 10 64 if (62 >= 64) NO - continue
63 10 64 if (63 >= 64) NO - continue
64 10 64 if (64 >= 64) YES - TOGGLE - NextDestination = NextDestination + TimeCycle
65 10 74 if (65 >= 74) NO - continue
66 10 74 if (66 >= 74) NO - continue
67 10 74 if (67 >= 74) NO - continue
68 10 74 if (68 >= 74) NO - continue
69 10 74 if (69 >= 74) NO - continue
70 10 74 if (70 >= 74) NO - continue
71 10 74 if (71 >= 74) NO - continue
72 10 74 if (72 >= 74) NO - continue
73 10 74 if (73 >= 74) NO - continue
74 10 74 if (74 >= 74) YES - TOGGLE - NextDestination = NextDestination + TimeCycle
75 10 84 if (75 >= 84) NO - continue
76 10 84 if (76 >= 84) NO - continue
77 10 84 if (77 >= 84) NO - continue
78 10 84 if (78 >= 84) NO - continue
79 10 84 if (79 >= 84) NO - continue
80 10 84 if (80 >= 84) NO - continue
81 10 84 if (81 >= 84) NO - continue
82 10 84 if (82 >= 84) NO - continue
83 10 84 if (83 >= 84) NO - continue




Now the solution: instead of adding the cycle time to calculate the next goal, we need to think backwards, calculating the time elapsed with respect to the last event.

In the second table, unlike the first, the previous event is stored, and the correct comparison to be made is: if (millis () - PreviousEvent > = TimeCycle) YES TOGGLE - NO continue.

As we can see in the 8-bit simulation there are no irregularities and everything runs smoothly always and forever.


current millis TimeCycle PreviousEvent if (millis() - PreviousEvent >= TimeCycle) YES TOGGLE - NO continue
1 10 0 if (1 - 0) >= 10 NO - continue
2 10 0 if (2 - 0) >= 10 NO - continue
3 10 0 if (3 - 0) >= 10 NO - continue
4 10 0 if (4 - 0) >= 10 NO - continue
5 10 0 if (5 - 0) >= 10 NO - continue
6 10 0 if (6 - 0) >= 10 NO - continue
7 10 0 if (7 - 0) >= 10 NO - continue
8 10 0 if (8 - 0) >= 10 NO - continue
9 10 0 if (9 - 0) >= 10 NO - continue
10 10 0 if (10 - 0) >= 10 YES - TOGGLE - PreviousEvent = PreviousEvent + TimeCycle
11 10 10 if (11 - 10) >= 10 NO - continue
12 10 10 if (12 - 10) >= 10 NO - continue
13 10 10 if (13 - 10) >= 10 NO - continue
14 10 10 if (14 - 10) >= 10 NO - continue
15 10 10 if (15 - 10) >= 10 NO - continue
16 10 10 if (16 - 10) >= 10 NO - continue
17 10 10 if (17 - 10) >= 10 NO - continue
18 10 10 if (18 - 10) >= 10 NO - continue
19 10 10 if (19 - 10) >= 10 NO - continue
20 10 10 if (20 - 10) >= 10 YES - TOGGLE - PreviousEvent = PreviousEvent + TimeCycle
21 10 20 if (21 - 20) >= 10 NO - continue
22 10 20 if (22 - 20) >= 10 NO - continue
23 10 20 if (23 - 20) >= 10 NO - continue
24 10 20 if (24 - 20) >= 10 NO - continue
25 10 20 if (25 - 20) >= 10 NO - continue
26 10 20 if (26 - 20) >= 10 NO - continue
27 10 20 if (27 - 20) >= 10 NO - continue
28 10 20 if (28 - 20) >= 10 NO - continue
29 10 20 if (29 - 20) >= 10 NO - continue
30 10 20 if (30 - 20) >= 10 YES - TOGGLE - PreviousEvent = PreviousEvent + TimeCycle
31 10 30 if (31 - 30) >= 10 NO - continue
32 10 30 if (32 - 30) >= 10 NO - continue
33 10 30 if (33 - 30) >= NO - continue
34 10 30 if (34 - 30) >= NO - continue
35 10 30 if (35 - 30) >= 10 NO - continue
36 10 30 if (36 - 30) >= 10 NO - continue
37 10 30 if (37 - 30) >= 10 NO - continue
38 10 30 if (38 - 30) >= 10 NO - continue
39 10 30 if (39 - 30) >= 10 NO - continue
--- --- --- ---
241 10 240 if (241 - 240) >= 10 NO - continue
242 10 240 if (242 - 240) >= 10 NO - continue
243 10 240 if (243 - 240) >= 10 NO - continue
244 10 240 if (244 - 240) >= 10 NO - continue
245 10 240 if (245 - 240) >= 10 NO - continue
246 10 240 if (246 - 240) >= 10 NO - continue
247 10 240 if (247 - 240) >= 10 NO - continue
248 10 240 if (248 - 240) >= 10 NO - continue
249 10 240 if (249 - 240) >= 10 NO - continue
250 10 240 if (250 - 240) >= 10 YES - TOGGLE - PreviousEvent = PreviousEvent + TimeCycle
251 10 250 if (251 - 250) >= 10 NO - continue
252 10 250 if (252 - 250) >= 10 NO - continue
253 10 250 if (253 - 250) >= 10 NO - continue
254 10 250 if (254 - 250) >= 10 NO - continue
255 10 250 if (255 - 250) >= 10 NO - continue
0 10 250 if (0 - 250) >= 10 NO - continue
1 10 250 if (1 - 250) >= 10 NO - continue
2 10 250 if (2 - 250) >= 10 NO - continue
3 10 250 if (3 - 250) >= 10 NO - continue
4 10 250 if (4 - 250) >= 10 YES - TOGGLE - PreviousEvent = PreviousEvent + TimeCycle
5 10 4 if (5 - 4) >= 10 NO - continue
6 10 4 if (6 - 4) >= 10 NO - continue
7 10 4 if (7 - 4) >= 10 NO - continue
8 10 4 if (8 - 4) >= 10 NO - continue
9 10 4 if (9 - 4) >= 10 NO - continue
10 10 4 if (10 - 4) >= 10 NO - continue
11 10 4 if (11 - 4) >= 10 NO - continue
12 10 4 if (12 - 4) >= 10 NO - continue
13 10 4 if (13 - 4) >= 10 NO - continue
14 10 4 if (14 - 4) >= 10 YES - TOGGLE - PreviousEvent = PreviousEvent + TimeCycle
15 10 14 if (15 - 14) >= 10 NO - continue
16 10 14 if (16 - 14) >= 10 NO - continue
17 10 14 if (17 - 14) >= NO - continue
18 10 14 if (18 - 14) >= NO - continue
19 10 14 if (19 - 14) >= NO - continue
20 10 14 if (20 - 14) >= NO - continue
21 10 14 if (21 - 14) >= NO - continue
22 10 14 if (22 - 14) >= NO - continue
23 10 14 if (23 - 14) >= NO - continue




Anyone wishing to see a real example, where this problem is not present, can find it on the ARDUINO IDE, in FILE -> DIGITAL -> MILLIS WITHOUT DELAY.

To complete the information, know that it is also possible to force or reset the millis counter () when we want to do it, for example once every 24 hours, to avoid the problem described above.
Programming purists deprecate this method ... you decide

The following function is called when you want to reset the millis counter:


extern unsigned long timer0_millis; // line to put in the initial declarations

// actual function
void resetMillis() {
  cli(); //stop interrupt
  timer0_millis = 0; //reset counter
  sei(); //reactivate interrupt
}


Luciano Pautasso




If you liked this guide click on one or more advertising banners. You will help us pay for the server. Thank you



Cerca 


Categorie Articoli

Ultimi articoli

OPTA-FINDER-ARDUINO-COMPATIBLE   APRI 

whatsapp-alarm-repeater   APRI 

Arduino_Template_Menu_Eng   APRI 

Arduino_Template_Menu   APRI 

Power-Supply-with-Current-Control   APRI 

Vantaggi_Alimentatori-Controllo_Corrente   APRI 

Camping-La-Secca-Moneglia   APRI 

Safety-Relays   APRI 

Rele-di-sicurezza   APRI 

Internal-or-External-Watchdog   APRI 

Watchdog-interno-o-esterno   APRI 

Ripetitore-di-allarme-su-Whatsapp   APRI 

Bufala-in-crosta   APRI 

Home-Automation-ESPeriment   APRI 

ESPerimento-Domotica   APRI 

Arduino-measures-liquid-level   APRI 

Arduino-misura-livello-liquidi   APRI 

finder   APRI 

LORA-english-version   APRI 

Pluviometro-LORA   APRI 

Pillole_di_Promessi_Sposi   APRI 

LORA   APRI 

promessisposi-riscrittura   APRI 

Arduino_crashes   APRI 

Arduino_si_blocca   APRI 

Arduino_e_Trenino   APRI 

millis_no_overflow   APRI 

millis   APRI 

Arduino_millis_no_Overflow   APRI 

millis   APRI