commit 06921fde2f59da4a37b6351f2e825f84013fa917 Author: bach Date: Wed Oct 7 11:59:07 2026 +0200 first 3x3 code diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..23ed157 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,101 @@ +# Projet : matrice LED RGB 7 × 39 (Arduino) + +## Objectif + +Construire une matrice LED RGB de **7 lignes × 39 colonnes** (273 pixels), avec un **pas de 10 mm** entre les centres des LED (grille physique déjà définie). + +Le projet avance en deux temps : +1. **Maquette expérimentale 3 × 3** en LED RGB classiques multiplexées (en cours). +2. **Matrice finale 7 × 39**, probablement en LED adressables WS2812B (piste privilégiée, pas encore arrêtée). + +## Langue et conventions + +- Échanges, commentaires de code et noms de variables en **français**. +- Code Arduino (C++), IDE Arduino. Préciser si on passe à arduino-cli ou PlatformIO. +- Garder le code lisible et pédagogique : c'est aussi un projet d'apprentissage du multiplexage. + +--- + +## Étape 1 : maquette 3 × 3 (multiplexage) + +### Matériel +- 1 Arduino (Uno supposé, à confirmer). +- 9 LED RGB **à cathode commune**. +- Transistors **NPN BC337** (ou 2N2222), un par ligne, pour commuter le GND des lignes. + - Kit utilisé : assortiment 10 modèles (A1015, BC327, BC337, C1815, S8050, S8550, 2N2222, 2N2907, 2N3904, 2N3906). + - Éviter C1815 et 2N3904 (courant max trop juste pour une ligne en blanc ≈ 180 mA). + - **Attention au brochage** : BC337 = C-B-E, 2N2222 / S8050 en TO-92 = E-B-C. Vérifier la datasheet. + +### Principe +- **12 pins Arduino** : 9 pour les couleurs (3 colonnes × R, G, B), 3 pour les bases des transistors de lignes. +- Balayage ligne par ligne : on éteint toutes les lignes, on écrit les 9 pins couleur de la ligne suivante, on allume cette ligne, on attend ~1 à 3 ms, on recommence. +- Toujours **éteindre les lignes avant de changer les couleurs** (évite les « fantômes »). + +### Câblage +- Par ligne : émetteur → GND, collecteur → les 3 cathodes de la ligne, base → pin Arduino via **1 kΩ**. +- Par ligne couleur : pin Arduino → résistance → anodes de cette couleur dans la colonne. + - Rouge ≈ **220 Ω**, vert et bleu ≈ **150 Ω** (≈ 15 mA sous 5 V). +- Logique : pin de ligne HIGH = ligne allumée ; pin couleur HIGH = couleur allumée. + +### Affectation des pins (provisoire, à adapter au câblage réel) +| Rôle | Pins | +|---|---| +| Colonne 0 (R, G, B) | 2, 3, 4 | +| Colonne 1 (R, G, B) | 5, 6, 7 | +| Colonne 2 (R, G, B) | 8, 9, 10 | +| Lignes 0, 1, 2 (bases transistors) | 11, 12, 13 | + +### Logiciel +- Pas de bibliothèque de matrice dédiée : balayage écrit à la main. +- Bibliothèque **TimerOne** pour rafraîchir par interruption (≈ 1 ms par ligne), afin de laisser `loop()` libre pour les animations. +- Image stockée dans `volatile byte image[3][3]` (bits : 0 = R, 1 = G, 2 = B → 7 couleurs en tout ou rien). +- Étape suivante prévue : **PWM logiciel** dans l'interruption pour mélanger les couleurs (dégradés). + +--- + +## Étape 2 : matrice finale 7 × 39 + +### Pourquoi pas le multiplexage à cette échelle +- 39 × 3 = 117 lignes couleur → registres à décalage ou drivers (74HC595, TLC5940, STP16CP05). +- Une ligne allumée tire ≈ 2,3 A → MOSFET logic-level nécessaires. +- Luminosité divisée par 7 et PWM lourd pour un Arduino. + +### Piste privilégiée : WS2812B +- LED avec puce intégrée, chaînées (DOUT → DIN), **un seul fil de données**. +- Protocole 800 kHz, 24 bits par LED dans l'ordre **GRB**, reset par niveau bas > 50 µs (≥ 280 µs sur versions récentes). +- Bibliothèque : **FastLED** (ou Adafruit NeoPixel). +- Format envisagé : **panneaux flexibles 8 × 32 + 8 × 8** (pas de 10 mm) → matrice 8 × 40, dont on n'utilise que 7 × 39. + - Ne pas couper la 8e ligne : le serpentin suit les colonnes de 8, couper casserait la chaîne. La 8e ligne reste éteinte (masquée ou repliée doucement à l'arrière). +- Rejeté : LED WS2812B individuelles sur PCB rond de 10 mm (se touchent au pas de 10 mm, pas de place pour le câblage). +- Alternative possible : bande à 100 LED/m (pas de 10 mm), à condition que sa largeur soit ≤ 10 mm. + +### Chiffres clés +- 320 LED adressées (8 × 40) → 960 octets de RAM sur Uno (2 Ko) : serré, envisager Mega ou ESP32. +- Rafraîchissement ≈ 30 µs par LED → ≈ 10 ms pour tout le panneau. +- Consommation max ≈ 60 mA par LED en blanc plein → limiter par logiciel : + `FastLED.setMaxPowerInVoltsAndMilliamps(5, 4000);` +- Alimentation 5 V externe ≈ 10 A, jamais via le 5 V de l'Arduino. + +### Câblage +- Résistance 300 à 500 Ω en série sur la ligne de données. +- Condensateur 1000 µF entre 5 V et GND à l'entrée. +- GND Arduino relié au GND de l'alimentation. +- Réinjecter 5 V / GND à plusieurs endroits de la chaîne. + +### Correspondance (x, y) → index (serpentin par colonnes de 8) +```cpp +#define HAUTEUR_PANNEAU 8 // 8 LED physiques par colonne, même si on n'en utilise que 7 + +int XY(int x, int y) { + if (x % 2 == 0) return x * HAUTEUR_PANNEAU + y; // colonnes paires : vers le bas + else return x * HAUTEUR_PANNEAU + (HAUTEUR_PANNEAU - 1 - y); // colonnes impaires : vers le haut +} +``` +Le sens réel est à vérifier sur les flèches imprimées au dos du panneau (départ en haut ou en bas). + +--- + +## À préciser +- Modèle exact d'Arduino. +- Choix définitif pour la version finale (panneaux WS2812B, bande 100 LED/m, ou multiplexage). +- Usage visé de la matrice (texte défilant, animations, interactivité ?). diff --git a/matrice_3x3/matrice_3x3.ino b/matrice_3x3/matrice_3x3.ino new file mode 100644 index 0000000..9c48a6f --- /dev/null +++ b/matrice_3x3/matrice_3x3.ino @@ -0,0 +1,533 @@ +/* + * ============================================================================= + * MATRICE LED RGB 3 x 3 MULTIPLEXÉE — Arduino Uno + * Workshop « Vitrine pixels » + * ============================================================================= + * + * CE QUE FAIT CE PROGRAMME + * ------------------------ + * Il affiche des animations de couleur sur un petit écran de 9 pixels + * (3 lignes × 3 colonnes). Chaque pixel est une LED RGB : une seule LED + * qui contient en réalité 3 petites LED, une rouge (R), une verte (G pour + * « green ») et une bleue (B). En les allumant ensemble, on mélange la lumière : + * + * rouge + vert = jaune + * rouge + bleu = magenta + * vert + bleu = cyan + * rouge + vert + bleu = blanc + * + * (C'est la synthèse ADDITIVE, celle des écrans — à l'inverse de la peinture, + * où mélanger les couleurs assombrit.) + * + * + * LE PROBLÈME : PAS ASSEZ DE BROCHES (PINS) + * ---------------------------------------- + * 9 LED × 3 couleurs = 27 petites LED à commander. + * L'Arduino Uno n'a que 20 broches utilisables… et on veut, plus tard, + * construire une matrice de 7 × 39 = 273 pixels ! + * Impossible de brancher chaque LED sur sa propre broche. + * + * + * LA SOLUTION : LE MULTIPLEXAGE (ou « balayage ») + * ----------------------------------------------- + * On n'allume JAMAIS toute l'image en même temps. On allume UNE SEULE LIGNE + * à la fois, très vite, l'une après l'autre : + * + * temps → ligne 0 | ligne 1 | ligne 2 | ligne 0 | ligne 1 | ... + * 1 ms 1 ms 1 ms 1 ms 1 ms + * + * Chaque ligne est allumée environ 333 fois par seconde. L'œil est trop + * lent pour voir le clignotement : c'est la PERSISTANCE RÉTINIENNE, le même + * principe que le cinéma (24 images/seconde) ou les vieux écrans cathodiques. + * Le cerveau « recolle » les trois lignes et voit une image fixe. + * + * Grâce à ça, il suffit de : + * - 9 broches pour les couleurs : 3 colonnes × (R, G, B) + * - 3 broches pour choisir quelle ligne est allumée + * = 12 broches au lieu de 27. + * + * + * LE CÂBLAGE EN DEUX MOTS + * ----------------------- + * Nos LED sont à « CATHODE COMMUNE » : les 3 couleurs d'une LED partagent + * la même patte « moins » (la cathode, la patte la plus longue). + * + * - Les 3 cathodes d'une même LIGNE sont reliées ensemble, puis vers le GND + * (le « moins » de l'Arduino) à travers un TRANSISTOR. Le transistor est + * un interrupteur électronique : quand l'Arduino envoie du courant sur sa + * patte « base », il laisse passer le courant de la ligne vers le GND. + * → broche de ligne à HIGH = ligne allumée. + * (On utilise un transistor car une ligne entière en blanc consomme + * ~180 mA, bien trop pour une broche d'Arduino qui supporte ~20-40 mA.) + * + * - Les anodes (« plus ») de même couleur dans une même COLONNE sont reliées + * ensemble, puis vers une broche de l'Arduino à travers une RÉSISTANCE + * (220 Ω pour le rouge, 150 Ω pour le vert et le bleu). La résistance + * limite le courant pour ne pas griller la LED. + * → broche couleur à HIGH = cette couleur est allumée dans la colonne. + * + * Un pixel s'allume donc quand SA ligne est active ET que SA colonne + * envoie de la couleur. C'est le croisement des deux qui choisit le pixel. + * + * + * ORGANISATION DU PROGRAMME + * ------------------------- + * 1. Réglages : quelles broches, combien de lignes/colonnes. + * 2. Les couleurs, codées par des nombres. + * 3. L'IMAGE : un tableau de 3 × 3 cases qui contient la couleur de chaque + * pixel. C'est notre « toile ». + * 4. Le BALAYAGE : une fonction déclenchée automatiquement toutes les + * millisecondes, qui recopie l'image sur les LED, ligne par ligne. + * 5. Des fonctions pour DESSINER dans l'image (effacer, remplir, pixel). + * 6. Les ANIMATIONS : elles ne font que modifier l'image ; le balayage + * s'occupe de l'afficher tout seul, en arrière-plan. + * + * → Pour créer vos propres animations, vous n'avez à toucher qu'aux + * parties 5 et 6. Le reste est le « moteur » de l'écran. + * + * + * BIBLIOTHÈQUE NÉCESSAIRE : TimerOne + * ---------------------------------- + * Dans l'IDE Arduino : menu Outils → Gérer les bibliothèques… + * → chercher « TimerOne » → Installer. + */ + + +// Une « bibliothèque » est un morceau de code écrit par quelqu'un d'autre, +// qu'on réutilise. TimerOne sert à déclencher une fonction à intervalle +// régulier, comme un métronome, sans bloquer le reste du programme. +// (Elle utilise le « Timer1 » du Uno : du coup analogWrite() ne marche plus +// sur les broches 9 et 10. Ici on ne s'en sert pas, donc pas de souci.) +#include + + +// ============================================================================= +// 1. RÉGLAGES DE LA MATRICE +// ============================================================================= + +// #define donne un nom à une valeur. Partout où le programme lit NB_LIGNES, +// c'est comme s'il lisait 3. Avantage : pour changer la taille de la +// matrice, on ne modifie qu'un seul endroit. +#define NB_LIGNES 3 +#define NB_COLONNES 3 + +// Numéros des broches qui commandent les couleurs, rangés dans un tableau +// à deux dimensions : pinsCouleur[numéro de colonne][couleur] +// couleur 0 = rouge, 1 = vert, 2 = bleu +// +// Exemple : pinsCouleur[1][2] = 7 → le bleu de la colonne 1 est sur la broche 7. +// +// « const » veut dire que ces valeurs ne changeront jamais pendant le programme. +// « byte » est un petit nombre entier entre 0 et 255 (1 octet de mémoire). +// +// ⚠ Si votre câblage est différent, c'est ICI qu'il faut corriger. +const byte pinsCouleur[NB_COLONNES][3] = { + // R G B + { 2, 3, 4 }, // colonne 0 (à gauche) + { 5, 6, 7 }, // colonne 1 (au milieu) + { 8, 9, 10 } // colonne 2 (à droite) +}; + +// Broches reliées aux bases des transistors (une par ligne, via une +// résistance de 1 kΩ). pinsLigne[0] = ligne du haut. +// Remarque : la broche 13 est aussi reliée à la petite LED soudée sur +// la carte Arduino. Elle va scintiller doucement : c'est normal. +const byte pinsLigne[NB_LIGNES] = { 11, 12, 13 }; + +// Temps pendant lequel chaque ligne reste allumée, en MICROsecondes +// (1000 µs = 1 ms = un millième de seconde). +// - Plus petit → image plus stable, mais l'Arduino travaille davantage. +// - Plus grand (essayez 10000 !) → on commence à voir le scintillement, +// et à 200000 on voit carrément les lignes s'allumer une par une. +// C'est une bonne expérience pour comprendre le multiplexage. +#define DUREE_LIGNE_US 1000 + + +// ============================================================================= +// 2. LES COULEURS +// ============================================================================= +// +// Chaque couleur est un nombre de 0 à 7. Pourquoi ces nombres-là ? +// Parce qu'on les écrit en BINAIRE (en 0 et 1), sur 3 chiffres (« bits ») : +// chaque bit dit si une des trois LED est allumée (1) ou éteinte (0). +// +// bit 2 bit 1 bit 0 +// BLEU VERT ROUGE valeur +// NOIR 0 0 0 → 0 +// ROUGE 0 0 1 → 1 +// VERT 0 1 0 → 2 +// JAUNE 0 1 1 → 3 (rouge + vert) +// BLEU 1 0 0 → 4 +// MAGENTA 1 0 1 → 5 (rouge + bleu) +// CYAN 1 1 0 → 6 (vert + bleu) +// BLANC 1 1 1 → 7 (tout allumé) +// +// Astuce : une couleur mélangée = la SOMME des couleurs qui la composent. +// JAUNE = ROUGE + VERT = 1 + 2 = 3 +// BLANC = ROUGE + VERT + BLEU = 1 + 2 + 4 = 7 +// +// Pour l'instant chaque LED est soit allumée, soit éteinte (« tout ou rien »), +// donc on n'a que ces 8 couleurs. Pour faire des dégradés (orange, rose +// pâle…), il faudra faire varier l'intensité : ce sera l'étape suivante +// (le « PWM »). + +#define NOIR 0 +#define ROUGE 1 +#define VERT 2 +#define JAUNE 3 +#define BLEU 4 +#define MAGENTA 5 +#define CYAN 6 +#define BLANC 7 + +// Une « palette » : la liste des 7 couleurs (sans le noir), dans l'ordre +// de l'arc-en-ciel. Pratique pour les parcourir avec une boucle : +// couleurs[0] = ROUGE, couleurs[1] = JAUNE, … couleurs[6] = BLANC. +const byte couleurs[] = { ROUGE, JAUNE, VERT, CYAN, BLEU, MAGENTA, BLANC }; +#define NB_COULEURS 7 + + +// ============================================================================= +// 3. L'IMAGE (la « toile ») +// ============================================================================= +// +// Un tableau de 3 × 3 cases. Chaque case contient la couleur d'un pixel. +// On y accède par image[ligne][colonne] : +// +// colonne 0 colonne 1 colonne 2 +// ligne 0 image[0][0] image[0][1] image[0][2] +// ligne 1 image[1][0] image[1][1] image[1][2] +// ligne 2 image[2][0] image[2][1] image[2][2] +// +// Attention : en informatique on compte à partir de 0, pas de 1 ! +// +// « volatile » prévient l'Arduino que cette variable peut changer +// « dans son dos » : elle est modifiée par les animations et lue en même +// temps par le balayage. Sans ce mot, l'Arduino pourrait garder une vieille +// copie de l'image et ne pas voir les changements. +volatile byte image[NB_LIGNES][NB_COLONNES]; + +// Numéro de la ligne actuellement allumée (0, 1 ou 2). +volatile byte ligneCourante = 0; + + +// ============================================================================= +// 4. LE BALAYAGE (le « moteur » de l'écran) +// ============================================================================= +// +// Cette fonction n'est jamais appelée directement par nous : c'est TimerOne +// qui la déclenche automatiquement toutes les DUREE_LIGNE_US microsecondes. +// On appelle ça une INTERRUPTION : l'Arduino met en pause ce qu'il est en +// train de faire (même au milieu d'un delay !), exécute cette fonction, +// puis reprend là où il en était. +// +// À chaque appel, elle passe à la ligne suivante. Il faut 3 appels pour +// afficher l'image complète une fois. +// +// Règle d'or d'une interruption : être COURTE et RAPIDE. Pas de delay(), +// pas de Serial.print() ici. + +void rafraichirLigne() { + + // --- Étape 1 : éteindre la ligne actuellement allumée --- + // Il faut le faire AVANT de changer les couleurs. Sinon, pendant un très + // court instant, la ligne actuelle s'afficherait avec les couleurs de la + // ligne suivante : on verrait des « fantômes », de légers reflets de + // couleur aux mauvais endroits. + digitalWrite(pinsLigne[ligneCourante], LOW); + + // --- Étape 2 : passer à la ligne suivante --- + // ligneCourante++ ajoute 1 : 0 → 1 → 2 → 3… + // Arrivé à 3 (qui n'existe pas), on revient à 0 : on boucle. + ligneCourante++; + if (ligneCourante >= NB_LIGNES) { + ligneCourante = 0; + } + + // --- Étape 3 : préparer les couleurs de cette ligne --- + // On parcourt les 3 colonnes. Pour chacune, on lit la couleur dans + // l'image et on allume ou éteint les broches R, G et B correspondantes. + for (byte col = 0; col < NB_COLONNES; col++) { + + // Couleur du pixel (ligne courante, colonne col), entre 0 et 7. + byte c = image[ligneCourante][col]; + + // Le symbole & (« ET bit à bit ») permet de tester UN bit de la couleur. + // Exemple avec c = MAGENTA = 5 = 101 en binaire : + // 5 & ROUGE (001) = 001 → non nul → le rouge est allumé + // 5 & VERT (010) = 000 → nul → le vert est éteint + // 5 & BLEU (100) = 100 → non nul → le bleu est allumé + // + // L'écriture (condition) ? HIGH : LOW veut dire : + // « si la condition est vraie, HIGH, sinon LOW ». + digitalWrite(pinsCouleur[col][0], (c & ROUGE) ? HIGH : LOW); + digitalWrite(pinsCouleur[col][1], (c & VERT) ? HIGH : LOW); + digitalWrite(pinsCouleur[col][2], (c & BLEU) ? HIGH : LOW); + } + + // --- Étape 4 : allumer la nouvelle ligne --- + // Les couleurs sont prêtes, on ouvre le transistor de la ligne : + // le courant circule, les LED de cette ligne s'allument. + // Elles resteront allumées jusqu'au prochain appel (dans 1 ms). + digitalWrite(pinsLigne[ligneCourante], HIGH); +} + + +// ============================================================================= +// 5. LES OUTILS DE DESSIN +// ============================================================================= +// +// Ces petites fonctions modifient l'image. Elles n'allument rien +// directement : c'est le balayage qui affichera le résultat à son prochain +// passage (moins de 3 ms plus tard, donc instantané pour l'œil). + +// Remplit toute l'image avec une seule couleur. +// Deux boucles imbriquées : pour chaque ligne l, pour chaque colonne c… +void remplir(byte couleur) { + for (byte l = 0; l < NB_LIGNES; l++) { + for (byte c = 0; c < NB_COLONNES; c++) { + image[l][c] = couleur; + } + } +} + +// Éteint tout (= remplir en noir). +void effacer() { + remplir(NOIR); +} + +// Colore un seul pixel. +// x = colonne (horizontal, de gauche à droite : 0, 1, 2) +// y = ligne (vertical, de haut en bas : 0, 1, 2) +// Comme sur un écran d'ordinateur, le point (0, 0) est en HAUT à gauche. +// +// x=0 x=1 x=2 +// y=0 (0,0) (1,0) (2,0) +// y=1 (0,1) (1,1) (2,1) +// y=2 (0,2) (1,2) (2,2) +// +// Le « if » vérifie qu'on ne dessine pas en dehors de la matrice : +// écrire image[5][5] irait abîmer d'autres données en mémoire. +// Attention à l'ordre : on écrit image[y][x] (ligne d'abord) ! +void pixel(byte x, byte y, byte couleur) { + if (x < NB_COLONNES && y < NB_LIGNES) { + image[y][x] = couleur; + } +} + + +// ============================================================================= +// 6. LES ANIMATIONS +// ============================================================================= +// +// Une animation, c'est une suite d'images, comme un flip-book : +// on dessine une image → on attend un peu (delay) → on dessine la suivante… +// +// delay(150) met le programme en pause 150 millisecondes. Pendant ce temps, +// le balayage continue de tourner grâce à l'interruption : l'image reste +// affichée. (Sans interruption, l'écran s'éteindrait pendant le delay !) +// +// Chaque animation dure quelques secondes puis se termine ; loop() lance +// alors la suivante. +// +// À VOUS DE JOUER : copiez une de ces fonctions, renommez-la, modifiez-la, +// puis ajoutez son nom dans loop() tout en bas. + + +// --- Animation 1 : test du câblage --- +// Allume chaque pixel, un par un, en rouge, puis en vert, puis en bleu. +// À lancer en premier sur une nouvelle maquette : si un pixel ne s'allume +// pas, ou s'allume au mauvais endroit / dans la mauvaise couleur, vous savez +// exactement quel fil vérifier. +void animTestPixels() { + const byte primaires[] = { ROUGE, VERT, BLEU }; // les 3 couleurs de base + + for (byte p = 0; p < 3; p++) { // pour chaque couleur de base + for (byte y = 0; y < NB_LIGNES; y++) { // pour chaque ligne + for (byte x = 0; x < NB_COLONNES; x++) { // pour chaque colonne + effacer(); // on éteint tout + pixel(x, y, primaires[p]); // on allume un seul pixel + delay(150); // on laisse le temps de voir + } + } + } +} + + +// --- Animation 2 : aplats de couleur --- +// Toute la matrice prend successivement les 7 couleurs de la palette. +void animCouleursPleines() { + for (byte i = 0; i < NB_COULEURS; i++) { // i va de 0 à 6 + remplir(couleurs[i]); // la i-ème couleur de la palette + delay(400); // 0,4 seconde par couleur + } +} + + +// --- Animation 3 : la chenille --- +// Un petit serpent de 2 pixels fait le tour du bord de la matrice, pendant +// que le pixel central reste blanc. Il change de couleur à chaque tour. +void animChenille() { + + // Les 8 cases du bord, dans l'ordre des aiguilles d'une montre. + // Chaque case est donnée par ses coordonnées {x, y}. + // + // 0 → 1 → 2 + // ↑ ↓ + // 7 · 3 + // ↑ ↓ + // 6 ← 5 ← 4 + const byte tour[8][2] = { + {0, 0}, {1, 0}, {2, 0}, // le haut, de gauche à droite + {2, 1}, // le côté droit + {2, 2}, {1, 2}, {0, 2}, // le bas, de droite à gauche + {0, 1} // le côté gauche + }; + + for (byte t = 0; t < 4; t++) { // 4 tours complets + byte couleur = couleurs[t % NB_COULEURS]; // une couleur différente par tour + // (% = reste de la division : garde + // le numéro entre 0 et 6) + + for (byte i = 0; i < 8; i++) { // 8 étapes par tour + effacer(); + pixel(1, 1, BLANC); // le centre, fixe + + // La tête du serpent, sur la case i du tour. + pixel(tour[i][0], tour[i][1], couleur); + + // La queue, sur la case juste avant. + // (i + 7) % 8 donne « i - 1 », mais en revenant à 7 quand i vaut 0 : + // la queue de la case 0 est la case 7, on boucle autour du carré. + byte prec = (i + 7) % 8; + pixel(tour[prec][0], tour[prec][1], couleur); + + delay(100); // vitesse du serpent + } + } +} + + +// --- Animation 4 : le damier --- +// Un damier cyan / magenta qui s'inverse régulièrement. +void animDamier() { + for (byte n = 0; n < 8; n++) { // 8 images + for (byte y = 0; y < NB_LIGNES; y++) { + for (byte x = 0; x < NB_COLONNES; x++) { + + // L'astuce du damier : on additionne x et y. + // Si le résultat est pair, une couleur ; s'il est impair, l'autre. + // (0,0) → 0 pair (1,0) → 1 impair (2,0) → 2 pair … + // En ajoutant n (qui augmente à chaque image), pair et impair + // s'échangent à chaque fois : le damier s'inverse. + if ((x + y + n) % 2 == 1) { + pixel(x, y, MAGENTA); + } else { + pixel(x, y, CYAN); + } + } + } + delay(300); + } +} + + +// --- Animation 5 : balayages --- +// Une barre verticale traverse la matrice de gauche à droite, puis une barre +// horizontale de haut en bas. On recommence avec chaque couleur de la palette. +void animBalayages() { + for (byte i = 0; i < NB_COULEURS; i++) { + byte couleur = couleurs[i]; + + // Barre verticale : on allume toute la colonne x, puis on avance. + for (byte x = 0; x < NB_COLONNES; x++) { + effacer(); + for (byte y = 0; y < NB_LIGNES; y++) { + pixel(x, y, couleur); + } + delay(120); + } + + // Barre horizontale : on allume toute la ligne y, puis on descend. + for (byte y = 0; y < NB_LIGNES; y++) { + effacer(); + for (byte x = 0; x < NB_COLONNES; x++) { + pixel(x, y, couleur); + } + delay(120); + } + } +} + + +// --- Animation 6 : scintillement aléatoire --- +// À chaque étape, un pixel pris au hasard prend une couleur au hasard +// (le noir compris, pour que des pixels s'éteignent aussi). +// random(3) donne un nombre au hasard parmi 0, 1, 2. +// random(8) donne un nombre au hasard entre 0 et 7 = une de nos 8 couleurs. +void animAleatoire() { + for (int n = 0; n < 40; n++) { // 40 changements + pixel(random(NB_COLONNES), random(NB_LIGNES), random(8)); + delay(80); + } +} + + +// ============================================================================= +// SETUP : exécuté UNE SEULE FOIS, à l'allumage de l'Arduino +// ============================================================================= +void setup() { + + // Toutes nos broches servent à ENVOYER du courant (sortie = OUTPUT), + // pas à en lire (ce serait INPUT, pour un bouton par exemple). + // On les met toutes à LOW au départ pour que tout soit éteint. + + // Les 3 broches de lignes + for (byte l = 0; l < NB_LIGNES; l++) { + pinMode(pinsLigne[l], OUTPUT); + digitalWrite(pinsLigne[l], LOW); + } + + // Les 9 broches de couleurs (3 colonnes × 3 couleurs) + for (byte c = 0; c < NB_COLONNES; c++) { + for (byte k = 0; k < 3; k++) { + pinMode(pinsCouleur[c][k], OUTPUT); + digitalWrite(pinsCouleur[c][k], LOW); + } + } + + // On part d'une image toute noire. + effacer(); + + // Le hasard d'un ordinateur n'est pas vraiment du hasard : c'est une + // longue suite de nombres calculée à partir d'un point de départ + // (la « graine »). Si la graine est toujours la même, la suite aussi. + // On lit donc la broche A0, qui n'est branchée à rien : elle capte du + // bruit électrique, différent à chaque démarrage → vrai point de départ + // imprévisible. + randomSeed(analogRead(A0)); + + // On démarre le métronome : toutes les DUREE_LIGNE_US microsecondes, + // TimerOne appellera rafraichirLigne(). À partir de maintenant, l'écran + // s'affiche tout seul, en arrière-plan. + Timer1.initialize(DUREE_LIGNE_US); + Timer1.attachInterrupt(rafraichirLigne); +} + + +// ============================================================================= +// LOOP : exécutée EN BOUCLE, à l'infini, après setup() +// ============================================================================= +// +// C'est la « playlist » : les animations s'enchaînent dans cet ordre, puis +// on recommence au début. +// Pour ne garder qu'une animation, mettez les autres en commentaire en +// ajoutant // devant la ligne. Pour ajouter la vôtre, écrivez son nom ici. +void loop() { + animTestPixels(); // 1. test du câblage (à retirer une fois validé) + animCouleursPleines(); // 2. aplats de couleur + animChenille(); // 3. serpent autour du bord + animDamier(); // 4. damier qui s'inverse + animBalayages(); // 5. barres qui traversent + animAleatoire(); // 6. scintillement aléatoire +}