One of the most common errors when you start writing your sketches for Arduino is the excessive use of the delay() function.
This function, as explained in the official documentation, pauses the program for the specified number of milliseconds. Let’s see an example: you connected to your Arduino a button and a led: when you press the button, the led should be turned on for 3 seconds.
The sketch to implement the goal could be (I slightly modified the one in the official tutorial):
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); } } |
Now add a second button and a second led and try to update the sketch to control both the leds, again using the delay() function:
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); } } |
Let’s test the circuit on a breadboard
You may note a problem: when a led is turned on, you cannot turn on also the other one! The reason is simple: when the first led is on, your sketch is stuck and cannot check the state of the second button…
MILLIS
To solve the problem, you can use the millis() function: it returns the number of milliseconds since the sketch was started.
If you need to know when a given time has passed, you can:
[checklist]
- store in a variable the time zero, that is the initial time (when you turn on the led)
- periodically check (for example at every loop execution) the difference between the actual and the initial time
[/checklist]
Here’s the new sketch:
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; } } |
I defined four new variables: two (led1OnTime e led2OnTime) to save the time when the leds are turned on and two (led1On e led2On) to save the current status (on/off, in boolean true/false) of each led.
When a button is pressed, the sketch turns the led on, saves the actual time and changes the status variable.
If a led is on (its status variable is true), the sketch periodically checks if the on period is longer than the required (30 seconds, it’s 30000 milliseconds): if so, the led is turned off.
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.