Led multi-modes - Contrôle tactile

De Les Fabriques du Ponant
Aller à : navigation, rechercher

Description

Contrôler une led RGB, un led ring ou ici un ruban led (led strip), grâce à un bouton tactile. A chaque contact détecté par le bouton tactile, le mode de contrôle des led est changé.

Liste du matériel

Électronique

  • 1 x Module Wifi D1 Mini Wemos ou 1 x Arduino UNO ou équivalent
  • 1 x Ruban de LED 1 mètre/60 LED
  • Câbles Dupont M-F et M-M
  • 1 x Bouton tactile TTP223
  • 1 x mini breadboard

Coût

Pour l'ensemble du matériel et en étant large, il faut compter moins de 30€.

Réalisation du projet

La réalisation de ce projet est relativement simple. Elle se résume en 3 étapes :

  1. Connecter les matériel comme indiqué ci-dessous dans la partie Schéma ;
  2. Télécharger le programme dans le D1 mini Wemos (cf. Code) ;
  3. Et c'est fini.

Schéma

Schéma circuit Led Touch.jpeg

Code

Certaines lignes sont surlignées en jaune. Ces lignes identifient les paramètres qui peuvent être modifiés sans risque afin de s'adapter aux spécificités et choix faits pour votre projet.

  1 #include <Adafruit_NeoPixel.h>
  2 
  3 // définition d'un type pour faciliter la déclaration des fonctions liées aux interruptions
  4 typedef void (*LED_MODE_FUNC)();
  5 
  6 // broche du wemos sur laquelle est connectée le ruban de led
  7 #define PIN_RUBAN_LED       D3
  8 // broche du wemos sur laquelle est connecté le bouton tactile TP223
  9 #define PIN_BOUTON_TACTILE  D2
 10 // nombre de led sur le ruban
 11 #define NB_LED              60
 12 
 13 // permet de suivre le mode dans lequel sont configurées les led (couleur unique, arc-en-ciel, etc.)
 14 /************************************/
 15 /* par défaut 6 modes :             */
 16 /*     - 0 : éteint                 */
 17 /*     - 1 : couleur unique (rouge) */
 18 /*     - 2 : couleur unique (vert)  */
 19 /*     - 3 : couleur unique (bleu)  */
 20 /*     - 4 : arc-en-ciel            */
 21 /*     - 5 : arc-en-ciel harmonisé  */
 22 /************************************/
 23 volatile byte led_mode = 0;
 24 // permet de switcher de mode d'affichage selon le mode actif
 25 volatile LED_MODE_FUNC ledFonction = NULL;
 26 
 27 // permet de forcer les fonctions contrôlant les led à sortir de leurs boucles,
 28 // et à contrôler les temps de bascule entre deux changements de couleur dans les modes arc-en-ciel
 29 volatile byte led_delai = 0;
 30 // délai par défaut entre deux changements de couleur en mode arc-en-ciel
 31 const byte LED_DELAI = 20;
 32 // définit la durée d'attente entre 2 changements de mode en milliseconde
 33 const unsigned long dureeAntiRebond = 1000;
 34 
 35 // initialise le ruban led
 36 // paramètre 1 = nombre de led dans le ruban
 37 // paramètre 2 = numéro de la broche sur laquelle est connecté le ruban
 38 // paramètre 3 = configuration des led du ruban
 39 //   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
 40 //   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
 41 //   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
 42 //   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
 43 //   NEO_RGBW    Pixels are wired for RGBW bitstream (NeoPixel RGBW products)
 44 Adafruit_NeoPixel ruban = Adafruit_NeoPixel(NB_LED, PIN_RUBAN_LED, NEO_GRB + NEO_KHZ800);
 45 
 46 /***************************************************************************************/
 47 /* Pour réduire le risque d'endommager le ruban led :                                  */
 48 /*   - ajouter un condensateur de 1000µF entre le vcc et la masse alimentant le ruban  */
 49 /*   - ajouter un résistance de 300/500 ohms entre le wemos et le câble data du ruban  */
 50 /*   - réduire au maximum la distance entre le wemos et le ruban led                   */
 51 /*   - si branchement à chaud, connecter en 1e la masse du ruban led                   */
 52 /***************************************************************************************/
 53 
 54 void setup() {
 55   ruban.begin();
 56   // force la luminosité du ruban à 0 (ruban éteint)
 57   ruban.setBrightness(0);
 58   ruban.show();
 59   // initialise la fonction paramétrant les led du ruban à rubanOff
 60   ledFonction = rubanOff;
 61   // initialise la broche du bouton tactile en pull up afin d'éviter les faux signaux
 62   pinMode(PIN_BOUTON_TACTILE, INPUT_PULLUP);
 63   // lie le bouton tactile à une interruption qui déclenche la fonction configLedMode
 64   attachInterrupt(digitalPinToInterrupt(PIN_BOUTON_TACTILE), configLedMode, FALLING);
 65 }
 66 
 67 void loop() {
 68   // exécute la fonction liée au mode d'affichage sélectionné par l'utilisateur
 69   ledFonction();
 70 }
 71 
 72 // fonction déclenchée par interruption via le bouton tactile
 73 // ICACHE_RAM_ATTR : force le stockage de cette fonction dans la RAM,
 74 // sinon elle est stockée dans la mémoire flash, et forcément ça plante
 75 // Cela est spécifique pour le wemos, attribut à supprimer si utilisation d'un Arduino.
 76 ICACHE_RAM_ATTR void configLedMode() {
 77   // stocke la dernière fois que le mode a été effectivement modifié
 78   // pour mémoire 1 changement de mode par seconde au maximum (cf. ligne 33 : dureeAntiRebond)
 79   static unsigned long date_mode_precedent = 0;
 80 
 81   // récupère l'instant actuel
 82   unsigned long date = millis();
 83   // si dernier changement de mode depuis plus d'une seconde alors on traite le signal
 84   if ((date - date_mode_precedent) > dureeAntiRebond) {
 85     // enregistre l'instant actuel
 86     date_mode_precedent = date;
 87     // incrémente le mode
 88     led_mode++;
 89 
 90     // modifie la fonction ledFonction selon le mode choisi
 91     switch(led_mode)
 92     {
 93       default: // mode hors porté, alors repasse le mode à 0
 94         led_mode = 0;
 95       case 0: // ruban led éteint
 96         ledFonction = rubanOff;
 97         led_delai = 0;  // force la sortie des boucles "for" du mode précédent
 98       break;
 99 
100       case 1: // couleur unie rouge
101         ledFonction = rubanCouleurRouge;
102         ruban.setBrightness(50);
103       break;
104 
105       case 2: // couleur unie verte
106         ledFonction = rubanCouleurVerte;
107       break;
108 
109       case 3: // couleur unie bleue
110         ledFonction = rubanCouleurBleue;
111       break;
112 
113       case 4: // arc-en-ciel en boucle
114         ledFonction = arcEnCiel;
115       break;
116 
117       case 5: // arc-en-ciel en boucle avec harmonisation des couleurs
118         led_delai = 0;  // force la sortie des boucles "for" du mode précédent
119         ledFonction = arcEnCielCycle;
120       break;
121     }
122   }
123 }
124 
125 // éteint les led
126 void rubanOff() {
127   // éteint les led en passant la luminosité à 0 et le couleur des led à 0
128   ruban.setBrightness(0);
129   rubanCouleurUnie(0);
130   ruban.show();
131 
132   // passe en attente du prochain changement de mode
133   ledFonction = rubanAttente;
134 }
135 
136 // ne fait rien
137 void rubanAttente() {
138   delay(1);
139 }
140 
141 // Applique la même couleur à toutes les led du ruban
142 // Puis modifie la fonction ledFonction pour passer en attente
143 void rubanCouleurUnie(uint32_t couleur) {
144   for(uint16_t num_led = 0; num_led < ruban.numPixels(); num_led++) {
145     ruban.setPixelColor(num_led, couleur);
146   }
147   ruban.show();
148 
149   // passe en attente du prochain changement de mode
150   ledFonction = rubanAttente;
151 }
152 
153 void rubanCouleurRouge() {
154   rubanCouleurUnie(ruban.Color(255, 0, 0));
155 }
156 
157 void rubanCouleurVerte() {
158   rubanCouleurUnie(ruban.Color(0, 255, 0));
159 }
160 
161 void rubanCouleurBleue() {
162   rubanCouleurUnie(ruban.Color(0, 0, 255));
163 }
164 
165 // fait varier la couleur des led en arc-en-ciel
166 void arcEnCiel() {
167   arcEnCiel(false);
168 }
169 
170 // fait varier la couleur des led en arc-en-ciel tout en faisant en sorte que les couleurs soient équilibrées/adoucies entre-elles
171 void arcEnCielCycle() {
172   arcEnCiel(true);
173 }
174 
175 // faire varier les couleurs des led
176 void arcEnCiel(bool harmonise) {
177   uint16_t num_led, id_couleur;
178 
179   // paramètre le taux de rafraichissement des changements de couleurs
180   led_delai = LED_DELAI;
181 
182   // si vrai, permet d'harmoniser les couleurs des led entre-elles
183   harmonise  = (harmonise) ? 256 / ruban.numPixels() : 1;
184 
185   // varaiation de la couleur des led
186   while(led_delai) {
187     for(id_couleur = 0; id_couleur < 256 && led_delai; id_couleur++) {
188       // applique à chaque led une nuance de couleur différente selon la couleur souhaitée
189       for(num_led = 0; num_led < ruban.numPixels() && led_delai; num_led++) {
190         ruban.setPixelColor(num_led, cycleRoue(((num_led * harmonise) + id_couleur) & 255));
191       }
192       ruban.show();
193       delay(led_delai);
194     }
195   }
196 }
197 
198 // permet de boucler sur les transitions des couleurs : rouge/vert/bleu/rouge/vert/...
199 uint32_t cycleRoue(byte position_cycle) {
200   position_cycle = 255 - position_cycle;
201 
202   // selon la valeur demandée, applique une nuance de couleur
203   if(position_cycle < 85) {
204     return ruban.Color(255 - position_cycle * 3, 0, position_cycle * 3);
205   }
206   if(position_cycle < 170) {
207     position_cycle -= 85;
208     return ruban.Color(0, position_cycle * 3, 255 - position_cycle * 3);
209   }
210   position_cycle -= 170;
211   return ruban.Color(position_cycle * 3, 255 - position_cycle * 3, 0);
212 }

