Led multi-modes - Contrôle tactile : Différence entre versions
(→Choix du Wemos) |
m (→Code) |
||
(3 révisions intermédiaires par le même utilisateur non affichées) | |||
Ligne 99 : | Ligne 99 : | ||
// ICACHE_RAM_ATTR : force le stockage de cette fonction dans la RAM, | // ICACHE_RAM_ATTR : force le stockage de cette fonction dans la RAM, | ||
// sinon elle est stockée dans la mémoire flash, et forcément ça plante | // sinon elle est stockée dans la mémoire flash, et forcément ça plante | ||
+ | // Cela est spécifique pour le wemos, attribut à supprimer si utilisation d'un Arduino. | ||
ICACHE_RAM_ATTR void configLedMode() { | ICACHE_RAM_ATTR void configLedMode() { | ||
// stocke la dernière fois que le mode a été effectivement modifié | // stocke la dernière fois que le mode a été effectivement modifié | ||
Ligne 120 : | Ligne 121 : | ||
case 0: // ruban led éteint | case 0: // ruban led éteint | ||
ledFonction = rubanOff; | ledFonction = rubanOff; | ||
+ | led_delai = 0; // force la sortie des boucles "for" du mode précédent | ||
break; | break; | ||
Ligne 149 : | Ligne 151 : | ||
// éteint les led | // éteint les led | ||
void rubanOff() { | void rubanOff() { | ||
− | |||
− | |||
− | |||
// éteint les led en passant la luminosité à 0 et le couleur des led à 0 | // éteint les led en passant la luminosité à 0 et le couleur des led à 0 | ||
ruban.setBrightness(0); | ruban.setBrightness(0); | ||
Ligne 239 : | Ligne 238 : | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |||
===Explications=== | ===Explications=== | ||
====Chargement du programme==== | ====Chargement du programme==== | ||
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 | + | 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|Améliorations/Evolutions]]'''. |
====Spécificités du code C++==== | ====Spécificités du code C++==== | ||
'''Interruption''' | '''Interruption''' | ||
− | Dans ce programme, on utilise le | + | 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 | + | 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''' | '''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é. | 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/Evolutions== | ||
'''Améliorations''' | '''Améliorations''' |
Version actuelle datée du 14 mai 2024 à 08:58
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 // 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 :
- 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 é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 ...