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
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:
[checklist]
- 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
[/checklist]
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.
Luca, it might be easier for ‘noobs’ to follow if you used symbols instead of < and >. I know you only used > on this occasion. Excellent description of millis() otherwise.
Hi Bob! Thanks for your comment: it seems that something went wrong with my wordpress “code” plugin: I’ll fix it!
Great write up and easy to understand
Thanks for sharing!
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.
grazie per il suggerimento Guido!
sono alle prime armi e ho modificato il tuo sketch per accendere un led 15 secondi dopo aver premuto il tasto. quando lo rilascio il led deve spegnersi. Invece dopo essersi acceso no si spegne piu… cosa sbaglio ? grazie
const int button1Pin = 2;
const int led1Pin = 4;
unsigned long led1OnTime;
bool led1On;
void setup() {
pinMode(led1Pin, OUTPUT);
pinMode(button1Pin, INPUT);
led1On = false;
Serial.begin (19200);
}
void loop(){
if (digitalRead(button1Pin) == HIGH) {
digitalWrite(led1Pin, HIGH);
led1On = true;
led1OnTime = millis();
if(led1On )
if(millis() – led1OnTime > 15000) {
digitalWrite(led1Pin, LOW);
led1On = false;
} } }
ciao, devi chiudere la parentesi graffa dopo
ed1OnTime = millis();
, altrimenti tutto il blocco seguente – compreso lo spegnimento del led – viene eseguito solo quando il pulsante è premuto.