Simulare il multitasking con arduino ( macchina a stati finiti )

Con Arduino molte volte ci sarà capitata la necessità di voler eseguire più azioni contemporaneamente.  Prendiamo ad esempio il classico lampeggio di un led. Fin qui tutto normale, infatti basta programmare l’accensione e lo spegnimento con la funzione delay() ed il gioco è fatto…Ecco il classico codice di esempio

 

#define led1 13
void setup()
{
 pinMode(led1, OUTPUT);

}
 
void loop()
{
  digitalWrite(led1, HIGH);
  delay(1000); // il led1 rimane acceso per 1 secondo
  digitalWrite(led1, LOW);
  delay(1000);    // il led1 rimane spento per 1 secondo
}

 

Il codice riportato verrà eseguito all’infinito. Proviamo adesso a voler far lampeggiare un secondo led collegato su un altro pin con una frequenza diversa dal primo. Come fare?  Se proviamo ad usare ancora la funzione delay()  è chiaro che le istruzioni relative ai due led verranno eseguite sequenzialmente, cioè il secondo led si accenderà e si spegnerà solo dopo l’accensione e lo spegnimento del primo.

 

#define led1 13
#define led2  12
 
void setup()
{
 pinMode(led1, OUTPUT);
 pinMode(led2, OUTPUT);
}
 
void loop()
{
  digitalWrite(led1, HIGH);
  delay(1000); // il led1 rimane acceso per 1 secondo
  digitalWrite(led1, LOW);
  delay(1000);    // il led1 rimane spento per 1 secondo
 
  digitalWrite(led2, HIGH);
  delay(1000); // il led2 rimane acceso per 1 secondo
  digitalWrite(led2, LOW);
  delay(1000);    // il led2 rimane spento per 1 secondo
}

 

Per ovviare a questo problema, ossia fare in modo che i due led lampeggino in modo indipendente l’uno dall’altro, si può adottare una tecnica tipo quella chiamata “Automa a stati finiti“. In altre parole si tiene conto del verificarsi di una determinata condizione per far si che venga eseguito qualcos’altro. Nel nostro esempio se sfruttiamo la funzione millis(), a tutti gli effetti un contatore che restituisce il tempo trascorso espresso in millisecondi dall’avvio di Arduino, peraltro indipendente dall’esecuzione delle istruzioni, possiamo far eseguire parti di codice in una precisa finestra temporale senza che queste si influenzino a vicenda. Riprendendo l’esempio precedente, il codice diventa quello di seguito riportato :

 

#define led1 13
#define led2 12
#define led3 11

unsigned long tempoTrascorso;     // variabile usata per contare i millisecondi trascorsi dall'avvio di Arduino
unsigned long tempoled1 = 0;        // variabile usata per stabilire quando dovrà accendersi il primo led
unsigned long tempoled2 = 0;       // variabile usata per stabilire quando dovrà accendersi il secondo led
unsigned long tempoled3 = 0;      // variabile usata per stabilire quando dovrà accendersi il terzo led

void setup() {

pinMode(led1,OUTPUT);
pinMode(led2,OUTPUT);
pinMode(led3,OUTPUT);
digitalWrite(led1,LOW);
digitalWrite(led2,LOW);
digitalWrite(led3,LOW);
}

void loop() {

tempoTrascorso = millis();                   // memorizzo millis() nella variabile tempoTrascorso

if(tempoTrascorso >= 10000)                 // Dopo 10 secondi la variabile tempoTrascorso viene azzerata
{
tempoTrascorso = 0;
tempoTrascorso = millis();
}

// Il primo led viene acceso dopo 1 secondo dall'avvio di arduino e spento dopo mezzo secondo

if(tempoTrascorso > tempoled1 + 1000)
{
digitalWrite(led1,HIGH);
tempoled1 = millis();
}

if(tempoTrascorso > tempoled1 + 500)
{
digitalWrite(led1,LOW);

}

// Il secondo led viene acceso dopo 2 secondi  dall'avvio di arduino e spento dopo 1 secondo

if(tempoTrascorso > tempoled2 + 2000)
{
digitalWrite(led2,HIGH);
tempoled2 = millis();
}

if(tempoTrascorso > tempoled2 + 1000)
{
digitalWrite(led2,LOW);

}

// Il terzo led viene acceso dopo mezzo secondo  dall'avvio di arduino spento dopo un quarto di secondo

if(tempoTrascorso > tempoled3 + 500)
{
digitalWrite(led3,HIGH);
tempoled3 = millis();

}
if(tempoTrascorso > tempoled3 + 250)
{
digitalWrite(led3,LOW);

}

}


Si noti come i led lampeggiano ognuno con una propria frequenza. 
In poche parole, ad ognuno dei tre led viene assegnata una variabile temporale che verrà sempre confrontata con quella che contiene il valore della funzione millis(). Se si verificano le condizioni richieste scatta l’esecuzione di una determinata azione (accensione e spegnimento dei led).

 

Nel video seguente mostro la simulazione del codice visto sopra.