WS2812B 8x32 256pixels
This commit is contained in:
@@ -0,0 +1,387 @@
|
||||
/*
|
||||
* =============================================================================
|
||||
* MATRICE LED WS2812B 8 x 32 (256 pixels) — Arduino Uno + FastLED
|
||||
* Workshop « Vitrine pixels »
|
||||
* =============================================================================
|
||||
*
|
||||
* Avant de téléverser ce programme, lisez le README.md de ce dossier
|
||||
* et vérifiez le branchement avec schema_branchement.svg.
|
||||
*
|
||||
*
|
||||
* CE QUI CHANGE PAR RAPPORT À LA MAQUETTE 3 x 3
|
||||
* ---------------------------------------------
|
||||
* Sur la maquette 3 x 3, l'Arduino devait allumer lui-même chaque ligne,
|
||||
* très vite, l'une après l'autre (le multiplexage). Il fallait 12 fils.
|
||||
*
|
||||
* Ici, chaque LED (WS2812B) contient une minuscule puce électronique.
|
||||
* Les 256 LED sont reliées les unes aux autres en une longue CHAÎNE,
|
||||
* et l'Arduino ne leur parle que par UN SEUL FIL : le fil de données.
|
||||
*
|
||||
* Imaginez une file de 256 personnes qui se passent un paquet de lettres :
|
||||
* - l'Arduino envoie une longue suite de couleurs dans le fil ;
|
||||
* - la 1re LED garde la 1re couleur pour elle, et transmet le reste ;
|
||||
* - la 2e LED garde la couleur suivante, et transmet le reste ;
|
||||
* - … et ainsi de suite jusqu'à la 256e.
|
||||
* Puis chaque LED garde sa couleur affichée jusqu'au prochain envoi.
|
||||
* Plus besoin de balayage : chaque LED « se souvient » de sa couleur.
|
||||
*
|
||||
* L'avantage : un seul fil de données, et chaque LED peut avoir n'importe
|
||||
* laquelle de 16 millions de couleurs (256 niveaux de rouge × 256 de vert
|
||||
* × 256 de bleu), au lieu des 8 couleurs « tout ou rien » de la maquette.
|
||||
*
|
||||
*
|
||||
* BIBLIOTHÈQUE NÉCESSAIRE : FastLED
|
||||
* ---------------------------------
|
||||
* Dans l'IDE Arduino : menu Outils → Gérer les bibliothèques…
|
||||
* → chercher « FastLED » → Installer.
|
||||
* FastLED s'occupe d'envoyer les couleurs dans le fil, au bon rythme
|
||||
* (800 000 bits par seconde !). Nous, on se contente de remplir un tableau
|
||||
* de couleurs, puis de dire « envoie » avec FastLED.show().
|
||||
*
|
||||
*
|
||||
* ORGANISATION DU PROGRAMME
|
||||
* -------------------------
|
||||
* 1. Réglages : broche, taille, luminosité, limite de courant.
|
||||
* 2. Le tableau de couleurs (une case par LED).
|
||||
* 3. La fonction XY() : trouver le numéro d'une LED à partir de sa
|
||||
* position (x, y) sur la matrice.
|
||||
* 4. Les outils de dessin.
|
||||
* 5. Les animations. ← c'est ici que vous créez !
|
||||
* 6. setup() et loop().
|
||||
*/
|
||||
|
||||
// On charge la bibliothèque FastLED.
|
||||
#include <FastLED.h>
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// 1. RÉGLAGES
|
||||
// =============================================================================
|
||||
|
||||
// Broche de l'Arduino reliée au fil VERT (DIN) de la matrice,
|
||||
// à travers une résistance de 330 Ω.
|
||||
#define PIN_DONNEES 6
|
||||
|
||||
// Taille de la matrice : 32 colonnes (largeur) × 8 lignes (hauteur).
|
||||
#define LARGEUR 32
|
||||
#define HAUTEUR 8
|
||||
#define NB_LEDS (LARGEUR * HAUTEUR) // = 256
|
||||
|
||||
// LUMINOSITÉ générale, de 0 (éteint) à 255 (maximum).
|
||||
// Ces LED sont TRÈS lumineuses : 40 suffit largement en intérieur,
|
||||
// et ça ménage les yeux… et l'alimentation.
|
||||
#define LUMINOSITE 40
|
||||
|
||||
// SÉCURITÉ : courant maximum autorisé, en milliampères (1000 mA = 1 A).
|
||||
// Une LED en blanc à fond consomme environ 60 mA.
|
||||
// 256 LED × 60 mA = 15 360 mA = plus de 15 A !
|
||||
// L'alimentation d'établi en fournit beaucoup moins (souvent 3 à 5 A).
|
||||
// FastLED calcule à chaque image ce que les LED vont consommer et baisse
|
||||
// automatiquement la luminosité si on dépasse cette limite.
|
||||
// → Réglez cette valeur UN PEU EN DESSOUS de la limite de courant de
|
||||
// l'alimentation (ex. : alimentation limitée à 3 A → 2500 mA ici).
|
||||
#define COURANT_MAX_MA 2500
|
||||
|
||||
// ORIENTATION de la matrice.
|
||||
// Selon la façon dont vous posez la matrice, la LED n° 0 peut se trouver
|
||||
// dans n'importe quel coin. Lancez l'animation animTestCoins() : le pixel
|
||||
// ROUGE doit être en HAUT À GAUCHE et le VERT en HAUT À DROITE.
|
||||
// - Si rouge et vert sont inversés (gauche/droite) → INVERSER_X à true
|
||||
// - Si rouge et vert sont en bas au lieu d'en haut → INVERSER_Y à true
|
||||
// (true = vrai, false = faux)
|
||||
#define INVERSER_X false
|
||||
#define INVERSER_Y false
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// 2. LE TABLEAU DE COULEURS
|
||||
// =============================================================================
|
||||
//
|
||||
// leds[] est une liste de 256 cases, une par LED, numérotées de 0 à 255
|
||||
// dans l'ORDRE DE LA CHAÎNE (l'ordre dans lequel passe le fil de données).
|
||||
//
|
||||
// Chaque case est de type CRGB : une couleur faite de trois nombres,
|
||||
// rouge, vert, bleu, chacun de 0 à 255.
|
||||
// CRGB(255, 0, 0) = rouge vif
|
||||
// CRGB(255, 128, 0) = orange
|
||||
// CRGB(20, 0, 40) = violet sombre
|
||||
// CRGB::Black = noir (éteint) — FastLED connaît aussi les noms
|
||||
// CRGB::White, CRGB::Red, CRGB::Gold, CRGB::Pink… (noms anglais)
|
||||
//
|
||||
// Mémoire : 256 LED × 3 octets = 768 octets, sur les 2048 du Uno.
|
||||
CRGB leds[NB_LEDS];
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// 3. DE LA POSITION (x, y) AU NUMÉRO DE LED
|
||||
// =============================================================================
|
||||
//
|
||||
// Pour dessiner, on préfère penser en coordonnées, comme sur une feuille
|
||||
// quadrillée :
|
||||
// x = colonne, de 0 (à gauche) à 31 (à droite)
|
||||
// y = ligne, de 0 (en haut) à 7 (en bas)
|
||||
//
|
||||
// Mais les LED, elles, sont numérotées dans l'ordre de la chaîne. Et cette
|
||||
// chaîne fait des ZIGZAGS (on dit « en serpentin ») : elle descend la
|
||||
// 1re colonne, remonte la 2e, redescend la 3e, etc.
|
||||
//
|
||||
// x=0 x=1 x=2 x=3
|
||||
// y=0 0 15 16 31 …
|
||||
// y=1 1 14 17 30
|
||||
// y=2 2 13 18 29
|
||||
// … … … … …
|
||||
// y=7 7 → 8 23 → 24
|
||||
// ↓ ↑ ↓ ↑
|
||||
//
|
||||
// Les colonnes PAIRES (0, 2, 4…) descendent, les colonnes IMPAIRES
|
||||
// (1, 3, 5…) remontent. La fonction XY() fait ce calcul pour nous.
|
||||
// (L'animation animOrdreDesLeds() permet de VOIR ce zigzag.)
|
||||
|
||||
uint16_t XY(int x, int y) {
|
||||
// Si la matrice est posée « à l'envers », on retourne les coordonnées.
|
||||
if (INVERSER_X) x = (LARGEUR - 1) - x;
|
||||
if (INVERSER_Y) y = (HAUTEUR - 1) - y;
|
||||
|
||||
if (x % 2 == 0) {
|
||||
// Colonne paire : la chaîne DESCEND.
|
||||
// On saute les x colonnes précédentes (x × 8 LED), puis on descend de y.
|
||||
return x * HAUTEUR + y;
|
||||
} else {
|
||||
// Colonne impaire : la chaîne REMONTE.
|
||||
// Même chose, mais on compte depuis le bas : (7 - y).
|
||||
return x * HAUTEUR + (HAUTEUR - 1 - y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// 4. LES OUTILS DE DESSIN
|
||||
// =============================================================================
|
||||
//
|
||||
// Ces fonctions modifient le tableau leds[], mais n'allument rien tout de
|
||||
// suite ! Comme un peintre qui prépare sa toile en coulisses : on dessine
|
||||
// toute l'image, puis on la montre d'un coup avec FastLED.show().
|
||||
|
||||
// Colore un pixel. Si (x, y) est en dehors de la matrice, on ne fait rien :
|
||||
// on peut donc dessiner des formes qui « dépassent » sans risque
|
||||
// (pratique pour faire défiler une image qui entre et sort de l'écran).
|
||||
void pixel(int x, int y, CRGB couleur) {
|
||||
if (x >= 0 && x < LARGEUR && y >= 0 && y < HAUTEUR) {
|
||||
leds[XY(x, y)] = couleur;
|
||||
}
|
||||
}
|
||||
|
||||
// Éteint toute la matrice (dans le tableau seulement).
|
||||
void effacer() {
|
||||
fill_solid(leds, NB_LEDS, CRGB::Black); // fill_solid = tout remplir
|
||||
}
|
||||
|
||||
// Affiche réellement l'image : envoie les 256 couleurs dans le fil.
|
||||
// Ça prend environ 8 millisecondes.
|
||||
void montrer() {
|
||||
FastLED.show();
|
||||
}
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// 5. LES ANIMATIONS
|
||||
// =============================================================================
|
||||
//
|
||||
// Comme pour la maquette 3 x 3, une animation est une suite d'images :
|
||||
// effacer / dessiner → montrer() → attendre (delay) → recommencer.
|
||||
//
|
||||
// À VOUS DE JOUER : copiez une animation, renommez-la, modifiez-la,
|
||||
// et ajoutez son nom dans loop() tout en bas.
|
||||
|
||||
|
||||
// --- Animation 1 : test des coins (orientation) ---
|
||||
// Un pixel de couleur dans chaque coin :
|
||||
// ROUGE en haut à gauche VERT en haut à droite
|
||||
// BLEU en bas à gauche BLANC en bas à droite
|
||||
// Si ce n'est pas le cas, changez INVERSER_X / INVERSER_Y (partie 1).
|
||||
void animTestCoins() {
|
||||
effacer();
|
||||
pixel(0, 0, CRGB::Red);
|
||||
pixel(LARGEUR - 1, 0, CRGB::Green);
|
||||
pixel(0, HAUTEUR - 1, CRGB::Blue);
|
||||
pixel(LARGEUR - 1, HAUTEUR - 1, CRGB::White);
|
||||
montrer();
|
||||
delay(3000); // 3 secondes pour regarder
|
||||
}
|
||||
|
||||
|
||||
// --- Animation 2 : l'ordre de la chaîne ---
|
||||
// Allume les LED une par une, dans l'ordre où le signal les traverse
|
||||
// (n° 0, 1, 2… 255), SANS passer par XY(). On voit le serpentin !
|
||||
void animOrdreDesLeds() {
|
||||
effacer();
|
||||
for (int i = 0; i < NB_LEDS; i++) {
|
||||
leds[i] = CRGB::Orange; // la tête du serpent
|
||||
montrer();
|
||||
leds[i] = CRGB(10, 3, 0); // laisse une trace très faible
|
||||
delay(15);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- Animation 3 : arc-en-ciel qui défile ---
|
||||
// Ici on utilise une autre façon de décrire une couleur : CHSV.
|
||||
// H (hue, la TEINTE) : de 0 à 255, fait le tour de l'arc-en-ciel
|
||||
// 0 = rouge, 32 = orange, 64 = jaune, 96 = vert, 128 = cyan,
|
||||
// 160 = bleu, 192 = violet, 224 = rose… puis retour au rouge.
|
||||
// S (saturation) : 0 = gris/blanc, 255 = couleur pure.
|
||||
// V (valeur, la LUMINOSITÉ) : 0 = noir, 255 = plein.
|
||||
// C'est souvent plus intuitif que RGB pour créer des dégradés.
|
||||
void animArcEnCiel() {
|
||||
for (int temps = 0; temps < 256; temps++) {
|
||||
for (int x = 0; x < LARGEUR; x++) {
|
||||
for (int y = 0; y < HAUTEUR; y++) {
|
||||
// La teinte dépend de la colonne (x × 8) et du temps qui passe.
|
||||
// Un byte revient tout seul à 0 après 255 : la teinte boucle.
|
||||
byte teinte = x * 8 + temps * 2;
|
||||
pixel(x, y, CHSV(teinte, 255, 255));
|
||||
}
|
||||
}
|
||||
montrer();
|
||||
delay(20);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- Animation 4 : la pluie ---
|
||||
// Des gouttes tombent au hasard et laissent une traînée qui s'estompe.
|
||||
void animPluie() {
|
||||
for (int image = 0; image < 200; image++) {
|
||||
|
||||
// fadeToBlackBy = « assombrir un peu » toutes les LED (ici de 25 %
|
||||
// environ, 64 sur 256). Les gouttes laissent ainsi une traînée.
|
||||
fadeToBlackBy(leds, NB_LEDS, 64);
|
||||
|
||||
// Faire descendre toute l'image d'une ligne : on recopie chaque ligne
|
||||
// dans celle du dessous, en partant du bas pour ne rien écraser.
|
||||
for (int y = HAUTEUR - 1; y > 0; y--) {
|
||||
for (int x = 0; x < LARGEUR; x++) {
|
||||
leds[XY(x, y)] = leds[XY(x, y - 1)];
|
||||
}
|
||||
}
|
||||
|
||||
// La ligne du haut s'éteint…
|
||||
for (int x = 0; x < LARGEUR; x++) {
|
||||
pixel(x, 0, CRGB::Black);
|
||||
}
|
||||
// … et de nouvelles gouttes apparaissent au hasard.
|
||||
// random(LARGEUR) = une colonne au hasard entre 0 et 31.
|
||||
for (int n = 0; n < 3; n++) {
|
||||
pixel(random(LARGEUR), 0, CRGB(0, 120, 255)); // bleu clair
|
||||
}
|
||||
|
||||
montrer();
|
||||
delay(60);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- Animation 5 : un dessin en pixel art qui défile ---
|
||||
// Le dessin est écrit comme du texte : une ligne de caractères par ligne
|
||||
// de pixels. Chaque lettre est une couleur (voir couleurDeLettre()),
|
||||
// et le point « . » est un pixel éteint.
|
||||
// → Dessinez le vôtre ! Gardez 8 lignes, et la même largeur partout.
|
||||
|
||||
#define DESSIN_LARGEUR 9
|
||||
const char* dessin[HAUTEUR] = {
|
||||
"..RR.RR..",
|
||||
".RBRRRRR.",
|
||||
".RRRRRRR.",
|
||||
".RRRRRRR.",
|
||||
"..RRRRR..",
|
||||
"...RRR...",
|
||||
"....R....",
|
||||
".........",
|
||||
};
|
||||
|
||||
// Traduit une lettre du dessin en couleur.
|
||||
CRGB couleurDeLettre(char lettre) {
|
||||
switch (lettre) {
|
||||
case 'R': return CRGB::Red;
|
||||
case 'O': return CRGB::Orange;
|
||||
case 'J': return CRGB::Yellow;
|
||||
case 'V': return CRGB::Green;
|
||||
case 'C': return CRGB::Cyan;
|
||||
case 'B': return CRGB::White; // B comme blanc
|
||||
case 'L': return CRGB::Blue; // L comme bLeu (B est déjà pris)
|
||||
case 'M': return CRGB::Magenta;
|
||||
case 'P': return CRGB::DeepPink; // P comme rose Pink
|
||||
default: return CRGB::Black; // « . » et tout le reste = éteint
|
||||
}
|
||||
}
|
||||
|
||||
// Dessine le dessin avec son coin haut-gauche en (departX, 0).
|
||||
void dessinerDessin(int departX) {
|
||||
for (int y = 0; y < HAUTEUR; y++) {
|
||||
for (int x = 0; x < DESSIN_LARGEUR; x++) {
|
||||
char lettre = dessin[y][x]; // la lettre en ligne y, colonne x
|
||||
if (lettre != '.') {
|
||||
pixel(departX + x, y, couleurDeLettre(lettre));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void animDessinQuiDefile() {
|
||||
// Le dessin entre par la droite (x = 32) et sort par la gauche
|
||||
// (x = -9, complètement hors de l'écran).
|
||||
for (int x = LARGEUR; x >= -DESSIN_LARGEUR; x--) {
|
||||
effacer();
|
||||
dessinerDessin(x);
|
||||
montrer();
|
||||
delay(70);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- Animation 6 : étincelles ---
|
||||
// Des pixels de couleur au hasard s'allument puis s'éteignent doucement.
|
||||
void animEtincelles() {
|
||||
for (int image = 0; image < 300; image++) {
|
||||
fadeToBlackBy(leds, NB_LEDS, 20); // tout s'estompe doucement
|
||||
// random(256) = une teinte au hasard.
|
||||
pixel(random(LARGEUR), random(HAUTEUR), CHSV(random(256), 200, 255));
|
||||
montrer();
|
||||
delay(15);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// 6. SETUP ET LOOP
|
||||
// =============================================================================
|
||||
|
||||
void setup() {
|
||||
// On présente la matrice à FastLED :
|
||||
// - WS2812B : le modèle de LED
|
||||
// - PIN_DONNEES : la broche du fil de données
|
||||
// - GRB : l'ordre des couleurs attendu par ces LED (Vert, Rouge, Bleu
|
||||
// — eh oui, pas RGB ! Si vos rouges sortent verts, c'est ici.)
|
||||
FastLED.addLeds<WS2812B, PIN_DONNEES, GRB>(leds, NB_LEDS);
|
||||
|
||||
FastLED.setBrightness(LUMINOSITE);
|
||||
FastLED.setMaxPowerInVoltsAndMilliamps(5, COURANT_MAX_MA);
|
||||
|
||||
// Graine du hasard (voir la maquette 3 x 3 : on lit le bruit
|
||||
// électrique d'une broche analogique non branchée).
|
||||
randomSeed(analogRead(A0));
|
||||
|
||||
effacer();
|
||||
montrer();
|
||||
}
|
||||
|
||||
// La « playlist » des animations, jouée en boucle.
|
||||
// Mettez // devant une ligne pour sauter une animation.
|
||||
void loop() {
|
||||
animTestCoins(); // 1. orientation (à retirer une fois réglée)
|
||||
animOrdreDesLeds(); // 2. le serpentin de la chaîne
|
||||
animArcEnCiel(); // 3. arc-en-ciel
|
||||
animPluie(); // 4. pluie
|
||||
animDessinQuiDefile(); // 5. pixel art
|
||||
animEtincelles(); // 6. étincelles
|
||||
}
|
||||
Reference in New Issue
Block a user