Explications

Chargement du programme

Voici les étapes à suivre afin de pourvoir charger le programme sur le D1 mini Wemos :

  1. Lancez le programme Arduino IDE
  2. Ajoutez la carte Wemos aux cartes pouvant être gérées par l'IDE Arduino
    1. Ajoutez une carte supplémentaire à partir de menu Fichier > Préférences ;
    2. Dans l'onglet "Paramètres" cliquez sur le bouton situé en face de "URL de gestionnaire de cartes supplémentaires" :
      Config ide arduino esp8266.jpg
    3. Ajoutez le lien suivant dans la fenêtre qui s'est ouverte et validez : https://arduino.esp8266.com/stable/package_esp8266com_index.json
    4. Ajoutez les librairies permettant de gérer les cartes à base d'ESP8266 (menu Outils > Carte > Gestionnaire de carte) ;
    5. Dans l'onglet qui s'ouvre, tapez "ESP8266" dans la barre de recherche ;
    6. Sélectionnez la carte "ESP8266 par ESP8266 Community" et installez-la ;
  3. Ajoutez la bibliothèque Neopixel permettant de contrôler le ruban LED
    1. Allez dans le menu Outils > Gérer les bibliothèques ;
    2. Dans la barre de recherche, saisissez : neopixel ;
    3. Sélectionnez la bibliothèque Adafruit Neopixel par Adafruit ;
  4. Copiez et téléversez le programme
    1. Copiez le code dans l'interface Arduino IDE ;
    2. Dans le menu "Outils > Carte", sélectionnez "esp8266 > LOLIN (WEMOS) D1 R2 & Mini", ainsi que le port série (menu Outils > Port) ;
    3. Compilez et téléversez vers le D1 Mini Wemos.

