Mis à jour le mercredi 30 novembre 2016
  • 15 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

Vous pouvez obtenir un certificat de réussite à l'issue de ce cours.

J'ai tout compris !

Tableaux et jeux de lumière avec plusieurs LED

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Vous avez maintenant un niveau en programmation et en électricité qui va vous permettre de vous amuser un peu avec les LED. Ce chapitre a pour but de vous apprendre à gagner en autonomie dans l'utilisation de l'Arduino. Il aborde aussi une sorte de variable importante : le tableau.

Vous allez monter en maîtrise en créant deux programmes ainsi que leurs montages correspondants :

  • "Blink à trois" : Blink à trois, un programme qui fait clignoter 3 LED à des temps précis.

  • "GuirLED" : une petite guirlande de 5 LED pour réaliser des figures lumineuses.

J'en profiterai pour aborder le stockage de variables sous forme de tableaux. On est souvent amenés à l'utiliser, mais ce n'est pas toujours simple à réaliser.

L'idéal serait que ces programmes, vous les réalisiez seul(e). Je vais donc vous aider pour le premier, mais pour le second... enfin, nous verrons.

Projet 1 : “Blink à trois”

Ce programme et le montage associé doivent permettre de faire clignoter trois LED à intervalles différents.  Avec cet exercice, vous allez mettre en pratique l’ensemble des notions de programmation et de montage que nous avons vues jusqu’ici.

Voici la description du programme :

  • Les trois LED sont éteintes.

  • Les trois LED s'allument 1 seconde.

  • Après une brève extinction de toutes les LED (1 dixième de seconde), les deux premières restent éteintes et la troisième s'allume une seconde.

  • Extinction brève, puis LED n°1 et LED n°3 éteintes, LED n°2 allumée une seconde.

  • Extinction brève, LED n°1 allumée et LED n°2 et LED n°3 éteintes une seconde.

  • On retourne au début, mais le programme recommence avec un temps d'allumage de 0,8s (8 dixièmes), puis 6 dixièmes, puis 4, puis 2.

  • Le programme recommence au début.

Avant de se lancer dans la programmation, il vaut mieux réfléchir dans un premier temps au montage et se poser les bonnes questions :

  • Est-ce que je branche les LEDs avec la patte + vers le pin ou vers le +5V (nous avons vu précédemment que ça change les branchements et le code) ?

  • Sur quels pins je connecte chaque LED ?

  • Comment j'organise mes connexions sur la breadBoard pour que ce ne soit pas le foutoir ? (surtout pour correctement repérer le sens du courant)

Ensuite il faut se poser les questions liées à la programmation :

  • De quelles variables ai-je besoin, et quels types ?

  • Quel nom donner à mes variables pour m'y retrouver ?

  • Comment résoudre les boucles pour obtenir le résultat ?

 Puis je vous conseille d’utiliser du pseudo-code, c'est-à-dire un code avec du langage humain qui permet de bien voir les boucles de programmation et de projeter les résultats.

Après tout ceci, vous pourrez vous lancer dans votre “vrai” code plus facilement. N’oubliez pas de le commenter un minimum pour qu’il soit clair et lisible.

Bon, ceux qui se sentent d'attaque pour le réaliser, et bien allez-y ! Je ne vous retiens pas ! On se retrouve à la machine à café !

Pour les autres, on va y aller plus tranquille...

Le montage et le test

Le plus simple pour le début est de connecter les pattes + des LEDs vers les pins. L'Arduino supportera la charge de connexion sans souci.

Il faut prévoir une carte Arduino (;)), 3 LED, 3 résistances (entre 100Ω et 1000Ω, par ex : 220Ω chacune), les jumpers, et la breadBoard.

Essayez un peu avant de regarder le résultat qui suit, il n'y a aucun risque si l'Arduino n'est pas connecté.

Montage pour Blink à Trois. Patte + vers pins
Montage pour le programme Blink à Trois (pattes + vers pins)

J'ai utilisé les pins 2, 4 et 6. Vous pouvez utiliser ceux que vous préférez, sauf si vous voulez ajouter des affichages vers le moniteur, dans ce cas, n’utilisez pas les pins 0 et 1.

Vérifiez bien dans votre montage le circuit du courant, l'orientation des pattes des LEDs, les connexions au Gnd ou +5V. Ces gestes deviendront vite une routine.

Bien, maintenant, créons un programme de test pour tester (ha ?) que tout est ok. Un programme de test ne nécessite pas forcément une structure complexe, on veut juste voir si chaque LED s'allume ou s'éteint quand on envoie la commande aux pins concernés.

