Controllo del periodo di lampeggio tramite pulsante (non-blocking mode)

Si desidera avere un led comandato con un pulsante con il seguente schema di funzionamento:

  1. Inizio: led acceso
  2. Primo tocco: led lampeggia con periodo di mezzo secondo
  3. Secondo tocco: led lampeggia con periodo di 1 secondo
  4. Terzo tocco: led lampeggia con periodo di 1 secondo e mezzo (al tocco successivo si riprende dal punto 1)
  5. Quarto tocco: si riparte dal punto 2.
Il circuito per effettuare l'operazione sia il seguente:


Una soluzione possibile, probablmente la più intuitiva, può essere trovata all'indirizzo: http://www.maffucci.it/2011/03/10/arduino-lezione-4-realizzare-un-programma-che-identifica-le-variazioni-di-stato/  che viene qui sotto riportata con alcune piccole modifiche.

// All'inizio led acceso
// Primo tocco: led lampeggia con periodo di mezzo secondo
// Secondo tocco: led lampeggia con periodo un secondo
// Terzo tocco: led lampeggia con periodo un secondo e mezzo
// Quarto tocco: led acceso
// N.B. Affinché la pressione venga letta e abbia efficacia 
// è necessario tenere premuto il pulsante per un breve periodo

#define BUTTON 7     // pin di input a cui è collegato il pulsante
#define LED 13 // LED collegato al pin digitale 13 // Variabili globali bool statoButton; // stato del pulsante int countButton = 0; // Conteggio del bottone // Avvio dell'applicazione void setup() { pinMode(LED, OUTPUT); // imposta il pin digitale come output pinMode(BUTTON, INPUT); // imposta il pin digitale come input digitalWrite(LED, HIGH); // accende il LED } // Avvio del loop void loop() { statoButton = digitalRead(BUTTON); // legge il valore dell'input e lo conserva if(statoButton == HIGH) // verifico se l'utente ha premuto il bottone { // Aumento il count del bottone if(countButton<=3) countButton=countButton+1; else countButton=0; while(digitalRead(BUTTON) == HIGH); // Aspettare il rilascio del pulsante // delay(200); // debounce, decommentare se necessario } // In base allo stato del bottone scelgo l'azione del led switch (countButton) { // Led lampeggia ogni mezzo secondo case 1: digitalWrite(LED, HIGH); // accende il LED delay(250); // aspetta 250 millisecondi digitalWrite(LED, LOW); // spegne il LED delay(250); // aspetta 250 millisecondi break; // Led lampeggia ogni secondo case 2: digitalWrite(LED, HIGH); // accende il LED delay(500); // aspetta 500 millisecondi digitalWrite(LED, LOW); // spegne il LED delay(500); // aspetta 500 millisecondi break; // led lampeggia ogni secondo e mezzo case 3: digitalWrite(LED, HIGH); // accende il LED delay(750); // aspetta 750 millisecondi digitalWrite(LED, LOW); // spegne il LED delay(750); // aspetta 750 millisecondi break; // Led si spegne case 0: digitalWrite(LED, HIGH); delay(15); // aspetta per aumentare le performance break; } }

Il problema del codice qui sopra riportato è che l'utilizzo del delay() interrompe il programam e quindi è necessario tenere premuto il pulsante fino a 1 secondo e mezzo, nel caso peggiore, affinché il delay() si esaurisca e Arduino senta il comando.

Scopo di questa lezione è risolvere questo tipo di problema.

Eliminando i delay() il programma diventa non-blocking e il controllo del pulsante può avvenire in continuazione, eliminando la necessità di tenerlo premuto. Per fare questa viene utilizzata la tecnica dei timer tramite la funzione millis()

// All'inizio led acceso
// Primo tocco: led lampeggia con periodo di mezzo secondo
// Secondo tocco: led lampeggia con periodo un secondo
// Terzo tocco: led lampeggia con periodo un secondo e mezzo
// Quarto tocco: led acceso

#define BUTTON 7     // pin di input a cui è collegato il pulsante
#define LED 13 // LED collegato al pin digitale 13 // Variabili globali bool statoButton; // stato del pulsante int countButton = 0; // Conteggio del bottone unsigned long timenow = 0; // variabile di appoggio per il conteggio dei microsecondi unsigned long lastUpdate = 0; // variabile di appoggio per il conteggio dei millisecondi da quando è avvenuto l'ultimo evento nel LED unsigned long interval = 0; // semiperiodo del LED in millisecondi (0 led acceso) bool statoLed = LOW; // stato del LED (LOW spento, HIGH acceso) // Avvio dell'applicazione void setup() { pinMode(LED, OUTPUT); // imposta il pin digitale come output pinMode(BUTTON, INPUT); // imposta il pin digitale come input digitalWrite(LED, HIGH); // accende il LED } // Avvio del loop void loop() { statoButton = digitalRead(BUTTON); // legge il valore dell'input e lo conserva if(statoButton == HIGH) // verifico se l'utente ha premuto il bottone { // Aumento il count del bottone if(countButton<=3) countButton=countButton+1; else countButton=0; while(digitalRead(BUTTON) == HIGH); // Aspettare il rilascio del pulsante // delay(200); // debounce, decommentare se necessario switch (countButton) // In base allo stato del bottone scelgo il periodo del led { case 1: interval = 250; // periodo lampeggio 0.5 secondi break; case 2: interval = 500; // periodo lampeggio 1 secondo break; case 3: interval = 750; // periodo lampeggio 1.5 secondi break; case 0: digitalWrite(LED, HIGH); // accende il LED interval = 0; break; } } // gestione del lampeggio timenow = millis(); // carico il tempo passato dall'avvio del programma // Verifico se devo fa cambiare stato al LED1 // && è l'operatore AND logico // (interval !=0) per gestire il pulsante sempre acceso if ((timenow >= lastUpdate + interval) && (interval !=0)){ if (statoLed == 0){ digitalWrite(LED, HIGH); // accende il LED statoLed = HIGH; // aggiorna stato LED } else{ digitalWrite(LED, LOW); // spegne il LED statoLed = LOW; // aggiorna stato LED } /* Al posto di tutto il blocco if si sarebbe potuto mettere * digitalWrite(LED, !statoLed); */ lastUpdate = timenow; // aggiorno per il nuovo evento } }

Ultime modifiche: domenica, 11 dicembre 2022, 13:53