LO SCAFFALE DEGLI HOBBY

Appunti On Line

AVVERTENZE da leggere attentamente


ARDUINO

Funzione millis la sintesi


Il contatore

Arduino dispone di un contatore a 32 bit che incrementa automaticamente ogni millisecondo e contiene i millisecondi trascorsi dall’avvio del sistema.

Il contatore all’accensione parte da zero, dopo circa 1193 ore raggiunge il valore massimo (4294967295), poi ritorna a zero e ricomincia ad incrementare.



Annotare il tempo attuale

Il valore attuale del contatore si legge con la funzione millis.

Nel momento esatto da cui si vuole iniziare misurare il tempo il valore ritornato da millis va salvato in una variabile di tipo unsigned long (o uint32_t).
iniziale = millis();



Calcolare il tempo trascorso

Il tempo trascorso è semplicemente il valore attuale ritornato da millis meno il valore di partenza salvato. Anche il valore ‘trascorso’ è di tipo unsigned long:
trascorso = millis() - iniziale;
Il codice seguente usa la funzione millis per simulare esattamente una chiamata alla funzione delay(10000):
uint32_t iniziale = millis();
while ((millis() - iniziale) < 10000) { }
Nota: questo sopra è solo un esempio, usare millis in questo modo è del tutto inutile in quanto svolge l’identica funzione di delay. Un uso più sensato è in abbinamento con la programmazione a stati.



Il (falso) problema dell’overflow

Quello riportato qua sopra è l’unico modo corretto per calcolare il tempo trascorso senza incorrere in alcun problema con il ritorno a zero del contatore (il famoso e temuto overflow). Effettuando la differenza tra numeri interi con conteggio circolare a 32 bit, il risultato viene sempre giusto.

Invece tutti gli altri sistemi di confronto diretto tra il valore di millis e qualcos’altro possono portare a malfunzionamenti del programma anche dopo molti giorni di funzionamento impeccabile.

Ad esempio la riga seguente è errata, perché da per scontato che il valore ritornato da millis sia sempre crescente senza limiti, ma questo non è vero. In questi casi il confronto in certi momenti può generare un risultato molto diverso da quello atteso e causare malfunzionamenti:
if (millis() > (accensione + 2000)) { .... }
Il problema è ben evidente nel disegno seguente a destra: se il tempo finale desiderato sono le 3, e noi effettuiamo il confronto tempo_attuale>finale, la condizione risulta vera anche alle 11, il che è evidentemente un errore. Effettuando invece una sottrazione circolare, cioè contando indietro di 10 passi, otteniamo sempre l’esatto tempo trascorso.


Quindi la forma corretta è sempre:
if ((millis() - accensione) > 2000) { .... }


Ottenere intervalli periodici precisi

Per ottenere una cadenza periodica precisa è necessario usare la forma seguente. La cosa più importante è incrementare la variabile tempo ‘t1’ esattamente del valore di ‘periodo’. Con questa forma ci si può aspettare un errore di qualche secondo all’ora dipendente solo dall’imprecisione dell’oscillatore.
if ((millis() - t1) >= periodo)
{
    t1 += periodo;
    ....
}
Il momento in cui viene valutata la condizione potrebbe essere in ritardo rispetto all’esatto istante ideale di scadenza del periodo (ritardo evidenziato in giallo nel disegno seguente). Incrementando la variabile tempo dell’esatto valore del periodo, si “insegue” sempre correttamente l’aumentare di millis(), spostando il prossimo riconoscimento all’esatto scadere del prossimo intervallo:


Invece la forma seguente è errata. Ogni volta che la condizione viene valutata in ritardo rispetto al momento ideale, “reimpostando” la variabile ‘inizio’ al tempo attuale, questo ritardo si aggiunge a tutti i ritardi precedenti. Con questa forma ci si può aspettare un errore di diversi secondi al minuto o anche peggiore.
if ((millis() - inizio) >= periodo)
{
    inizio = millis();
    .... 
}
Il disegno seguente (in basso) mostra visivamente l’accumulo del ritardo (frecce grige) rispetto agli istanti periodici ideali. Il riconoscimento degli istanti ideali avviene invece nel primo caso (anche se il ritardo nella valutazione della condizione introduce comunque un piccolo jitter casuale rispetto agli istanti ideali).




All'indice principale | Al vecchio sito