first 3x3 code

This commit is contained in:
bach
2026-10-07 11:59:07 +02:00
commit 06921fde2f
2 changed files with 634 additions and 0 deletions
+101
View File
@@ -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é ?).
+533
View File
@@ -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 <TimerOne.h>
// =============================================================================
// 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
}