Fonctionnement général

Par défaut, 6 modes de fonctionnement sont programmés pour contrôler l'éclairage des led :

  1. Eteint
  2. Couleur unie rouge
  3. Couleur unie verte
  4. Couleur unie bleue
  5. Arc-en-ciel
  6. Arc-en-ciel v2

Pour basculer d'un mode à l'autre, il suffit d'appuyer sur le bouton tactile. Si l'on appuie lorsque le dernier mode est en cours d'exécution, alors le programme boucle sur le 1e mode (ici Eteint).

Choix du Wemos

De prime abord, le choix d'un contrôleur type Wemos n'est pas celui qui viendrait naturellement à l'esprit. Cependant, ce choix a été fait d'une part pour son prix et d'autre part pour sa petite taille. L'origine de ce projet était d'intégrer ce système de contrôle de ruban led dans un boîtier imprimé en 3D créant un jeu d'ombres chinoises. Aussi, fallait-il que le contrôleur soit le plus petit possible, et le Wemos (sans ses broches) était ce qu'il y avait de plus petit dans les tiroirs. De plus, dans ce projet le breadbord n'a pas été utilisé, de même pour les broches, et les soudures entre les différents éléments électroniques ont été minimalisées au maximum. Toujours dans cet esprit de minimalisation, une piste alternative, autre qu'Arduino, est proposée dans la partie Améliorations/Evolutions.

