Professioni Segnaposto
millis() ed il problema dell'overflow
In una precedente guida (https://www.realmeteo.com/arduino/millis/) avevamo visto come con la funzione millis(), sia possibile creare ritardi non bloccanti. Avevamo anche detto che questa funzione può essere affetta da un problema di overflow, qualora il nostro arduino venga tenuto acceso per più di 49 giorni. Questo non vuole dire che la funzione abbia un baco, ma semplicemente che, nel nostro modo comune di pensare, siamo portati ad usarlo in un modo errato, e non ci accorgiamo della cosa se non dopo 49 giorni. Ma da dove deriva questo, e come evitare il problema? La prima risposta è semplice, il contatore che viene automaticamente incrementato ogni millisecondo è un registro da 32 bit; questo significa che dopo 4.294.967.295 millisecondi, corrispondenti a 1193,05 ore, o a 49,7 giorni, il contatore si azzera e ricomincia da zero.Siccome questo numero è piuttosto elevato per fare dei ragionamenti semplici, articolerò la descrizione del problema e della soluzione fingendo che il registro abbia solo 8 bit; in questo caso fittizio, il contatore arriva a 255 millisecondi e poi ricomincia da zero.
Faccio una parentesi di matematica binaria sui numeri da 8 bit, dove ribadisco, il numero massimo rappresentabile è 255, e poi, se aggiungo uno, riparte da zero. Quindi, tanto per fare qualche esempio di operazioni ad 8 bit, avremo questi risultati: 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 .... ma per le sottrazioni è la stessa cosa, ovvero 9-10=255; 8-10=254; 2-10=248; 1-10=247 ecc ecc.
Se queste cose sono chiare partiamo con la descrizione del problema, e sul come evitarlo:
Immaginiamo di dover generare con Arduino, una onda quadra da 50Hz, ovvero fare un toggle di un output, che sarà per 10 milliecondi ad 1 e per 10 millisecondi a 0.
Nella tabella seguente abbiamo, lo scorrere dei millisecondi nella prima colonna, il tempo ciclo nella seconda, la prossima meta nella terza e nella quarta l'operazione di controllo che erroneamente siamo portati a fare, per creare il ritardo da 10 millisecondi. All'inizio tutto funziona bene, ed ogni 10 millisecondi l'operazione di confronto fa invertire l'output, generando l'onda quadra a 50Hz. Ora spostiamoci nei pressi dell'evento nefasto. Al millisecondo 250 abbiamo l'ultimo toggle corretto, poi al 251 incontriamo il primo problema, un toggle inaspettato, e poi un altro a 252, ed altri ancora, fino al millisecondo 255
Ma non basta... segue un lungo periodo dove non ci sono toggle, ed arriviamo a millis 54 del secondo giro, dove tutto si sistema.
Quindi nella realtà avremo che i toggle non sono regolari, ma solo dopo 49 giorni!!!!
millis attuale | TempoCiclo | ProssimaMeta | if (millis() >= ProssimamMeta) SI NO |
---|---|---|---|
1 | 10 | 10 | NO - continua |
2 | 10 | 10 | if (2 >= 10) NO - continua |
3 | 10 | 10 | if (3 >= 10) NO - continua |
4 | 10 | 10 | if (4 >= 10) NO - continua |
5 | 10 | 10 | if (5 >= 10) NO - continua |
6 | 10 | 10 | if (6 >= 10) NO - continua |
7 | 10 | 10 | if (7 >= 10) NO - continua |
8 | 10 | 10 | if (8 >= 10) NO - continua |
9 | 10 | 10 | if (9 >= 10) NO - continua |
10 | 10 | 10 | if (10 >= 10) SI - TOGGLE - ProssimaMeta = ProssimaMeta +TempoCiclo |
11 | 10 | 20 | if (11 >= 20) NO - continua |
12 | 10 | 20 | if (12 >= 20) NO - continua |
13 | 10 | 20 | if (13 >= 20) NO - continua |
14 | 10 | 20 | if (14 >= 20) NO - continua |
15 | 10 | 20 | if (15 >= 20) NO - continua |
16 | 10 | 20 | if (16 >= 20) NO - continua |
17 | 10 | 20 | if (17 >= 20) NO - continua |
18 | 10 | 20 | if (18 >= 20) NO - continua |
19 | 10 | 20 | if (19 >= 20) NO - continua |
20 | 10 | 20 | if (20 >= 20) SI - TOGGLE - ProssimaMeta = ProssimaMeta +TempoCiclo |
21 | 10 | 30 | if (21 >= 30) NO - continua |
22 | 10 | 30 | if (22 >= 30) NO - continua |
23 | 10 | 30 | if (23 >= 30) NO - continua |
24 | 10 | 30 | if (24 >= 30) NO - continua |
25 | 10 | 30 | if (25 >= 30) NO - continua |
26 | 10 | 30 | if (26 >= 30) NO - continua |
27 | 10 | 30 | if (27 >= 30) NO - continua |
28 | 10 | 30 | if (28 >= 30) NO - continua |
29 | 10 | 30 | if (29 >= 30) NO - continua |
30 | 10 | 30 | if (30 >= 30) SI - TOGGLE - ProssimaMeta = ProssimaMeta +TempoCiclo |
31 | 10 | 40 | if (31 >= 40) NO - continua |
32 | 10 | 40 | if (32 >= 40) NO - continua |
33 | 10 | 40 | if (33 >= 40) NO - continua |
34 | 10 | 40 | if (34 >= 40) NO - continua |
35 | 10 | 40 | if (35 >= 40) NO - continua |
36 | 10 | 40 | if (36 >= 40) NO - continua |
37 | 10 | 40 | if (37 >= 40) NO - continua |
38 | 10 | 40 | if (38 >= 40) NO - continua |
39 | 10 | 40 | NO - continua |
---- | ---- | ---- | ---- |
241 | 10 | 250 | if (241 >= 250) NO - continua |
242 | 10 | 250 | if (242 >= 250) NO - continua |
243 | 10 | 250 | if (243 >= 250) NO - continua |
244 | 10 | 250 | if (244 >= 250) NO - continua |
245 | 10 | 250 | if (245 >= 250) NO - continua |
246 | 10 | 250 | if (246 >= 250) NO - continua |
247 | 10 | 250 | if (247 >= 250) NO - continua |
248 | 10 | 250 | if (248 >= 250) NO - continua |
249 | 10 | 250 | if (249 >= 250) NO - continua |
250 | 10 | 250 | if (250 >= 250) SI - TOGGLE - ProssimaMeta = ProssimaMeta +TempoCiclo |
251 | 10 | 4 | if (251 >= 4) SI - TOGGLE - ProssimaMeta = ProssimaMeta +TempoCiclo |
252 | 10 | 14 | if (252 >= 14) SI - TOGGLE - ProssimaMeta = ProssimaMeta +TempoCiclo |
253 | 10 | 24 | if (253 >= 24) SI - TOGGLE - ProssimaMeta = ProssimaMeta +TempoCiclo |
254 | 10 | 34 | if (254 >= 34) SI - TOGGLE - ProssimaMeta = ProssimaMeta +TempoCiclo |
255 | 10 | 44 | if (255 >= 44) SI - TOGGLE - ProssimaMeta = ProssimaMeta +TempoCiclo |
0 | 10 | 54 | if (0 >= 54) NO - continua |
1 | 10 | 54 | if (1 >= 54) NO - continua |
2 | 10 | 54 | if (2 >= 54) NO - continua |
3 | 10 | 54 | if (3 >= 54) NO - continua |
4 | 10 | 54 | if (4 >= 54) NO - continua |
5 | 10 | 54 | if (5 >= 54) NO - continua |
6 | 10 | 54 | if (6 >= 54) NO - continua |
7 | 10 | 54 | if (7 >= 54) NO - continua |
8 | 10 | 54 | if (8 >= 54) NO - continua |
9 | 10 | 54 | if (9 >= 54) NO - continua |
10 | 10 | 54 | if (10 >= 54) NO - continua |
11 | 10 | 54 | if (11 >= 54) NO - continua |
12 | 10 | 54 | if (12 >= 54) NO - continua |
13 | 10 | 54 | if (13 >= 54) NO - continua |
14 | 10 | 54 | if (14 >= 54) NO - continua |
15 | 10 | 54 | if (15 >= 54) NO - continua |
16 | 10 | 54 | if (16 >= 54) NO - continua |
17 | 10 | 54 | if (17 >= 54) NO - continua |
18 | 10 | 54 | if (18 >= 54) NO - continua |
19 | 10 | 54 | if (19 >= 54) NO - continua |
20 | 10 | 54 | if (20 >= 54) NO - continua |
21 | 10 | 54 | if (21 >= 54) NO - continua |
22 | 10 | 54 | if (22 >= 54) NO - continua |
23 | 10 | 54 | if (23 >= 54) NO - continua |
---- | ---- | ---- | ---- |
49 | 10 | 54 | if (49 >= 54) NO - continua |
50 | 10 | 54 | if (50 >= 54) NO - continua |
51 | 10 | 54 | if (51 >= 54) NO - continua |
52 | 10 | 54 | if (52 >= 54) NO - continua |
53 | 10 | 54 | if (53 >= 54) NO - continua |
54 | 10 | 54 | if (54 >= 54) SI - TOGGLE - ProssimaMeta = ProssimaMeta +TempoCiclo |
55 | 10 | 64 | if (55 >= 64) NO - continua |
56 | 10 | 64 | if (56 >= 64) NO - continua |
57 | 10 | 64 | if (57 >= 64) NO - continua |
58 | 10 | 64 | if (58 >= 64) NO - continua |
59 | 10 | 64 | if (59 >= 64) NO - continua |
60 | 10 | 64 | if (60 >= 64) NO - continua |
61 | 10 | 64 | if (61 >= 64) NO - continua |
62 | 10 | 64 | if (62 >= 64) NO - continua |
63 | 10 | 64 | if (63 >= 64) NO - continua |
64 | 10 | 64 | if (64 >= 64) SI - TOGGLE - ProssimaMeta = ProssimaMeta +TempoCiclo |
65 | 10 | 74 | if (65 >= 74) NO - continua |
66 | 10 | 74 | if (66 >= 74) NO - continua |
67 | 10 | 74 | if (67 >= 74) NO - continua |
68 | 10 | 74 | if (68 >= 74) NO - continua |
69 | 10 | 74 | if (69 >= 74) NO - continua |
70 | 10 | 74 | if (70 >= 74) NO - continua |
71 | 10 | 74 | if (71 >= 74) NO - continua |
72 | 10 | 74 | if (72 >= 74) NO - continua |
73 | 10 | 74 | if (73 >= 74) NO - continua |
74 | 10 | 74 | if (74 >= 74) SI - TOGGLE - ProssimaMeta = ProssimaMeta +TempoCiclo |
75 | 10 | 84 | if (75 >= 84) NO - continua |
76 | 10 | 84 | if (76 >= 84) NO - continua |
77 | 10 | 84 | if (77 >= 84) NO - continua |
78 | 10 | 84 | if (78 >= 84) NO - continua |
79 | 10 | 84 | if (79 >= 84) NO - continua |
80 | 10 | 84 | if (80 >= 84) NO - continua |
81 | 10 | 84 | if (81 >= 84) NO - continua |
82 | 10 | 84 | if (82 >= 84) NO - continua |
83 | 10 | 84 | if (83 >= 84) NO - continua |
Ora la soluzione: invece di sommare il tempo ciclo per calcolarela prossima meta, occorre ragionare alla rovescia, calcolando il tempo trascorso rispetto all'ultimo evento.
Nella seconda tabella, a differenza dalla prima, viene memorizzato l'evento precedente, ed il confronto corretto da fare è: if (millis() - MetaPrecedente >= tempoCiclo) SI TOGGLE - NO continua.
Come possiamo vedere nella simulazione ad 8 bit non ci sono irregolarità e tutto fila liscio sempre e per sempre.
millis attuale | TempoCiclo | MetaPrecedente | if (millis() - MetaPrecedente >= tempoCiclo) SI TOGGLE - NO continua |
---|---|---|---|
1 | 10 | 0 | if (1 - 0) >= 10 NO - continua |
2 | 10 | 0 | if (2 - 0) >= 10 NO - continua |
3 | 10 | 0 | if (3 - 0) >= 10 NO - continua |
4 | 10 | 0 | if (4 - 0) >= 10 NO - continua |
5 | 10 | 0 | if (5 - 0) >= 10 NO - continua |
6 | 10 | 0 | if (6 - 0) >= 10 NO - continua |
7 | 10 | 0 | if (7 - 0) >= 10 NO - continua |
8 | 10 | 0 | if (8 - 0) >= 10 NO - continua |
9 | 10 | 0 | if (9 - 0) >= 10 NO - continua |
10 | 10 | 0 | if (10 - 0) >= 10 SI -TOGGLE - MetaPrecedente = MetaPrecedente + TempoCiclo |
11 | 10 | 10 | if (11 - 10) >= 10 NO - continua |
12 | 10 | 10 | if (12 - 10) >= 10 NO - continua |
13 | 10 | 10 | if (13 - 10) >= 10 NO - continua |
14 | 10 | 10 | if (14 - 10) >= 10 NO - continua |
15 | 10 | 10 | if (15 - 10) >= 10 NO - continua |
16 | 10 | 10 | if (16 - 10) >= 10 NO - continua |
17 | 10 | 10 | if (17 - 10) >= 10 NO - continua |
18 | 10 | 10 | if (18 - 10) >= 10 NO - continua |
19 | 10 | 10 | if (19 - 10) >= 10 NO - continua |
20 | 10 | 10 | if (20 - 10) >= 10 SI -TOGGLE - MetaPrecedente = MetaPrecedente + TempoCiclo |
21 | 10 | 20 | if (21 - 20) >= 10 NO - continua |
22 | 10 | 20 | if (22 - 20) >= 10 NO - continua |
23 | 10 | 20 | if (23 - 20) >= 10 NO - continua |
24 | 10 | 20 | if (24 - 20) >= 10 NO - continua |
25 | 10 | 20 | if (25 - 20) >= 10 NO - continua |
26 | 10 | 20 | if (26 - 20) >= 10 NO - continua |
27 | 10 | 20 | if (27 - 20) >= 10 NO - continua |
28 | 10 | 20 | if (28 - 20) >= 10 NO - continua |
29 | 10 | 20 | if (29 - 20) >= 10 NO - continua |
30 | 10 | 20 | if (30 - 20) >= 10 SI -TOGGLE - MetaPrecedente = MetaPrecedente + TempoCiclo |
31 | 10 | 30 | if (31 - 30) >= 10 NO - continua |
32 | 10 | 30 | if (32 - 30) >= 10 NO - continua |
33 | 10 | 30 | if (33 - 30) >= NO - continua |
34 | 10 | 30 | if (34 - 30) >= NO - continua |
35 | 10 | 30 | if (35 - 30) >= 10 NO - continua |
36 | 10 | 30 | if (36 - 30) >= 10 NO - continua |
37 | 10 | 30 | if (37 - 30) >= 10 NO - continua |
38 | 10 | 30 | if (38 - 30) >= 10 NO - continua |
39 | 10 | 30 | if (39 - 30) >= 10 NO - continua |
--- | --- | --- | --- |
241 | 10 | 240 | if (241 - 240) >= 10 NO - continua |
242 | 10 | 240 | if (242 - 240) >= 10 NO - continua |
243 | 10 | 240 | if (243 - 240) >= 10 NO - continua |
244 | 10 | 240 | if (244 - 240) >= 10 NO - continua |
245 | 10 | 240 | if (245 - 240) >= 10 NO - continua |
246 | 10 | 240 | if (246 - 240) >= 10 NO - continua |
247 | 10 | 240 | if (247 - 240) >= 10 NO - continua |
248 | 10 | 240 | if (248 - 240) >= 10 NO - continua |
249 | 10 | 240 | if (249 - 240) >= 10 NO - continua |
250 | 10 | 240 | if (250 - 240) >= 10 SI -TOGGLE - MetaPrecedente = MetaPrecedente + TempoCiclo |
251 | 10 | 250 | if (251 - 250) >= 10 NO - continua |
252 | 10 | 250 | if (252 - 250) >= 10 NO - continua |
253 | 10 | 250 | if (253 - 250) >= 10 NO - continua |
254 | 10 | 250 | if (254 - 250) >= 10 NO - continua |
255 | 10 | 250 | if (255 - 250) >= 10 NO - continua |
0 | 10 | 250 | if (0 - 250) >= 10 NO - continua |
1 | 10 | 250 | if (1 - 250) >= 10 NO - continua |
2 | 10 | 250 | if (2 - 250) >= 10 NO - continua |
3 | 10 | 250 | if (3 - 250) >= 10 NO - continua |
4 | 10 | 250 | if (4 - 250) >= 10 SI -TOGGLE - MetaPrecedente = MetaPrecedente + TempoCiclo |
5 | 10 | 4 | if (5 - 4) >= 10 NO - continua |
6 | 10 | 4 | if (6 - 4) >= 10 NO - continua |
7 | 10 | 4 | if (7 - 4) >= 10 NO - continua |
8 | 10 | 4 | if (8 - 4) >= 10 NO - continua |
9 | 10 | 4 | if (9 - 4) >= 10 NO - continua |
10 | 10 | 4 | if (10 - 4) >= 10 NO - continua |
11 | 10 | 4 | if (11 - 4) >= 10 NO - continua |
12 | 10 | 4 | if (12 - 4) >= 10 NO - continua |
13 | 10 | 4 | if (13 - 4) >= 10 NO - continua |
14 | 10 | 4 | if (14 - 4) >= 10 SI -TOGGLE - MetaPrecedente = MetaPrecedente + TempoCiclo |
15 | 10 | 14 | if (15 - 14) >= 10 NO - continua |
16 | 10 | 14 | if (16 - 14) >= 10 NO - continua |
17 | 10 | 14 | if (17 - 14) >= NO - continua |
18 | 10 | 14 | if (18 - 14) >= NO - continua |
19 | 10 | 14 | if (19 - 14) >= NO - continua |
20 | 10 | 14 | if (20 - 14) >= NO - continua |
21 | 10 | 14 | if (21 - 14) >= NO - continua |
22 | 10 | 14 | if (22 - 14) >= NO - continua |
23 | 10 | 14 | if (23 - 14) >= NO - continua |
Chi volesse vedere un esempio reale, dove questo problema non è presente lo trova sull'ARDUINO IDE, in FILE -> DIGITAL -> MILLIS WITHOUT DELAY.
Per completare l'informazione, sappiate che è anche possibile forzare od azzerare il contatore millis() quando lo desideriamo fare, ad esempio una volta ogni 24 ore, per evitare il problema descritto sopra.
I puristi della programmazione deprecano questo metodo... decidete voi
Si chiama la seguente funzione quando si vuole azzerare il contatore millis:
extern unsigned long timer0_millis;
void resetMillis() {
cli();
timer0_millis = 0;
sei();
}
Luciano Pautasso
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