Là encore je vous propose d'essayer avant de regarder la solution...

int pinLed1, pinLed2, pinLed3; //on peut déclarer plusieurs variables
void setup()
{
  //initialisation des variables
  pinLed1 = 2;
  pinLed2 = 4;
  pinLed3 = 6;
  //initialisation des modes
  pinMode(pinLed1, OUTPUT);
  pinMode(pinLed2, OUTPUT);
  pinMode(pinLed3, OUTPUT);
  //mise à 0V de chaque pin
  digitalWrite(pinLed1, LOW);
  digitalWrite(pinLed2, LOW);
  digitalWrite(pinLed3, LOW);
}
void loop()
{
  //test allumage et repérage des lEDs
  digitalWrite(pinLed1, HIGH);
  delay(500);
  digitalWrite(pinLed2, HIGH);
  delay(500);
  digitalWrite(pinLed3, HIGH);
  delay(500);
  //on éteint tout
  digitalWrite(pinLed1, LOW);
  digitalWrite(pinLed2, LOW);
  digitalWrite(pinLed3, LOW);
  delay(500);
}

Les  delay() mis dans la  loop() permettent de vérifier le fonctionnement de chaque LED l’une après l’autre.

Vous allez me dire : "Ouahou, c'est long non pour un programme de test ?" (Lukas, c'était façon de parler, vous n'étiez pas obligé de poser la question...).

D'une part, avec des copiés-collés bien faits, on gagne du temps, d'autre part, vous allez voir qu'on va en garder une partie pour le vrai programme...

Quelles variables, quelles boucles ?

On voit que l'objectif est finalement de faire s'allumer l'une après l'autre, les trois LED, puis de recommencer avec desdelay() plus courts.

On a déjà les variables pour les LEDs (les nommer pinLed1, pinLed2 et pinLed3 me paraissait bien, libre à vous de donner le nom qui vous convient), il nous faut maintenant la variable qui va faire varier le temps dudelay().

Nous avons deux choix :

  • soit c'est une variable globale (mise en début de programme) que nous allons faire varier par du code,

  • soit c'est une variable de boucle et dans ce cas, c'est la boucle qui s'en charge.

Si on regarde les attentes, on demande de commencer à 1000ms (1 seconde), puis 800, 600,400, et enfin 200 et on recommence. Une boucle est donc très adaptée avec non pas un incrément (augmenter la valeur du compteur) mais un décrément (diminuer la valeur).

On peut donc imaginer une boucle du genre :

for (int temps=1000;temps>=200;temps=temps-200)

... qui veut dire : on met un compteur qui débute à 1 000 ms, qui diminue de 200 ms à chaque tour de boucle, et qui continue de faire des tours de boucles tant qu’il est supérieur ou égal à 200.

Finalement, ça devrait être plus facile que prévu... essayez ! ;)

Voici le premier code que je propose :

// déclaration
int pinLed1, pinLed2, pinLed3; //variables des pins
void setup()
{
  //initialisation des variables
  pinLed1 = 2;
  pinLed2 = 4;
  pinLed3 = 6;
  //initialisation des modes
  pinMode(pinLed1, OUTPUT);
  pinMode(pinLed2, OUTPUT);
  pinMode(pinLed3, OUTPUT);
  //mise à 0V de chaque pin
  digitalWrite(pinLed1, LOW);
  digitalWrite(pinLed2, LOW);
  digitalWrite(pinLed3, LOW);
}
void loop()
{
    //allumage des trois LED durant 1 seconde
    digitalWrite(pinLed3,HIGH);
    digitalWrite(pinLed2,HIGH);
    digitalWrite(pinLed1,HIGH);
    delay(1000);
    //on les éteint toutes brièvement
    digitalWrite(pinLed3, LOW);
    digitalWrite(pinLed2, LOW);
    digitalWrite(pinLed1, LOW);
    delay(100);
  //Boucle de la variable temps qui diminue
  for (int temps = 1000; temps >= 200; temps -= 200)
  {
    //les trois LEDs sont éteintes
    digitalWrite(pinLed1, HIGH);//allumage LED 3
    delay(temps); // pendant la valeur de temps
    digitalWrite(pinLed1,LOW); //on éteint la 3
    delay(100); // court délai, tout est éteint
    digitalWrite(pinLed2, HIGH);//allumage LED 2
    delay(temps); // pendant la valeur de temps
    digitalWrite(pinLed2,LOW); //on éteint la 2
    delay(100);
    digitalWrite(pinLed3, HIGH);//allumage de LED 1
    delay(temps); // pendant la valeur de temps
    digitalWrite(pinLed3, LOW); // on éteint 1
    delay(100);
    //la boucle reprend
  }
  //retour au début de la loop();
}