Spécificités du code C++

Interruption

Dans ce programme, on utilise le mécanisme des interruptions pour basculer d'un mode d'éclairage à un autre.

Dans notre cas, on utilise le mécanismes des interruptions afin que lorsque l'on appuie sur le bouton tactile le basculement du mode d'éclairage au suivant soit instantané. Effectivement, si l'on n'utilisait pas les interruptions, cela signifierait que les appuis sur le bouton tactile ne seraient pas toujours pris en compte. La lecture de l'état du bouton tactile interviendrait uniquement au moment où l'instruction correspondante est exécutée. Dans cette hypothèse, si l'utilisateur appuie au moment où le programme rentre dans une boucle un peu longue, alors l'appui ne sera pas détecté. Ainsi, afin de pallier cet écueil, les changements d'état du bouton tactile sont associés au déclenchement d'une interruption. Dans ce cas, dès qu'un changement d'état est opéré au niveau du bouton tactile, cela déclenche une interruption qui met en pause le fonctionnement normal du programme pour aller exécuter prioritairement la partie du code associée à ladite interruption avant de reprendre l'exécution normale du programme.

Pointeur de fonctions

Afin de faciliter et simplifier l'écriture de ce code, il a été choisi d'utiliser un pointeur de fonction. Sans entrer dans les détails, en C++ un pointeur de fonction se comporte comme une variable à laquelle il est possible d'assigner des valeurs. Ici, les valeurs assignées seront des fonctions. Ces fonctions correspondent individuellement à un mode d'éclairage. Ainsi, dans la boucle principale du programme une seule instruction est exécutée qui correspond à l'appel de la fonction ledFonction(). Cette fonction un peu particulière est en fait le pointeur de fonction qui pointera in fine vers le code à exécuter associé au mode de fonctionnement sélectionné.

Améliorations/Evolutions

Améliorations

En termes d'amélioration, quelques recommandations doivent être appliquées (non mises en œuvre dans ce projet). Celles-ci concernent la réalisation du câblage et plus particulièrement la protection du ruban led contre les risques d'endommagement :

  • ajouter un condensateur de 1000µF entre le vcc et la masse alimentant le ruban ;
  • ajouter un résistance de 300/500 ohms entre le wemos et le câble data du ruban ;
  • réduire au maximum la distance entre le wemos et le ruban led ;
  • si branchement à chaud, connecter en 1e la masse du ruban led.

Evolutions

Afin de travailler sur la miniaturisation de l'électronique, il serait intéressant d'étudier son portage sur un microcontrôleur type ATTiny85.

A vous de jouer ...