Led multi-modes - Contrôle tactile : Différence entre versions
(→Choix du Wemos) |
|||
Ligne 269 : | Ligne 269 : | ||
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''). | 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==== | ====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 est 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. Dans la partie ''[[#Améliorations/Evolutions|Améliorations/Evolutions]]''', une piste alternative, autre qu'Arduino, est proposée. | + | 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 est 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. Dans la partie '''[[#Améliorations/Evolutions|Améliorations/Evolutions]]''', une piste alternative, autre qu'Arduino, est proposée. |
+ | |||
====Spécificités du code C++==== | ====Spécificités du code C++==== | ||
'''Interruption''' | '''Interruption''' |
Version du 13 mai 2024 à 13:47
Sommaire
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 :
- Connecter les matériel comme indiqué ci-dessous dans la partie Schéma ;
- Télécharger le programme dans le D1 mini Wemos (cf. Code) ;
- Et c'est fini.
Schéma
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 ICACHE_RAM_ATTR void configLedMode() {
76 // stocke la dernière fois que le mode a été effectivement modifié
77 // pour mémoire 1 changement de mode par seconde au maximum (cf. ligne 33 : dureeAntiRebond)
78 static unsigned long date_mode_precedent = 0;
79
80 // récupère l'instant actuel
81 unsigned long date = millis();
82 // si dernier changement de mode depuis plus d'une seconde alors on traite le signal
83 if ((date - date_mode_precedent) > dureeAntiRebond) {
84 // enregistre l'instant actuel
85 date_mode_precedent = date;
86 // incrémente le mode
87 led_mode++;
88
89 // modifie la fonction ledFonction selon le mode choisi
90 switch(led_mode)
91 {
92 default: // mode hors porté, alors repasse le mode à 0
93 led_mode = 0;
94 case 0: // ruban led éteint
95 ledFonction = rubanOff;
96 break;
97
98 case 1: // couleur unie rouge
99 ledFonction = rubanCouleurRouge;
100 ruban.setBrightness(50);
101 break;
102
103 case 2: // couleur unie verte
104 ledFonction = rubanCouleurVerte;
105 break;
106
107 case 3: // couleur unie bleue
108 ledFonction = rubanCouleurBleue;
109 break;
110
111 case 4: // arc-en-ciel en boucle
112 ledFonction = arcEnCiel;
113 break;
114
115 case 5: // arc-en-ciel en boucle avec harmonisation des couleurs
116 led_delai = 0; // force la sortie des boucles "for" du mode précédent
117 ledFonction = arcEnCielCycle;
118 break;
119 }
120 }
121 }
122
123 // éteint les led
124 void rubanOff() {
125 // permet de forcer la sortie des boucles arc-en-ciel
126 led_delai = 0;
127
128 // éteint les led en passant la luminosité à 0 et le couleur des led à 0
129 ruban.setBrightness(0);
130 rubanCouleurUnie(0);
131 ruban.show();
132
133 // passe en attente du prochain changement de mode
134 ledFonction = rubanAttente;
135 }
136
137 // ne fait rien
138 void rubanAttente() {
139 delay(1);
140 }
141
142 // Applique la même couleur à toutes les led du ruban
143 // Puis modifie la fonction ledFonction pour passer en attente
144 void rubanCouleurUnie(uint32_t couleur) {
145 for(uint16_t num_led = 0; num_led < ruban.numPixels(); num_led++) {
146 ruban.setPixelColor(num_led, couleur);
147 }
148 ruban.show();
149
150 // passe en attente du prochain changement de mode
151 ledFonction = rubanAttente;
152 }
153
154 void rubanCouleurRouge() {
155 rubanCouleurUnie(ruban.Color(255, 0, 0));
156 }
157
158 void rubanCouleurVerte() {
159 rubanCouleurUnie(ruban.Color(0, 255, 0));
160 }
161
162 void rubanCouleurBleue() {
163 rubanCouleurUnie(ruban.Color(0, 0, 255));
164 }
165
166 // fait varier la couleur des led en arc-en-ciel
167 void arcEnCiel() {
168 arcEnCiel(false);
169 }
170
171 // fait varier la couleur des led en arc-en-ciel tout en faisant en sorte que les couleurs soient équilibrées/adoucies entre-elles
172 void arcEnCielCycle() {
173 arcEnCiel(true);
174 }
175
176 // faire varier les couleurs des led
177 void arcEnCiel(bool harmonise) {
178 uint16_t num_led, id_couleur;
179
180 // paramètre le taux de rafraichissement des changements de couleurs
181 led_delai = LED_DELAI;
182
183 // si vrai, permet d'harmoniser les couleurs des led entre-elles
184 harmonise = (harmonise) ? 256 / ruban.numPixels() : 1;
185
186 // varaiation de la couleur des led
187 while(led_delai) {
188 for(id_couleur = 0; id_couleur < 256 && led_delai; id_couleur++) {
189 // applique à chaque led une nuance de couleur différente selon la couleur souhaitée
190 for(num_led = 0; num_led < ruban.numPixels() && led_delai; num_led++) {
191 ruban.setPixelColor(num_led, cycleRoue(((num_led * harmonise) + id_couleur) & 255));
192 }
193 ruban.show();
194 delay(led_delai);
195 }
196 }
197 }
198
199 // permet de boucler sur les transitions des couleurs : rouge/vert/bleu/rouge/vert/...
200 uint32_t cycleRoue(byte position_cycle) {
201 position_cycle = 255 - position_cycle;
202
203 // selon la valeur demandée, applique une nuance de couleur
204 if(position_cycle < 85) {
205 return ruban.Color(255 - position_cycle * 3, 0, position_cycle * 3);
206 }
207 if(position_cycle < 170) {
208 position_cycle -= 85;
209 return ruban.Color(0, position_cycle * 3, 255 - position_cycle * 3);
210 }
211 position_cycle -= 170;
212 return ruban.Color(position_cycle * 3, 255 - position_cycle * 3, 0);
213 }
Explications
Chargement du programme
Voici les étapes à suivre afin de pourvoir charger le programme sur le D1 mini Wemos :
- Lancez le programme Arduino IDE
- Ajoutez la carte Wemos aux cartes pouvant être gérées par l'IDE Arduino
- Ajoutez une carte supplémentaire à partir de menu Fichier > Préférences ;
- Dans l'onglet "Paramètres" cliquez sur le bouton situé en face de "URL de gestionnaire de cartes supplémentaires" :
- Ajoutez le lien suivant dans la fenêtre qui s'est ouverte et validez : https://arduino.esp8266.com/stable/package_esp8266com_index.json
- Ajoutez les librairies permettant de gérer les cartes à base d'ESP8266 (menu Outils > Carte > Gestionnaire de carte) ;
- Dans l'onglet qui s'ouvre, tapez "ESP8266" dans la barre de recherche ;
- Sélectionnez la carte "ESP8266 par ESP8266 Community" et installez-la ;
- Ajoutez la bibliothèque Neopixel permettant de contrôler le ruban LED
- Allez dans le menu Outils > Gérer les bibliothèques ;
- Dans la barre de recherche, saisissez : neopixel ;
- Sélectionnez la bibliothèque Adafruit Neopixel par Adafruit ;
- Copiez et téléversez le programme
- Copiez le code dans l'interface Arduino IDE ;
- Dans le menu "Outils > Carte", sélectionnez "esp8266 > LOLIN (WEMOS) D1 R2 & Mini", ainsi que le port série (menu Outils > Port) ;
- 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 :
- Eteint
- Couleur unie rouge
- Couleur unie verte
- Couleur unie bleue
- Arc-en-ciel
- 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 est 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. Dans la partie Améliorations/Evolutions, une piste alternative, autre qu'Arduino, est proposée.
Spécificités du code C++
Interruption
Dans ce programme, on utilise le système d'interruptions pour basculer d'un mode d'éclairage à un autre.
Dans notre cas, on utilise le système 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 ...