Arduino, delay() vs millis()

luca 21/07/2015 6

Uno degli errori più frequenti di chi inizia a scrivere sketch per Arduino è l’uso eccessivo della funzione delay().

Tale funzione, come spiegato nella reference ufficiale, mette in pausa il programma per il numero di millisecondi indicato come parametro. Vediamo un semplice esempio: abbiamo collegato ad Arduino un pulsante e un led: alla pressione del pulsante, il led deve essere acceso per 3 secondi.

Lo sketch in esecuzione su Arduino potrebbe essere (modificando quello presentato nel tutorial ufficiale):

const int buttonPin = 2;
const int ledPin = 4;
 
void setup() {
 
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
}
 
void loop() {
 
  if (digitalRead(buttonPin) == HIGH) {     
    digitalWrite(ledPin, HIGH);
    delay(3000);
    digitalWrite(ledPin, LOW);  
  } 
}

Aggiungiamo ora un secondo pulsante e un secondo led e proviamo a modificare lo sketch per gestire entrambi, sempre utilizzando delay():

const int button1Pin = 2;
const int button2Pin = 3;
const int led1Pin = 4;
const int led2Pin = 5;
 
void setup() {
 
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  pinMode(button1Pin, INPUT);
  pinMode(button2Pin, INPUT);
}
 
void loop(){
 
  if (digitalRead(button1Pin) == HIGH) {     
    digitalWrite(led1Pin, HIGH);
    delay(3000);  
    digitalWrite(led1Pin, LOW);
  }
  if (digitalRead(button2Pin) == HIGH) {     
    digitalWrite(led2Pin, HIGH);
    delay(3000);  
    digitalWrite(led2Pin, LOW);
  } 
}

Provando il circuito su breadboard

delay-fritzing

ci accorgiamo di un problema: quando uno dei due led è acceso, non è possibile accendere anche l’altro! Il motivo è semplice: mentre il led è acceso, lo sketch è fermo e non può controllare lo stato dell’altro pulsante…

MILLIS

Per risolvere il problema, possiamo sfruttare la funzione millis(): tale funzione restituisce i millisecondi trascorsi dall’avvio dello sketch.

Per sapere quindi quando sono trascorsi 3 secondi possiamo:

  • memorizzare in una variabile il tempo zero, ovvero l’istante di inizio (il momento in cui abbiamo acceso il led)
  • controllare periodicamente (ad esempio ad ogni esecuzione del loop) la differenza tra l’istante attuale e quello iniziale

Ecco lo sketch modificato:

const int button1Pin = 2;
const int button2Pin = 3;
const int led1Pin = 4;
const int led2Pin = 5;
 
unsigned long led1OnTime;
unsigned long led2OnTime;
bool led1On;
bool led2On;
 
void setup() {
 
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  pinMode(button1Pin, INPUT);
  pinMode(button2Pin, INPUT);
 
  led1On = false;
  led2On = false;
}
 
void loop(){
 
  if (digitalRead(button1Pin) == HIGH) {     
    digitalWrite(led1Pin, HIGH);
    led1On = true;
    led1OnTime = millis();
  }
  if (digitalRead(button2Pin) == HIGH) {     
    digitalWrite(led2Pin, HIGH);
    led2On = true;
    led2OnTime = millis();
  }
 
  if(led1On) 
    if(millis() - led1OnTime > 30000) {
      digitalWrite(led1Pin, LOW);
      led1On = false;
    }   
  if(led2On) 
    if(millis() - led2OnTime > 30000) {
      digitalWrite(led2Pin, LOW);
      led2On = false;
    }
}

Ho dichiarato quattro nuove variabili: due (led1OnTime e led2OnTime) per memorizzare l’istante in cui i led vengono accesi e due (led1On e led2On) per memorizzare lo stato (acceso/spento ovvero true/false) di ogni led.

Quando viene premuto un tasto, lo sketch accende il led, memorizza l’istante di accensione e cambia la variabile di stato.

Infine se un led è acceso (la sua variabile di stato ha valore true), viene ciclicamente verificato se tale led è acceso da più del tempo previsto (30 secondi ovvero 30000 millisecondi): in tal caso il led viene spento.

6 Comments »

  1. Bob Green 23/07/2015 at 19:15 - Reply

    Luca, it might be easier for ‘noobs’ to follow if you used symbols instead of &lt and &gt. I know you only used &gt on this occasion. Excellent description of millis() otherwise.

    • luca 27/07/2015 at 08:27 - Reply

      Hi Bob! Thanks for your comment: it seems that something went wrong with my wordpress “code” plugin: I’ll fix it!

  2. Mark 16/03/2016 at 04:31 - Reply

    Great write up and easy to understand

    • luca 16/03/2016 at 14:18 - Reply

      Thanks for sharing!

  3. Guido 17/04/2016 at 07:59 - Reply

    E’ raro che possa accadere ma è da tenere in conto che la variabile millis() si azzera dopo circa 50 giorni; questo significa che se utilizzi questo metodo su un sistema che resta sempre acceso potrebbe, dopo 50 giorni, non funzionare più.
    Se invece del confronto diretto tra Millis() e la variabile si confrontano i due valori assoluti il problema non si presenta.

    • luca 18/04/2016 at 19:31 - Reply

      grazie per il suggerimento Guido!

Leave A Response »

Questo sito usa i cookie per poterti offrire una migliore esperienza di navigazione maggiori informazioni

Questo sito utilizza i cookie per fonire la migliore esperienza di navigazione possibile. Continuando a utilizzare questo sito senza modificare le impostazioni dei cookie o clicchi su "Accetta" permetti al loro utilizzo.

Chiudi