first 3x3 code
This commit is contained in:
@@ -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é ?).
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user