arduino
Gestione del tempo
Ricerca…
Sintassi
longless non firmati ()
micros lungo non firmato ()
ritardo vuoto (millisecondi lunghi senza segno)
void delayMicroseconds (microsecondi lunghi non firmati)
Vedi l'intestazione di ElisedMillis per costruttori e operatori di quella classe. In breve:
- elapsedMillis elapsedMillisObject; crea un oggetto per tenere traccia del tempo da quando è stato creato o da qualche altro punto nel tempo esplicitamente impostato
- elapsedMillisObject = 0; resettare il tempo tracciato dall'oggetto su "da ora"
- deltaT lungo non firmato = elapsedMillisObject; lasciaci guardare il tempo tracciato
- elapsedMillisObject + = and - = questi funzionano come previsto
Osservazioni
Blocco contro codice non bloccante
Per schizzi molto semplici, scrivere codice di blocco usando delay()
e delayMicroseconds()
può essere appropriato. Quando le cose diventano più complesse, l'uso di queste funzioni può avere alcuni inconvenienti. Alcuni di questi sono:
- Sprecare tempo della CPU: schizzi più complessi potrebbero aver bisogno della CPU per qualcos'altro mentre si attende la fine di un periodo di intermittenza del LED.
- ritardi imprevisti: quando
delay()
viene chiamato in subroutine che non sono ovviamente chiamate, ad esempio nelle librerie incluse. - eventi mancanti che si verificano durante il ritardo e non vengono gestiti da un gestore di interruzioni, ad esempio la pressione di un pulsante di polling: un pulsante potrebbe essere premuto per 100 ms, ma potrebbe essere ombreggiato da un
delay(500)
.
Dettagli di implementazione
millis()
solito si basa su un timer hardware eseguito a una velocità molto più alta di 1 kHz. Quando viene chiamato millis()
, l'implementazione restituisce un valore, ma non si sa quanti anni sia effettivamente. È possibile che il millisecondo "corrente" sia appena iniziato o che termini dopo la chiamata di funzione. Ciò significa che, quando si calcola la differenza tra due risultati da millis()
, si può avere un valore compreso tra quasi zero e quasi un millisecondo. Usa micros()
se è necessaria una maggiore precisione.
Esaminando il codice sorgente di elapsedMillis
rivela che utilizza effettivamente millis()
internamente per confrontare due punti nel tempo, quindi soffre anche di questo effetto. Anche in questo caso, esiste l'alternativa elapsedMicros
per una maggiore precisione, dalla stessa libreria.
blocco lampeggiante con ritardo ()
Uno dei modi più semplici per far lampeggiare un LED è: accenderlo, attendere un po ', spegnerlo, attendere ancora e ripetere all'infinito:
// set constants for blinking the built-in LED at 1 Hz
#define OUTPIN LED_BUILTIN
#define PERIOD 500
void setup()
{
pinMode(OUTPIN, OUTPUT); // sets the digital pin as output
}
void loop()
{
digitalWrite(OUTPIN, HIGH); // sets the pin on
delayMicroseconds(PERIOD); // pauses for 500 miliseconds
digitalWrite(OUTPIN, LOW); // sets the pin off
delayMicroseconds(PERIOD); // pauses for 500 milliseconds
// doing other time-consuming stuff here will skew the blinking
}
Tuttavia, l'attesa come nell'esempio precedente spreca i cicli della CPU, perché si limita a rimanere in attesa di un determinato punto nel tempo. Questo è quello che i modi non bloccanti, usando millis()
o elapsedMillis
, fanno meglio - nel senso che non bruciano gran parte delle capacità dell'hardware.
Bloccato non bloccante con la libreria di Mills (e la classe) trascorsa
La libreria ElapsedMillis fornisce una classe con lo stesso nome che tiene traccia del tempo trascorso da quando è stato creato o impostato su un determinato valore:
#include <elapsedMillis.h>
#define OUTPIN LED_BUILTIN
#define PERIOD 500
elapsedMillis ledTime;
bool ledState = false;
void setup()
{
// initialize the digital pin as an output.
pinMode(OUTPIN, OUTPUT);
}
void loop()
{
if (ledTime >= PERIOD)
{
ledState = !ledState;
digitalWrite(OUTPIN, ledState);
ledTime = 0;
}
// do other stuff here
}
Nell'esempio si può vedere che l'oggetto ledTime
è assegnato a zero quando il pin del LED è stato commutato. Questo potrebbe non essere sorprendente a prima vista, ma ha un effetto se stanno accadendo cose che richiedono più tempo:
Si consideri una situazione in cui il confronto tra ledTime
e PERIOD
viene eseguito dopo 750 millisecondi. Quindi impostare ledTime
su zero significa che tutte le successive operazioni di commutazione saranno 250 ms "in ritardo". Se, al contrario, il PERIOD
stato sottratto da ledTime
, il LED vedrebbe un breve periodo e quindi continua a lampeggiare come se nulla fosse accaduto.
Bloccato non bloccante con millis ()
Questo è molto simile a un esempio dei documenti arduino :
// set constants for blinking the built-in LED at 1 Hz
#define OUTPIN LED_BUILTIN
#define PERIOD 500 // this is in milliseconds
int ledState = LOW;
// millis() returns an unsigned long so we'll use that to keep track of time
unsigned long lastTime = 0;
void setup() {
// set the digital pin as output:
pinMode(OUTPIN, OUTPUT);
}
void loop() {
unsigned long now = millis();
if (now - lastTime >= PERIOD) // this will be true every PERIOD milliseconds
{
lastTime = now;
if (ledState == LOW)
{
ledState = HIGH;
}
else
{
ledState = LOW;
}
digitalWrite(OUTPIN, ledState);
}
// now there's lots of time to do other stuff here
}
L'uso di millis()
in questo modo - per operazioni temporali in modo non bloccante - è qualcosa che è necessario abbastanza spesso, quindi considerate di utilizzare la libreria elapsedMillis
per questo.
Misurare quanto tempo è durato qualcosa, utilizzando la Millis trascorsa e il Microfono trascorso
#include <elapsedMillis.h>
void setup() {
Serial.begin(115200);
elapsedMillis msTimer;
elapsedMicros usTimer;
long int dt = 500;
delay(dt);
long int us = usTimer;
long int ms = msTimer;
Serial.print("delay(");Serial.print(dt);Serial.println(") took");
Serial.print(us);Serial.println(" us, or");
Serial.print(ms);Serial.println(" ms");
}
void loop() {
}
In questo esempio, un oggetto elapsedMillis
e un oggetto elapsedMicros
vengono utilizzati per misurare quanto tempo è durato qualcosa, creandoli appena prima dell'esecuzione dell'espressione che vogliamo utilizzare per il tempo e ottenendo successivamente i loro valori. Mostreranno risultati leggermente diversi, ma il risultato del millisecondo non sarà inferiore a più di un millisecondo.
Più di 1 attività senza ritardo ()
Se hai più di 1 compito da eseguire ripetutamente a intervalli diversi, usa questo esempio come punto di partenza:
unsigned long intervals[] = {250,2000}; //this defines the interval for each task in milliseconds
unsigned long last[] = {0,0}; //this records the last executed time for each task
void setup() {
pinMode(LED_BUILTIN, OUTPUT); //set the built-it led pin as output
Serial.begin(115200); //initialize serial
}
void loop() {
unsigned long now = millis();
if(now-last[0]>=intervals[0]){ last[0]=now; firstTask(); }
if(now-last[1]>=intervals[1]){ last[1]=now; secondTask(); }
//do other things here
}
void firstTask(){
//let's toggle the built-in led
digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN)?0:1);
}
void secondTask(){
//say hello
Serial.println("hello from secondTask()");
}
Per aggiungere un'altra attività da eseguire ogni 15 secondi, estendere gli intervals
variabili e last
:
unsigned long intervals[] = {250,2000,15000};
unsigned long last[] = {0,0,0};
Quindi aggiungere un'istruzione if
per eseguire la nuova attività. In questo esempio, l'ho chiamato thirdTask
.
if(now-last[2]>=intervals[2]){ last[2]=now; thirdTask(); }
Alla fine dichiara la funzione:
void thirdTask(){
//your code here
}