Le multitasking sur Arduino

Partage et review :

Introduction Materiel Prérequis Objectif

Description

Si vous avez déjà codé sur Arduino, vous avez sûrement déjà utilisé la fonction retard ou delay() (notamment pour faire clignoter une simple LED dans blink).  Mais ceux-ci demandent à l’Arduino d’attendre et ne permettent pas de réaliser d’autres tâches en parallèle.

Dans ce cours nous allons apprendre l’astuce pour permettre le multitâche ou multitasking sur Arduino.

materiaux

  • Carte Arduino
  • LED
  • Jumpers
  • Breadboard

Prérequis

Connaitre le fonctionnement d’un code arduino et/ou avoir suivi ce cours : Votre premier code arduino.

Objectifs

Apprendre à écrire un code permettant de réaliser plusieurs taches demandant de l’attente en même temps.

Le problème

Nous savons faire clignoter une LED avec la fonction delay(), comme ici:

 digitalWrite(13, HIGH);
 delay(1000);
 digitalWrite(13, LOW);

…pour allumer la LED branchée en position 13 pendant 1 seconde (1000 millisecondes).

 

Cependant, cette commande bloque le système et ne permet pas qu’une autre tâche soit réalisée en même temps.

Voici par exemple un programme que l’on aurait pu écrire pour faire clignoter une LED toutes les secondes et augmenter un compteur toutes les 1.5 secondes:

int led = 13;
int compteur = 0;

void setup() {

 pinMode(led, OUTPUT);
 Serial.begin(9600); //ouvre la communication avec la console
}

void loop() {
 digitalWrite (led, HIGH);
 delay(1000);
 digitalWrite (led, LOW);
 delay(1000);
 Serial.println(compteur); //on inscrit la valeur du compteur dans la console
 compteur = compteur + 1; //on augmente la valeur du compter
 delay(1500);
}

Voici deux frises: une avec le résultat attendu et une avec le résultat obtenu.

Il est très clair que nous sommes très loin du programme que nous voulions créer.

Evidemment, il est possible de bidouiller un programme en calculant les écarts, comme ici…

void loop() {
Serial.println(compteur);
compteur = compteur+1;
digitalWrite (led, HIGH);
delay(1000);
digitalWrite (led, LOW);
delay(500);
Serial.println(compteur);
compteur = compteur+1;
delay(500);
digitalWrite (led, HIGH);
delay(1000);
Serial.println(compteur);
compteur = compteur+1;
digitalWrite (led, LOW);
delay(1000);
digitalWrite (led, HIGH);
delay(500);
Serial.println(compteur);
compteur = compteur+1;
delay(500);
digitalWrite (led, LOW);
delay(1000);
}

…mais c’est très lourd à écrire, et n’en parlons pas si l’on veut modifier les délais pour avoir 7 et 11 secondes par exemple.

 

C’est pourquoi je vais vous présenter une solution simple pour que votre carte Arduino puisse réaliser simultanément plusieurs tâches.

Le multitasking : une soustraction, et le tour est joué !

Pour faire répéter  une action apres un certain intervalle sans pour autant mettre le système sur pause, nous allons utiliser l’horloge de l’Arduino.

Le principe est simple : il consiste à garder en mémoire la dernière fois que l’action a été effectuée et vérifié quand l’intervalle a été dépassé.

Illustration avec la frise ci-dessous en prenant l’exemple d’une LED;

On crée dans un premier temps une variable que l’on nommera « derniereAction »

unsigned long derniereAction= 0;

À chaque fois que l’on fait cette action, on enregistre « l’instant » dans cette variable gràce à la fonction millis() qui retourne le temps écoulé depuis l’allumage de l’Arduino en millisecondes.

derniereAction = millis();

 

Avant chaque action, on va vérifier si il est temps ou non de la réaliser.

Par une soustraction, nous pourrons ensuite calculer le temps depuis lequel l’action a été réalisée.

heure actuelle – heure à laquelle on a fait l’action précédemment = temps écoulé depuis celle-ci

En traduisant ceci en code Arduino, voici comment nous obtenons la valeur recherchée:

millis() - derniereAction

En comparant cette valeur à l’intervalle  (ici une seconde) voulu, on sait alors si il est temps de réaliser l’action.

int derniereAction = 0;



void loop() {
 if (millis() - derniereAction >= 1000) {
   //code de l'action à réaliser
   derniereAction = millis();
 }
}

Enfin, nous devons redéfinir notre variable derniereAction en lui donnant comme valeur l’instant actuel.

Ainsi , quand le programme continuera sa boucle et qu’il retombera sur cette ligne, il refera la comparaison mais ne réalisera rien tant que le temps écoulé ne sera pas supérieur ou égal au délai souhaité.

 

Pour chaque action voulue, il nous faudra alors créer une variable qui hébergera l’instant de la dernière occurrence de l’action. Vous pourrez ainsi créer plusieurs tâches alternées ou superposées à votre carte Arduino, sans bloquer la totalité de votre carte !

Application

Nous allons conserver du code précédent la variable et le setup qui ne changent pas.

int led = 13;
int compteur = 0;

void setup() {

 pinMode(led, OUTPUT);
 Serial.begin(9600);  //ouvre la communication avec la console
}

 

Mais nous allons aussi ajouter de nouvelles variables que l’on utilisera pour notre multitasking.

unsigned long ledModifiee = 0;   //dernier moment ou la LED a changé d'état
unsigned long compModifie = 0;   //dernier moment ou l'on a activé le compteur

 

Le clignotement de la LED est géré dans la loop par :

 if (millis() - ledModifiee >= 1000) {  //verifie si le delai est ecoule
  if (digitalRead(led) == LOW) {  //Si led éteinte
   digitalWrite(led, HIGH);       // on l'allume
  }
  else {                      //sinon
   digitalWrite(led, LOW); // on l'éteint
  }
 }
 ledModifiee = millis(); // on enregistre l'instant

Il ne faut surtout pas oublier de remplacer la valeur de ledModifiee sinon le programme pensera que l’action n’a jamais été réalisée et changera son état aussi vite qu’il le pourra : le délai ne sera pas respecté !

Pour le compteur, même chose :

if (millis() - compModifie >= 1500) { //verifie si le delai est ecoule

  compteur = compteur + 1;
  Serial.println(compteur);     //affiche la valeur du compteur dans la console
  compModifie = millis();       //on remplace compModifie par l'instant
}

Voici donc un aperçu du programme complet :

int led = 13;
int compteur = 0;

unsigned long ledModifiee = 0; //dernier moment ou la LED a changé d'état
unsigned long compModifie = 0; //dernier moment ou l'on a activé du compteur


void setup() {

 pinMode(led, OUTPUT);
 Serial.begin(9600); //ouvre la communication avec la console
}


void loop() {

 if (millis() - ledModifiee >= 1000) { //verifie si le delai est ecoule

 if ( digitalRead(led) == LOW ) { //si la LED est éteinte
 digitalWrite (led, HIGH); //l'allumer
 }
 else { //sinon
 digitalWrite (led, LOW); // l'éteindre
 }

 ledModifiee = millis(); //on enregistre l'instant
 }



 if (millis() - compModifie >= 1500) { //verifie si le delai est ecoule

 compteur = compteur + 1;
 Serial.println(compteur); //affiche la valeur du compteur dans la console
 compModifie = millis(); //on remplace compModifie par l'instant
 }

}

Félicitations, vous pouvez à présent réaliser plusieurs tâches à la fois sur votre Arduino ! Cela ne rendra pas la fonction delay() obsolète, elle restera utile dans certains cas, mais d’ans d’autres, elle est moins adaptée.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *