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
Categorie Articoli
Corso-di-elettrotecnica-ed-elettronica-3-volumi
Libro-tutto-sull-audio---inglese
Libro-ELETTRONICA-FONDAMENTALE
Dove-acquistare-abbigliamento-risparmiando
Come-vedere-le-partite-sullo-smartphone
Come-difendersi-dagli-allegati-pericolosi-nelle-email
KEEPASS-un-posto-sicuro-per-le-nostre-PASSWORD
I-3-trend-estivi-del-2020-scopri-i-tagli-che-ti-stanno-meglio
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