Le très court délai où tout est éteint n'est pas visible à l'œil nu, mais il existe : delay(100);

Comme pour les programmes précédents, amusez-vous à modifier les valeurs dans la boucle pour en voir les effets et les limites visuelles.

Les tableaux    

Je suis sûr que vos yeux de lynx ont remarqué avec grande sagacité que le code précédent présente des répétitions : on réalise la même opération pour chaque pin. Il existe plusieurs moyens de créer du code qui se répète en l'utilisant plusieurs fois et en changeant les variables. Ici nous allons le faire à l'aide de tableaux.

Qu'est-ce qu'un tableau en programmation ? (Oui Lukas, en programmation, sinon je sais que vous savez ce que c'est !)

C’est une façon de stocker des variables dans un même endroit au lieu de les créer séparément et leur donner des noms différents.

Prenons l'exemple de nos variables de pin dans le code précédent :

  • Elles sont toutes de type "int" ;

  • Seuls leurs numéros sont différents (pinLed1, pinLed2, pinLed3)

  • On les utilise par la suite pour des opérations similaires.

On peut donc facilement utiliser un tableau.

Plutôt que de donner un nom différent à chaque variable de pin, nous allons donc les regrouper dans un tableau nommé “pinLed” par exemple, et il suffira de les repérer dans ce tableau à l’aide d’un numéro.

  Comment déclarer un tableau ?

Il existe plusieurs façons de déclarer un tableau, mais avant tout il vous faut repérer commente écrire des crochets : [  et ].

  • Pour les utilisateurs de Windows, il faut appuyer sur :

Alt Gr + ( ouAlt Gr + )

  • Pour les utilisateurs de mac, c'est la combinaison :

Alt + + ( ou Alt+ )

Il faut maintenant déclarer le tableau pour que l'IDE sache qu'on va utiliser un nom générique pour plusieurs variables. Et bien on le lui dit avec ces fameux crochets !

Dans notre cas c'est un tableau avec des "int". Il n'y aura que trois valeurs à stocker : la valeur du pin pour la LED 1, celle pour la LED 2 et celle pour la LED 3. À la déclaration d'un tableau on doit dire à l'IDE combien de valeurs doit stocker le tableau. Donc pour nous : 3.

Voici le code de déclaration du tableau :

int pinLed[3];

Ça veut dire : ménage un espace dans ta mémoire pour stocker pour un tableau de type "int" avec le nom générique pinLed qui contiendra 3 valeurs.

Ensuite on doit remplir le tableau. Là encore, on a plusieurs choix :

  • Soit on remplit le tableau à la déclaration, on utilise alors des accolades et on sépare les valeurs par des virgules :

    int pinLed[3]={2,4,6};
  • Soit on remplit le tableau valeur par valeur, dans ce cas on indique les valeurs à ranger dans chaque “case” numérotée du tableau :

    int pinLed[3]; // déclaration du tableau
    pinLed[0]=2; // on donne la valeur 2 à la première valeur
    pinLed[1]=4; // 4 à la deuxième
    pinLed[2]=6; // 6 à la troisième

Et comment on va chercher ces valeurs ensuite ?

Ha, je serai toujours impressionné par la pertinence de certaines questions !

Et bien on appelle (ou utilise) une valeur d'un tableau en combinant le nom générique du tableau et la position de la valeur, par exemple pour utiliser la valeur en position 1 on fera :

pinMode(pinLed[1],OUTPUT);

Le programme ira chercher la valeur située en position 1 du tableau (4 dans notre cas) et l'utilisera comme une variable.

Je vous donne donc le code du programme “Blink à trois” modifié pour ranger les variables de pin dans un tableau... Prenez votre temps pour le comprendre.

/*
Pour ce programme on utilise des LEDs connectées sur les pins 2,4 et 6
*/

int  pinLed[3] = {2, 4, 6}; //déclaration et initialisation du tableau
                            //avec les valeurs des pins
void setup()
{
  //Boucle d'initialisation des modes et mise à 0V
  for (int i = 0; i < 3; i++) // i va nous servir pour parcourir le tableau
  {
    pinMode(pinLed[i], OUTPUT); //on utilise les valeurs du tableau
    digitalWrite(pinLed[i], LOW); // l'une après l'autre
  }

}
void loop()
{
  //on allume les 3 LED (ici en utilisant une boucle)
  for (int i = 0; i < 3; i++) // on parcourt le tableau
  {
    digitalWrite(pinLed[i], HIGH);// on allume
  }
  delay(1000); //pendant 1 seconde
  //puis on les éteint brièvement (ici en utilisant leur position dans le tableau)
  digitalWrite(pinLed[0],LOW); // on éteint la 1
  digitalWrite(pinLed[1], LOW); // on éteint la 2
  digitalWrite(pinLed[2],LOW); // on éteint la 3
  delay(100);//délai bref
  
  //Boucle pour diminuer le temps d’allumage des LED
  for (int temps = 1000; temps >= 200; temps -= 200)
  {
    //Les trois LED sont éteintes
    for (int i = 0; i < 3; i++) // t pour parcourir le tableau
    {
      digitalWrite(pinLed[i], HIGH);//on allume la LED correspondante
      delay(temps); // pendant la valeur de temps
      digitalWrite(pinLed[i], LOW); //on éteint la correspondante
      delay(100); // court délai pendant lequel les 3 LED sont éteintes
    }
    //on a allumé les 3 LED pendant une durée “temps”, la boucle reprend avec une valeur “temps” décrémentée
  }
}

Le programme est bien plus court. J'attire votre attention sur la boucle qui permet de "lire" un tableau. On fait varier une variable (tiens donc...) de la position 0 du tableau à sa valeur maximum. Du coup on peut aller chercher les valeurs pour chaque position. On peut aller les chercher directement avec leur numéro de position (ligne 26 à 28) qui est dans le code pour l'exemple.

Nous aurons bien des fois l'occasion d'utiliser des tableaux, dès le programme suivant d’ailleurs, donc ne vous alarmez pas, ça va finir par rentrer.

Le point machine à café

Bon, pour ceux qui ont essayé seul(e)s et qui ont réussi, je vous dis bravo ! C'est important d'aboutir par ses propres moyens (vous Lukas, c'est rarement propre et souvent moyen, mais ne vous découragez pas).

Jetez un œil tout de même à la solution de code que j’ai proposée, car les tableaux solutionnent souvent bien des choses. Attention, il ne s'agit pas d'utiliser un marteau pour écraser une mouche ! 

Je m'explique : un programme est un bon programme quand il répond à la demande, dans un temps court avec un nombre de lignes de code suffisant. Chercher le moins de ligne de code possible est un travail intéressant, mais cela n'aboutit pas toujours au résultat le plus performant.

Chaque test et opération qu'effectue la machine prend un certain nombre de cycles d'horloge (souvenez-vous que votre Arduino est cadencé à 16MHz). Certains tests sont plus rapides que d'autres. 

Il est tout à fait possible de tester le temps pris par une portion de code, nous verrons cela quand nous utiliserons les fonctions liées au temps et des programmes plus complexes (dans le cours de perfectionnement). Je vous ai tout de même fourni un exemple dans un chapitre précédent.

Et maintenant, c’est parti pour le deuxième programme de ce chapitre, la GuirLED !

Projet 2 : Une GuirLED

Le programme que je vous propose de réaliser utilise 5 LED. Je vous laisse choisir les couleurs que vous préférez. L'objectif est de réussir à créer des illuminations variées un peu comme une guirlande.

On essaiera dans les montages de positionner les 5 LED en une ligne assez rapprochée (contrainte de montage). Puis nos LED devront effectuer des "figures" lumineuses variées. Je vais vous proposer 4 figures pour le moment, vous inventerez celles qui vous conviennent !

  • Les LED s'allument de droite à gauche une par une ;

  • Les LED s'allument de gauche à droite une par une ;

  • Les LED s'allument toutes puis s'éteignent de droite à gauche ;

  • Les LEDs s'allument toutes puis s'éteignent de gauche à droite.

Je vous conseille vivement d’utiliser un tableau pour stocker les valeurs des pins de chaque LED. Utiliser un tableau de variables booléennes pour les états d’allumage vous sera également très utile !

Il faut donc deux boucles pour parcourir un double tableau. La boucle qui parcourt les positions des premiers crochets, et celle qui parcourt les positions des seconds crochets.

Imaginons maintenant un tableau qui contient les états de chaque LED en fonction de ce qu'on veut faire, prenons l'exemple de l'allumage de droite à gauche. Le 1 signifie allumé, le 0 éteint :

Séquence

Led1

Led2

Led3

Led4

Led5

000000

1

0000

1

2

000

1

0

3

00

1

0

0

4

0

1

00

0

5

1

000

0

 

 

 

 

 

 

Ce tableau ci-dessus peut être représenté dans notre code par un tableau à double entrée : un tableau de séquences, qui contient un tableau de booléens pour chaque séquence. C’est donc un tableau qui contient 6 tableaux (un tableau par séquence de 0 à 5), avec chacun des 6 tableaux qui contient 5 booléens (un booléen par LED). 

On peut donc utiliser ce tableau à double-entrée pour mettre à jour chaque pin en position HIGH ou LOW.

Réaliser ce programme seul demande un gros effort de compréhension de boucles et de tableaux. Mais si vous êtes motivés, c'est tout à fait faisable. Bien sûr, vous allez devoir faire travailler votre matière grise pour y arriver. Mais je suis sûr que vous brûlez d’envie d’essayer pour devenir de plus en plus autonomes sur vos futurs projets !

Lancez-vous, essayez, persévérez ! 

Solution

Voici le montage proposé pour la GuirLED, vous pouvez modifier les écarts entre les LED si ça vous chante et utiliser la résistance pour vous connecter directement au Gnd depuis la LED.

Montage pour le projet GuirLed
Montage pour le projet GuirLed

Voici maintenant le programme correspondant.

/*
On utilise pour ce programme 5 LED
connectées sur les pins 2,4,6,8 et 10
*/

int pinLed[5]={2,4,6,8,10}; // Tableau listant les pins
//Tableau à double entrée listant l’état (booléen 1 allumé, 0 éteint) des LED à chaque séquence
boolean affichage[25][5]={
  0,0,0,0,0,
  0,0,0,0,1,
  0,0,0,1,0,
  0,0,1,0,0,
  0,1,0,0,0,
  1,0,0,0,0,
  0,0,0,0,0,
  1,0,0,0,0,
  0,1,0,0,0,
  0,0,1,0,0,
  0,0,0,1,0,
  0,0,0,0,1,
  0,0,0,0,0,
  1,1,1,1,1,
  1,1,1,1,0,
  1,1,1,0,0,
  1,1,0,0,0,
  1,0,0,0,0,
  0,0,0,0,0,
  1,1,1,1,1,
  0,1,1,1,1,
  0,0,1,1,1,
  0,0,0,1,1,
  0,0,0,0,1,
  0,0,0,0,0};

void setup() {
  for (int i=0;i<5;i++)
  {
    pinMode(pinLed[i],OUTPUT);
    digitalWrite(pinLed[i],LOW);
  }
  
}

void loop() {
  for (int i=0;i<25;i++) // boucle de séquence d'affichage
  {
    for (int p=0;p<5;p++) // boucle pour chaque pin
    {
      boolean etat=affichage[i][p]; // on va chercher l'état pour le pin
      digitalWrite(pinLed[p],etat); // on met le pin concerné à l'état
    }
    //tous les pins sont dans l'état de la séquence en cours
    delay(300); //petite pause d'affichage
    // on passe à la séquence suivante
  }
  // fin des séquences et on repart au début de la loop()

}

Vous observerez l'initialisation du tableau des séquences d'affichage, il ne faut pas hésiter dans un cas comme celui-ci à organiser correctement votre affichage pour vous y retrouver, on aurait pu écrire le tableau comme suit :

boolean affichage[25][5]={0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,
1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,
0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0};

Mais on voit bien qu'on ne voit rien !

Le tableauaffichage contient bien, dans les deux cas, 25 séries de 5 booléens.

Amusez-vous à expérimenter avec les tableaux et les valeurs dans ce programme. Passez à 10 LED et faites des séquences plus complexes.

Rien ne vous empêche de positionner les diodes différemment (en carré, cercle, ou autre).

Vous voyez que déjà, avec peu de matériel, on peut correctement se martyriser le cerveau, pour finalement un résultat assez sympa !

Vous voici à la fin de la première partie de ce cours. Félicitations !

Dans la seconde partie, vous allez pouvoir ajouter de nouveaux composants et matériels à votre Arduino et bien sûr de apprendre de nouvelles instruction pour le programmer ! D'ailleurs, le premier chapitre va vous donner des boutons !

Exemple de certificat de réussite
Exemple de certificat de réussite