Matrice LED MAX7219 avec Arduino : texte défilant et horloge
Matrice LED MAX7219 et Arduino : câblage 8x8 et 4 en 1 8x32, texte défilant avec MD_Parola, texte en miroir corrigé par FC16_HW, horloge et code ESP32.
Le MAX7219 est un circuit pilote bon marché qui commande à lui seul 64 LED, et c'est la façon la plus simple d'utiliser une matrice LED avec Arduino. Tu le trouveras surtout sous deux formes : un module avec une seule matrice de points 8x8 et un module 4 en 1 de 8x32 points où quatre matrices sont alignées côte à côte. Le MAX7219 n'a besoin que de 3 fils de signal venant de l'Arduino (DIN, CS, CLK) ; il balaie lui-même les lignes des centaines de fois par seconde, règle la luminosité et mémorise l'état de chaque LED. L'Arduino reste ainsi libre pour un texte défilant, une horloge, un tableau de score ou des animations, et tu peux allonger l'afficheur autant que tu veux en chaînant les modules.
Dans cet article, tu vas apprendre comment fonctionne le MAX7219, comment brancher le module en SPI sur un Arduino Uno, un ESP32 et un Raspberry Pi Pico, comment chaîner les modules et comment afficher ton premier texte défilant avec la bibliothèque MD_Parola. Ensuite, tu régleras le problème du texte en miroir ou à l'envers, celui qui bloque le plus les débutants, en choisissant le bon type de matériel (FC16_HW), tu calculeras la luminosité et la consommation, tu afficheras les accents et tes propres caractères, puis tu construiras une horloge avec un module RTC et une animation pixel par pixel. Les dernières parties montrent comment envoyer des messages depuis ton téléphone avec un ESP32, le code MicroPython pour le Pico et les solutions aux erreurs les plus fréquentes.

Qu'est-ce que le MAX7219 et comment fonctionne-t-il ?
Impossible de relier 64 LED une par une aux broches de l'Arduino : les matrices LED utilisent donc le multiplexage. Dans une matrice 8x8, les LED sont câblées sur une grille de 8 lignes et 8 colonnes. À chaque instant, le MAX7219 n'active qu'un seul groupe de LED (un « digit » dans la fiche technique, soit une ligne ou une colonne sur la matrice), indique par les autres fils lesquelles des huit LED de ce groupe s'allument, puis passe au groupe suivant. Les huit groupes sont balayés environ 800 fois par seconde ; l'œil ne peut pas suivre cette vitesse, si bien que l'image paraît fixe. Pendant ce temps, la puce garde le motif de chaque groupe dans sa propre RAM de 8x8 bits, limite le courant des LED avec une seule résistance et règle la luminosité sur 16 niveaux.
L'Arduino communique avec le MAX7219 par une liaison série à 3 fils qui fonctionne un peu comme le SPI. Chaque commande est un paquet de 16 bits : l'octet de poids fort indique le registre à écrire et l'octet de poids faible contient la valeur. Tant que CS (LOAD dans la fiche technique) est à LOW, les bits entrent par DIN à chaque front montant de CLK ; quand CS repasse à HIGH, le paquet est enregistré dans le registre. C'est le même principe que le registre à décalage 74HC595, mais comme le MAX7219 se charge aussi du balayage et de la limitation du courant, il demande bien moins de travail. Tu trouveras le fonctionnement général du SPI dans l'article Qu'est-ce que le SPI ?.
| Caractéristique | Valeur |
|---|---|
| Tension d'alimentation | 4,0–5,5 V (5 V en pratique) |
| Interface | Série 3 fils (DIN, CLK, CS), jusqu'à 10 MHz |
| LED pilotées | 64 (une matrice 8x8 ou 8 chiffres 7 segments) |
| Fréquence de balayage | 800 Hz typique (8 chiffres) |
| Courant par segment | Fixé par la résistance RSET, 40 mA maximum (souvent 10 kΩ sur les modules) |
| Luminosité | 16 niveaux, rapport cyclique de 1/32 à 31/32 |
| Courant en veille (shutdown) | Environ 150 µA |
| Seuil HIGH en entrée | Au moins 3,5 V (avec une alimentation de 5 V) |
| Chaînage | Sortie DOUT vers l'entrée DIN de la puce suivante |
Le MAX7219 possède 14 registres adressables, mais ceux qui servent pour une matrice LED sont dans le tableau ci-dessous. Les bibliothèques les règlent pour toi ; savoir à quoi ils servent aide pourtant beaucoup quand tu cherches une panne. Par exemple, à la première mise sous tension, la puce démarre en mode shutdown (veille) avec l'afficheur éteint : si le code d'initialisation ne s'exécute pas, le module semble totalement mort. Sa sœur, la MAX7221, possède les mêmes registres, mais ajoute une vraie broche CS compatible SPI et des sorties de segments à pente limitée qui réduisent les perturbations électromagnétiques.
| Adresse | Registre | Rôle |
|---|---|---|
| 0x00 | No-Op | Laisse cette puce inchangée pendant qu'un paquet va vers une autre puce de la chaîne |
| 0x01–0x08 | Digit 0–7 | Le motif de 8 bits de chacune des huit lignes (ou colonnes) |
| 0x09 | Decode Mode | Décodage BCD pour les 7 segments ; désactivé (0x00) pour une matrice |
| 0x0A | Intensity | Luminosité, de 0x0 à 0xF |
| 0x0B | Scan Limit | Nombre de chiffres balayés ; 7 (les huit) pour une matrice |
| 0x0C | Shutdown | 0 : mode veille, 1 : fonctionnement normal |
| 0x0F | Display Test | 1 : toutes les LED s'allument à pleine luminosité |
Module 8x8 seul ou module 4 en 1 de 8x32 ?
Les deux modules que tu croiseras le plus souvent utilisent le même circuit ; la différence tient à la façon dont la matrice LED est câblée au MAX7219 et à la forme de la carte. Le module seul sur carte verte porte un MAX7219 en boîtier DIP (24 broches) et une matrice 8x8 comme la 1088AS, avec les broches d'entrée (VCC, GND, DIN, CS, CLK) à une extrémité et celles de sortie (VCC, GND, DOUT, CS, CLK) à l'autre. Sur le module 4 en 1 à carte bleue, quatre MAX7219 CMS sont placés sous les matrices et les quatre blocs sont déjà chaînés en usine ; la carte porte généralement l'inscription FC-16. Pour un long texte défilant, le module 4 en 1 est à la fois moins cher et plus propre.

| Caractéristique | Module 8x8 seul | Module 4 en 1 8x32 (FC-16) |
|---|---|---|
| Résolution | 8x8 = 64 LED | 32x8 = 256 LED |
| Nombre de MAX7219 | 1 (boîtier DIP) | 4 (boîtier CMS) |
| Type de matériel dans le code | Généralement GENERIC_HW | Généralement FC16_HW |
| Caractères visibles en même temps | 1 | 4–6 (selon la largeur des lettres) |
| Courant maximal à pleine luminosité | Environ 330 mA | Environ 1,3 A |
| Usage idéal | Icônes, dé, smiley, petits jeux | Texte défilant, horloge, tableau de score |
Câblage du MAX7219 : Arduino Uno, ESP32 et Pico
Le module a cinq broches : VCC et GND pour l'alimentation, DIN pour les données, CLK pour l'horloge et CS pour la sélection (chargement). Par défaut, MD_Parola et MD_MAX72XX utilisent le SPI matériel : DIN doit alors aller sur la broche MOSI de ta carte et CLK sur la broche SCK, tandis que CS peut être n'importe quelle broche numérique. Tu peux vérifier l'emplacement des broches SPI matérielles de ta carte avec l'outil Pinout. Branche toujours les fils du côté entrée (IN) du module, l'extrémité marquée DIN ; l'extrémité marquée DOUT est destinée au module suivant.
| Broche du module | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| VCC | 5V | 5V (VIN) | VBUS (5 V) |
| GND | GND | GND | GND |
| DIN | D11 (MOSI) | GPIO 23 (MOSI) | GP19 (SPI0 TX) |
| CS | D10 | GPIO 5 | GP17 |
| CLK | D13 (SCK) | GPIO 18 (SCK) | GP18 (SPI0 SCK) |
Les broches de l'ESP32 et du Pico fournissent 3,3 V, alors que la fiche technique du MAX7219 exige au moins 3,5 V pour un niveau HIGH avec une alimentation de 5 V. Les signaux en 3,3 V sont donc techniquement un peu sous la limite. La plupart des modules fonctionnent quand même, mais avec des fils longs ou certains lots de puces, des points peuvent s'allumer au hasard et l'image se brouiller. La solution fiable est un tampon comme le 74HCT125, qui accepte 3,3 V comme niveau HIGH et sort du 5 V, ou un convertisseur de niveau logique rapide sur les lignes DIN, CLK et CS. Garder les fils de signal sous 20 cm règle aussi souvent le problème.
Chaîner les modules (daisy chain)
La broche DOUT du MAX7219 ressort les données entrées sur DIN 16,5 cycles d'horloge plus tard. Quand tu relies le côté OUT d'un module au côté IN du suivant, DOUT va vers le DIN de la puce suivante, tandis que CLK et CS sont communs à toutes les puces. Ainsi, seuls 3 fils de signal sortent toujours de l'Arduino, mais l'afficheur peut compter 8, 16 ou 32 blocs. À chaque mise à jour, la bibliothèque envoie des paquets dans toute la chaîne et, quand CS remonte, toutes les puces se mettent à jour en même temps. Sur les modules 4 en 1, ce câblage est déjà fait sur la carte ; pour obtenir un afficheur de 8 blocs (64x8) avec deux modules 4 en 1, il suffit de relier les broches OUT du premier aux broches IN du second et de mettre MAX_DEVICES à 8 dans le code.
Dans la bibliothèque, la numérotation des blocs commence au module le plus proche de l'entrée DIN et augmente vers la gauche ; pour MD_MAX72XX, l'origine des coordonnées est le coin supérieur droit de l'afficheur. C'est pourquoi l'entrée DIN doit rester à droite pour que le texte se lise correctement. Plus la chaîne est longue, plus l'alimentation devient la vraie limite : tous les 4 à 8 blocs, réinjecte le 5 V et le GND dans la chaîne avec des fils épais, et ajoute sur l'entrée d'alimentation de chaque module un condensateur électrolytique de 10 µF et un condensateur céramique de 100 nF. La fiche technique recommande aussi ce duo pour lisser l'ondulation due aux pointes de courant des LED.
Installer les bibliothèques MD_MAX72XX et MD_Parola
Les deux bibliothèques les plus utilisées pour le MAX7219 ont le même auteur (majicDesigns) et fonctionnent ensemble. MD_MAX72XX s'occupe du bas niveau : elle initialise les modules, écrit les pixels et les colonnes et gère la police. MD_Parola s'appuie dessus et ajoute le texte défilant, les effets, l'alignement et les zones. La bibliothèque LedControl que tu verras dans d'anciens exemples fonctionne aussi, mais tu dois alors programmer toi-même le défilement. Si tu n'as jamais installé de bibliothèque, lis d'abord Ajouter une bibliothèque Arduino.
- Dans l'Arduino IDE, ouvre le gestionnaire de bibliothèques (Outils > Gérer les bibliothèques) et cherche MD_Parola.
- Installe la bibliothèque MD_Parola de majicDesigns. Quand l'IDE te demande pour les dépendances, choisis Install all afin d'installer aussi MD_MAX72XX.
- Câble le module selon le tableau ci-dessus et, pour un module 4 en 1, mets HARDWARE_TYPE sur FC16_HW et MAX_DEVICES sur 4 dans le code.
- Téléverse le programme. Si le texte apparaît à l'envers, en miroir ou tourné, pas d'inquiétude : tu le corrigeras avec une seule ligne dans la partie sur le type de matériel.
Premier programme : texte défilant avec MD_Parola
1// MAX7219 4'lü modülde kayan yazı (MD_Parola) / Scrolling text on a 4-in-1 MAX7219 module (MD_Parola)
2#include <MD_Parola.h>
3#include <MD_MAX72xx.h>
4#include <SPI.h>
5
6#define HARDWARE_TYPE MD_MAX72XX::FC16_HW // mavi PCB'li 4'lü modül / blue-PCB 4-in-1 module
7#define MAX_DEVICES 4 // zincirdeki 8x8 blok sayısı / number of 8x8 blocks in the chain
8#define CS_PIN 10 // DIN = D11 (MOSI), CLK = D13 (SCK)
9
10MD_Parola display = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
11
12void setup() {
13 display.begin();
14 display.setIntensity(4); // parlaklık 0–15 / brightness 0–15
15 display.displayClear();
16 // metin, hizalama, hız (ms/kare), bekleme (ms), giriş efekti, çıkış efekti
17 // text, alignment, speed (ms/frame), pause (ms), entry effect, exit effect
18 display.displayText("Merhaba BlueGrays!", PA_CENTER, 50, 1000, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
19}
20
21void loop() {
22 if (display.displayAnimate()) { // efekt bittiğinde true döner / returns true when the effect ends
23 display.displayReset(); // aynı yazıyı baştan başlat / restart the same text
24 }
25}La ligne la plus importante est displayText() : elle reçoit, dans l'ordre, le texte, l'alignement (PA_LEFT, PA_CENTER, PA_RIGHT), le temps entre deux images en millisecondes, la pause une fois le texte en place, puis les effets d'entrée et de sortie. Plus la valeur de vitesse est petite, plus le texte défile vite ; entre 25 et 60 ms, le défilement reste bien lisible. displayAnimate() avance d'au plus une image à chaque appel et rend la main tout de suite. Il faut donc l'appeler sans arrêt dans loop() et ne pas utiliser delay() dans le reste du code, sinon le texte avance par saccades. Tu trouveras comment attendre sans bloquer le programme dans l'article millis() ou delay().
| Fonction | Ce qu'elle fait |
|---|---|
| begin() | Initialise les modules, les sort de veille et efface l'afficheur |
| displayText(texte, alignement, vitesse, pause, entrée, sortie) | Définit le texte et les effets à afficher et lance l'animation |
| displayAnimate() | Dessine l'image suivante ; renvoie true quand l'effet est terminé |
| displayReset() | Rejoue le même texte et le même effet depuis le début |
| print("...") | Affiche un texte fixe, sans effet |
| setIntensity(0–15) | Règle la luminosité de tous les modules |
| setInvert(true) | Inverse les LED allumées et éteintes (image en négatif) |
| displayShutdown(true) | Met l'afficheur en veille ; false le rallume |
| begin(2) et setZone(0, 0, 1) | Divise l'afficheur en zones indépendantes, chacune avec son texte et son effet |
En plus de PA_SCROLL_LEFT, il existe de nombreux effets d'entrée et de sortie : PA_PRINT (le texte apparaît d'un coup), PA_SCROLL_UP et PA_SCROLL_DOWN (défilement vertical), PA_WIPE (balayage), PA_OPENING et PA_CLOSING (ouverture et fermeture depuis le centre), PA_FADE (fondu par la luminosité), PA_DISSOLVE, PA_BLINDS, PA_RANDOM et PA_GROW_UP. Pour tous les voir, téléverse l'exemple Parola_Animation_Catalog depuis Fichier > Exemples > MD_Parola ; n'oublie pas d'adapter les lignes HARDWARE_TYPE et MAX_DEVICES à ton module.
Choisir le type de matériel (FC16_HW) et corriger le texte en miroir
Les fabricants câblent la matrice 8x8 au MAX7219 de différentes façons : sur certaines cartes, les lignes « digit » de la puce vont aux lignes de la matrice, sur d'autres aux colonnes, et l'ordre des lignes ou des colonnes peut être inversé. La bibliothèque compense cette différence avec le réglage HARDWARE_TYPE. Si tu choisis le mauvais type, le module n'est pas en panne, mais les lettres apparaissent en miroir, à l'envers ou tournées de 90 degrés dans chaque bloc 8x8. Comme beaucoup d'anciens codes trouvés en ligne utilisent PAROLA_HW ou GENERIC_HW, c'est le problème le plus fréquent avec les modules 4 en 1 bleus vendus aujourd'hui. Le tableau indique quoi changer selon le symptôme ; il est établi pour le module 4 en 1 FC-16.
| Ce que tu vois | Cause probable | Solution |
|---|---|---|
| Les lettres sont en miroir gauche-droite dans chaque bloc | PAROLA_HW choisi, ordre des colonnes inversé | Utilise FC16_HW |
| Les lettres sont tournées de 90 degrés dans chaque bloc | GENERIC_HW choisi, lignes et colonnes permutées | Utilise FC16_HW |
| Les lettres sont à l'envers dans chaque bloc | ICSTATION_HW choisi, ordre des lignes et des colonnes inversé | Utilise FC16_HW |
| Tout le texte est à l'envers et défile de gauche à droite | Le module est retourné, entrée DIN à gauche | Tourne le module de 180 degrés pour que l'entrée DIN soit à droite |
| Seuls certains blocs sont corrects, les autres sont vides ou brouillés | MAX_DEVICES ne correspond pas au nombre réel de blocs | Mets dans MAX_DEVICES le nombre réel de blocs |
Réglage de la luminosité et consommation
La luminosité dépend de deux choses. La première est la résistance RSET du module : la puce envoie aux LED environ 100 fois le courant qui sort de la broche ISET. Les modules utilisent généralement 10 kΩ, ce qui donne un courant crête un peu supérieur à 40 mA avec des LED rouges et d'environ 40 mA avec des LED bleues ou blanches. La seconde est le registre Intensity réglé par logiciel : une valeur n de 0 à 15 garde les LED allumées pendant (2n+1)/32 de chaque intervalle de balayage, 0 étant la luminosité minimale (1/32) et 15 la maximale (31/32). Et comme chaque ligne n'est allumée qu'un huitième du temps, même à pleine luminosité une LED consomme en moyenne environ 5 mA. Tu trouveras les tensions directes selon la couleur de la LED dans l'outil Tensions des LED.
Tu peux estimer grossièrement le courant moyen d'un module ainsi : I ≈ 8 mA + 5 mA × (2n+1)/32 × L. Ici, 8 mA est la consommation propre de la puce, n la valeur de luminosité et L le nombre de LED allumées sur ce module (0–64) ; 5 mA correspond au huitième du courant crête de 40 mA. Par exemple, à la luminosité 15 avec les 64 LED allumées, on obtient 8 + 5 × 0,97 × 64 ≈ 318 mA, ce qui concorde avec les 330 mA de la fiche technique. Un texte défilant n'allume en général que 25 à 35 pour cent des LED, la consommation réelle est donc bien plus faible. Le tableau donne des valeurs typiques pour un module 4 en 1.
| Situation | Par module | Module 4 en 1 (32x8) |
|---|---|---|
| Toutes les LED allumées, luminosité 15 | ≈ 320 mA | ≈ 1,3 A |
| Toutes les LED allumées, luminosité 7 | ≈ 160 mA | ≈ 630 mA |
| Texte défilant (~30 % des LED), luminosité 7 | ≈ 55 mA | ≈ 210 mA |
| Texte défilant (~30 % des LED), luminosité 2 | ≈ 25 mA | ≈ 90 mA |
| Mode veille (displayShutdown) | ≈ 0,15 mA | ≈ 0,6 mA |
Pour baisser l'afficheur la nuit, tu peux régler la luminosité automatiquement avec un capteur de lumière LDR et mettre l'afficheur en veille avec displayShutdown(true) quand personne n'est là. Si tu conçois un panneau sur batterie, saisis les valeurs ci-dessus dans l'outil Autonomie de batterie pour calculer combien d'heures il tiendra. En intérieur, une luminosité de 2 à 4 au lieu de 15 suffit le plus souvent : c'est moins fatigant pour les yeux et le courant des LED tombe à environ un tiers, voire un sixième.
Accents et caractères spéciaux (é, è, à, ç)
L'Arduino IDE enregistre ton code en UTF-8 : une lettre comme « é » ou « ç » n'occupe donc pas un octet dans le texte, mais deux. MD_Parola cherche chaque octet comme un numéro de caractère dans la police, c'est pourquoi les lettres accentuées se transforment en symboles incompréhensibles. La police par défaut de la bibliothèque contient tout le jeu Latin-1 (é, è, ê, à, ç, ù, ô, ï et d'autres) ; il suffit donc d'une petite fonction qui convertit l'UTF-8 en codes de la police. Les lettres absentes du Latin-1, comme les lettres turques ğ, ı et ş de l'exemple ci-dessous, doivent être dessinées pixel par pixel et ajoutées avec addChar(). Le programme fait les deux.
1// MAX7219 + MD_Parola: Türkçe karakterli kayan yazı / Scrolling text with Turkish letters
2#include <MD_Parola.h>
3#include <MD_MAX72xx.h>
4#include <SPI.h>
5
6#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
7#define MAX_DEVICES 4
8#define CS_PIN 10
9
10MD_Parola display = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
11
12// Fontta olmayan 6 harf: ilk bayt genişlik, sonrakiler sütunlar (bit 0 = en üst satır)
13// 6 letters missing from the font: first byte is the width, then the columns (bit 0 = top row)
14const uint8_t trG[] = {5, 56, 69, 70, 85, 116}; // Ğ
15const uint8_t trg[] = {4, 25, 166, 166, 125}; // ğ
16const uint8_t trI[] = {3, 68, 125, 68}; // İ
17const uint8_t tri[] = {1, 124}; // ı
18const uint8_t trS[] = {5, 70, 73, 201, 73, 49}; // Ş
19const uint8_t trs[] = {4, 88, 212, 84, 52}; // ş
20
21// UTF-8 metni fontun kodlarına çevirir / converts UTF-8 text to the font's codes
22void utf8ToFont(const char *src, char *dst, size_t size) {
23 size_t n = 0;
24 while (*src && n < size - 1) {
25 uint8_t c = *src++;
26 if (c < 0x80) { dst[n++] = c; continue; } // ASCII aynen kalır / ASCII stays as is
27 if ((c & 0xE0) == 0xC0 && *src) { // 2 baytlık harf / 2-byte letter
28 uint16_t u = ((c & 0x1F) << 6) | (*src++ & 0x3F);
29 switch (u) {
30 case 0x11E: dst[n++] = (char)0x80; break; // Ğ
31 case 0x11F: dst[n++] = (char)0x81; break; // ğ
32 case 0x130: dst[n++] = (char)0x82; break; // İ
33 case 0x131: dst[n++] = (char)0x83; break; // ı
34 case 0x15E: dst[n++] = (char)0x84; break; // Ş
35 case 0x15F: dst[n++] = (char)0x85; break; // ş
36 default: dst[n++] = (u < 0x100) ? (char)u : '?'; // ç ö ü Ç Ö Ü ° fontta var / already in the font
37 }
38 continue;
39 }
40 while ((*src & 0xC0) == 0x80) src++; // desteklenmeyen karakteri atla / skip an unsupported character
41 dst[n++] = '?';
42 }
43 dst[n] = '\0';
44}
45
46char message[96];
47
48void setup() {
49 display.begin();
50 display.setIntensity(3);
51 display.addChar(0x80, trG); // addChar begin()'den sonra / addChar after begin()
52 display.addChar(0x81, trg);
53 display.addChar(0x82, trI);
54 display.addChar(0x83, tri);
55 display.addChar(0x84, trS);
56 display.addChar(0x85, trs);
57 utf8ToFont("Günaydın İstanbul! Şehirde hava 22°C, çok güzel bir gün.", message, sizeof(message));
58 display.displayText(message, PA_LEFT, 40, 1000, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
59}
60
61void loop() {
62 if (display.displayAnimate()) display.displayReset();
63}Dans chaque tableau de caractère personnalisé, le premier octet donne la largeur de la lettre en colonnes et les octets suivants les colonnes de gauche à droite ; le bit 0 de chaque octet correspond à la ligne du haut. Par exemple, le ı turc (i sans point) tient sur une seule colonne et la valeur 124 (0b01111100) allume les lignes 2 à 6 ; il ne diffère du i normal que par l'absence du point. Pour les majuscules Ğ et İ, la lettre a été raccourcie de deux lignes (5 au lieu de 7) afin de laisser la place au signe au-dessus. addChar() ne copie pas les données, elle ne garde que leur adresse : les tableaux doivent donc être globaux et ajoutés après begin(). Les codes 0x80 à 0x85 ont été choisis parce qu'ils n'apparaissent jamais dans un texte normal. De la même façon, tu peux ajouter n'importe quel symbole, comme un cœur ou une flèche.
Exemple d'horloge : horloge numérique avec un module RTC

Le compteur millis() de l'Arduino repart de zéro après une coupure de courant et, à cause du résonateur céramique de l'Uno, il peut dériver de plusieurs minutes par jour. Pour une vraie horloge, utilise un module horloge RTC. Branche le module DS1307 sur le bus I2C (SDA → A4, SCL → A5, VCC → 5V, GND → GND) ; le MAX7219 utilise les broches SPI, les deux modules ne se gênent donc pas. Pour le code, installe la bibliothèque RTClib d'Adafruit depuis le gestionnaire de bibliothèques.
1// MAX7219 + DS1307 RTC ile dijital saat / Digital clock with MAX7219 + DS1307 RTC
2#include <MD_Parola.h>
3#include <MD_MAX72xx.h>
4#include <SPI.h>
5#include <RTClib.h> // Adafruit RTClib
6
7#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
8#define MAX_DEVICES 4
9#define CS_PIN 10
10
11MD_Parola display = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
12RTC_DS1307 rtc; // SDA = A4, SCL = A5
13
14char timeText[8]; // "12:34" + sonlandırıcı / + terminator
15uint8_t lastSecond = 99;
16
17void setup() {
18 display.begin();
19 display.setIntensity(2);
20 display.setTextAlignment(PA_CENTER); // print() bu hizalamayı kullanır / print() uses this alignment
21 if (!rtc.begin()) {
22 display.print("RTC?"); // modül bulunamadı / module not found
23 while (true) {}
24 }
25 if (!rtc.isrunning()) {
26 rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // ilk kurulumda derleme saati / compile time on first run
27 }
28}
29
30void loop() {
31 DateTime now = rtc.now();
32 if (now.second() != lastSecond) { // saniyede bir güncelle / update once a second
33 lastSecond = now.second();
34 // ':' ve boşluk aynı genişlikte, yazı kaymaz / ':' and space are equally wide, nothing shifts
35 sprintf(timeText, (lastSecond % 2) ? "%02d %02d" : "%02d:%02d", now.hour(), now.minute());
36 display.print(timeText);
37 }
38}Le programme lit l'heure une fois par seconde et fait clignoter les deux-points. Dans la police par défaut, les deux-points (:) et l'espace ont la même largeur (2 colonnes), les chiffres ne bougent donc pas. Au premier démarrage, la RTC est réglée sur l'instant où le programme a été compilé. Un DS1307 peut dériver d'environ une minute par mois ; pour une horloge plus précise, prends un module DS3231 et utilise dans le code RTC_DS3231 au lieu de RTC_DS1307 et remplace la condition if (!rtc.isrunning()) par if (rtc.lostPower()). Grâce à son quartz compensé en température, le DS3231 ne dérive que d'environ une minute par an. Tu peux aussi diviser l'afficheur en deux zones pour montrer l'heure d'un côté et la température de l'autre.
Animation : dessiner pixel par pixel avec MD_MAX72XX
Pour aller au-delà du texte défilant, tu peux utiliser directement la bibliothèque MD_MAX72XX. Elle traite toute la chaîne comme un seul afficheur de pixels : un module 4 en 1 compte 32 colonnes et 8 lignes. setPoint(ligne, colonne, état) allume ou éteint une seule LED, setColumn() écrit d'un coup les 8 bits d'une colonne et clear() efface l'afficheur. L'origine (0, 0) est le coin supérieur droit ; les numéros de colonne augmentent vers la gauche et les numéros de ligne vers le bas. Le code suivant dessine une balle qui rebondit sur les bords de l'afficheur :
1// MD_MAX72XX ile seken top animasyonu / Bouncing ball animation with MD_MAX72XX
2#include <MD_MAX72xx.h>
3#include <SPI.h>
4
5#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
6#define MAX_DEVICES 4
7#define CS_PIN 10
8
9MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
10
11int x = 0, y = 0; // topun konumu (sütun, satır) / ball position (column, row)
12int dx = 1, dy = 1; // hareket yönü / direction of travel
13
14void setup() {
15 mx.begin();
16 mx.control(MD_MAX72XX::INTENSITY, 2);
17 mx.clear();
18}
19
20void loop() {
21 const int lastCol = mx.getColumnCount() - 1; // 4 modülde 31 / 31 with 4 modules
22 mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF); // çizim bitene kadar gönderme / hold updates while drawing
23 mx.setPoint(y, x, false); // eski konumu sil / erase the old position
24 x += dx;
25 y += dy;
26 if (x <= 0 || x >= lastCol) dx = -dx; // kenara çarpınca dön / bounce off the edge
27 if (y <= 0 || y >= 7) dy = -dy;
28 mx.setPoint(y, x, true); // yeni konumu yak / light the new position
29 mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON); // hepsini tek seferde gönder / send everything at once
30 delay(40);
31}À chaque image, la mise à jour automatique (UPDATE) est d'abord coupée, l'ancien pixel est effacé et le nouveau dessiné, puis UPDATE est réactivé pour envoyer toutes les modifications aux modules en une seule fois. Ainsi, une image à moitié dessinée n'apparaît jamais. Sur le même principe, tu peux dessiner un dé, des smileys, un jeu du serpent ou des barres de niveau sonore. Les exemples de MD_MAX72XX proposent aussi des animations toutes prêtes comme Pac-Man, des yeux de robot et un sablier. Avec MD_Parola, tu accèdes aux mêmes fonctions de dessin grâce à getGraphicObject().
Messages par internet avec un ESP32 : texte défilant depuis ton téléphone
Avec un ESP32, ton panneau à texte défilant devient sans fil. Le code ci-dessous se connecte à ton réseau domestique, fait d'abord défiler sa propre adresse IP, puis affiche l'heure récupérée sur internet (NTP). Ouvre cette adresse IP dans le navigateur d'un téléphone connecté au même Wi-Fi : tu verras une zone de texte, et le message que tu tapes commence à défiler au tour suivant, en alternance avec l'heure. Le module se branche sur les broches VSPI comme dans le tableau : CLK sur GPIO 18, DIN sur GPIO 23 et CS sur GPIO 5. Si tu découvres l'ESP32, lis d'abord Qu'est-ce que l'ESP32 ?.
1// ESP32: telefondan mesaj + internet saati / ESP32: message from your phone + internet time
2#include <WiFi.h>
3#include <WebServer.h>
4#include <time.h>
5#include <MD_Parola.h>
6#include <MD_MAX72xx.h>
7#include <SPI.h>
8
9#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
10#define MAX_DEVICES 4
11#define CS_PIN 5 // VSPI: CLK = GPIO 18, DIN = GPIO 23
12
13const char* ssid = "AgAdi"; // Wi-Fi adın / your Wi-Fi name
14const char* password = "Sifre123"; // Wi-Fi şifren / your Wi-Fi password
15
16MD_Parola display = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
17WebServer server(80);
18
19char message[128];
20char nextMessage[128];
21char clockText[8] = "--:--";
22bool newMessage = false;
23bool showClock = false;
24
25const char PAGE[] = R"rawliteral(<!DOCTYPE html><html><head><meta charset="utf-8">
26<meta name="viewport" content="width=device-width"><title>MAX7219</title></head><body>
27<h2>Kayan yazı / Scrolling text</h2>
28<form action="/"><input name="m" maxlength="100"> <button>Gönder / Send</button></form>
29</body></html>)rawliteral";
30
31void handleRoot() {
32 if (server.hasArg("m")) { // formdan gelen mesaj / message from the form
33 server.arg("m").toCharArray(nextMessage, sizeof(nextMessage));
34 newMessage = true;
35 }
36 server.send(200, "text/html; charset=utf-8", PAGE);
37}
38
39void setup() {
40 display.begin();
41 display.setIntensity(3);
42 display.print("WiFi..");
43 WiFi.begin(ssid, password);
44 while (WiFi.status() != WL_CONNECTED) delay(500);
45 configTime(3 * 3600, 0, "pool.ntp.org"); // Türkiye UTC+3 / Turkey is UTC+3
46 snprintf(message, sizeof(message), "IP: %s", WiFi.localIP().toString().c_str());
47 server.on("/", handleRoot);
48 server.begin();
49 display.displayText(message, PA_LEFT, 40, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
50}
51
52void loop() {
53 server.handleClient();
54 if (display.displayAnimate()) { // önceki gösterim bitti / the previous show has ended
55 showClock = !showClock;
56 if (newMessage) { // yeni mesaj sırayı keser / a new message jumps the queue
57 strlcpy(message, nextMessage, sizeof(message));
58 newMessage = false;
59 showClock = false;
60 }
61 if (showClock) {
62 struct tm t;
63 if (getLocalTime(&t, 10)) strftime(clockText, sizeof(clockText), "%H:%M", &t);
64 display.displayText(clockText, PA_CENTER, 40, 3000, PA_SCROLL_DOWN, PA_SCROLL_UP);
65 } else {
66 display.displayText(message, PA_LEFT, 40, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
67 }
68 }
69}handleRoot() n'affiche pas tout de suite le message reçu du formulaire : il le met en attente dans nextMessage. Le message n'est copié qu'à la fin de l'animation en cours (quand displayAnimate() renvoie true) ; ainsi, le texte que MD_Parola est en train de lire ne change jamais en cours de route. La valeur 3 × 3600 de configTime() correspond au fuseau UTC+3 de la Turquie ; en France, en Belgique ou en Suisse, remplace cette ligne par configTzTime("CET-1CEST,M3.5.0,M10.5.0/3", "pool.ntp.org"), qui gère aussi l'heure d'été. Pour des messages avec accents, ajoute à ce programme les lignes addChar() et la fonction utf8ToFont() vues plus haut, et remplace la ligne strlcpy() par utf8ToFont(nextMessage, message, sizeof(message)). Pour l'heure par internet et les tableaux de bord web en temps réel, consulte Horloge NTP avec ESP32 et Serveur web et WebSocket avec ESP32.
MAX7219 avec le Raspberry Pi Pico et MicroPython
Sur le Pico avec MicroPython, le plus pratique est de copier le pilote libre max7219.py (micropython-max7219) sur le Pico avec Thonny. Comme ce pilote s'appuie sur le module framebuf de MicroPython, des fonctions de dessin comme text(), pixel(), line() et rect() sont disponibles tout de suite, et l'orientation est correcte sur les modules 4 en 1 FC-16. Alimente le module par VBUS (5 V) et relie DIN à GP19, CLK à GP18 et CS à GP17. MicroPython réserve aussi la broche MISO du SPI0 (GP16) : ne l'utilise pas pour autre chose. La police de framebuf fait 8x8 pixels et ne contient que l'ASCII ; un module 4 en 1 affiche donc 4 lettres à la fois et pas d'accents. Pour l'installation, vois Qu'est-ce que le Raspberry Pi Pico ? et Les bases de MicroPython.
1# Pico + 4'lü MAX7219 modül: kayan yazı / Pico + 4-in-1 MAX7219 module: scrolling text
2from machine import Pin, SPI
3import time
4import max7219 # max7219.py Pico'da olmalı / must be on the Pico
5
6# GP18 = SCK -> CLK, GP19 = MOSI -> DIN, GP17 -> CS; GP16 (MISO) boş kalır / GP16 (MISO) stays free
7spi = SPI(0, baudrate=5_000_000, polarity=0, phase=0, sck=Pin(18), mosi=Pin(19))
8display = max7219.Matrix8x8(spi, Pin(17, Pin.OUT), 4)
9display.brightness(3) # parlaklık 0–15 / brightness 0–15
10
11def scroll(text, delay_ms=35):
12 width = len(text) * 8 # her harf 8 piksel / each letter is 8 px wide
13 for x in range(32, -width, -1): # sağdan girip solda kaybolur / enters right, leaves left
14 display.fill(0)
15 display.text(text, x, 0, 1)
16 display.show()
17 time.sleep_ms(delay_ms)
18
19while True:
20 scroll("BlueGrays + Pico")
21 display.fill(0)
22 display.text("Pico", 0, 0, 1) # 4 harf tam sığar / exactly 4 letters fit
23 display.show()
24 time.sleep(1)
25 display.fill(0)
26 display.rect(0, 0, 32, 8, 1) # ekran çerçevesi / display frame
27 display.show()
28 time.sleep_ms(500)Idées de projets avec le MAX7219
- Panneau à texte défilant : fabrique un tableau de messages pour une boutique, une salle de classe ou la porte de ta chambre, et change le message depuis ton téléphone avec un module Bluetooth HC-05.
- Horloge, calendrier et température : affiche à tour de rôle l'heure et la date de la RTC, puis la température et l'humidité d'un capteur DHT11.
- Horloge internet et météo : fais défiler avec un ESP32 l'heure NTP et la température obtenue auprès d'une API météo.
- Tableau de score : pilote un afficheur à deux zones pour un match de ping-pong ou de basket avec une télécommande IR.
- Mini-jeux : joue au serpent, à Pong ou à un jeu d'esquive sur l'afficheur 32x8 avec un joystick ; d'autres idées dans Projets de jeux Arduino.
- Vumètre : dessine les mesures d'un capteur de son sous forme de bargraphe de 32 colonnes.
- Panneau d'animation 32x32 : empile quatre modules 4 en 1 et joue des animations comme de la pluie, des étoiles ou un feu d'artifice.
Erreurs fréquentes et solutions
| Symptôme | Cause probable | Solution |
|---|---|---|
| Aucune LED ne s'allume | Pas d'alimentation, fils branchés côté OUT ou broche CS différente du code | Branche les fils côté IN marqué DIN, vérifie CS_PIN et l'alimentation 5 V |
| Toutes les LED sont allumées à fond et ne changent pas | Les données n'arrivent pas : DIN et CLK inversés ou puce restée en mode test | Relie DIN à MOSI et CLK à SCK, puis coupe et remets l'alimentation |
| Lettres en miroir, à l'envers ou tournées de 90 degrés | Mauvais HARDWARE_TYPE | Essaie FC16_HW sur le module 4 en 1 et GENERIC_HW sur le module seul |
| Tout le texte est à l'envers et défile de gauche à droite | Module monté à l'envers, entrée DIN à gauche | Tourne le module de 180 degrés ; l'entrée DIN doit être à droite |
| Un seul bloc fonctionne ou le texte paraît coupé | MAX_DEVICES erroné ou liaison coupée entre modules | Mets le nombre de blocs dans MAX_DEVICES et vérifie les fils OUT → IN |
| L'Arduino redémarre ou l'image scintille à forte luminosité | La limite USB de 500 mA est dépassée, la tension chute | Utilise une alimentation externe 5 V 2 A, relie les GND et baisse la luminosité |
| Points aléatoires et caractères brouillés avec l'ESP32 | Le signal 3,3 V est sous le seuil HIGH de 3,5 V, fils trop longs | Remonte le niveau avec un 74HCT125 et raccourcis les fils |
| Les lettres accentuées deviennent des symboles incompréhensibles | Les octets UTF-8 arrivent tels quels dans la police | Utilise la méthode utf8ToFont() et addChar() |
| Le texte défilant avance par saccades | Un delay() ou une tâche longue se trouve dans loop() | Appelle displayAnimate() souvent et gère les attentes avec millis() |
Le MAX7219 est l'un des moyens les moins chers d'obtenir un afficheur accrocheur avec quelques fils : la puce gère le balayage, la limitation du courant et la luminosité, et toi, tu te concentres sur ce que tu veux afficher. Commence par dessiner des icônes sur un module 8x8, puis passe au texte défilant, à l'horloge et aux messages sans fil avec un ESP32 sur un module 4 en 1. Si tu veux des LED de couleur pilotées une par une, les WS2812B NeoPixel sont un bon choix, et pour un projet qui n'affiche que des chiffres, un afficheur 7 segments. Dans l'application BlueGrays, tu trouveras des projets MAX7219 comme une horloge et un calendrier à matrice de points, une station météo, des animations 32x8 et du texte défilant, pas à pas avec schémas et code.
Questions fréquentes
Pourquoi le texte de mon module MAX7219 est-il en miroir ou à l'envers ?
Les fabricants câblent la matrice 8x8 au MAX7219 de différentes manières, et la bibliothèque compense avec le réglage HARDWARE_TYPE. La plupart des modules 4 en 1 bleus vendus aujourd'hui s'affichent correctement avec FC16_HW, et les modules seuls verts avec GENERIC_HW. Si l'image reste fausse, essaie aussi PAROLA_HW et ICSTATION_HW ; une seule ligne du code change.
Combien de modules MAX7219 peut-on chaîner ?
La puce elle-même n'impose aucune limite et, comme MD_MAX72XX stocke le nombre de modules dans un octet, la bibliothèque en accepte jusqu'à 255. En pratique, ce sont l'alimentation et la qualité du signal qui limitent : réinjecte le 5 V et le GND tous les 4 à 8 blocs, garde des fils courts et ajoute à chaque module un condensateur de 10 µF et un de 100 nF. Plus la chaîne est longue, plus chaque mise à jour prend de temps et de RAM.
Le MAX7219 fonctionne-t-il avec un ESP32 en 3,3 V ?
Le MAX7219 a besoin d'au moins 4 V d'alimentation : alimente donc le module par la broche 5V (VIN) de l'ESP32. La fiche technique exige 3,5 V pour un niveau HIGH avec une alimentation de 5 V ; les signaux 3,3 V de l'ESP32 fonctionnent tout de même sur la plupart des modules, mais restent sous cette limite. Pour un fonctionnement fiable, place un adaptateur de niveau comme le 74HCT125 sur les lignes DIN, CLK et CS.
Quelle est la consommation d'une matrice LED MAX7219 ?
Un module 8x8 avec toutes ses LED allumées à pleine luminosité consomme environ 330 mA, et un module 4 en 1 8x32 jusqu'à 1,3 A. Avec un texte défilant, seule une partie des LED est allumée et la luminosité reste en général entre 2 et 7 ; un module 4 en 1 consomme alors d'habitude 100 à 250 mA. En veille, chaque puce ne consomme qu'environ 150 µA.
Comment afficher les accents sur une matrice MAX7219 ?
La police par défaut de MD_Parola contient é, è, à, ç et les autres caractères Latin-1, mais l'Arduino IDE les enregistre sous forme de deux octets UTF-8. Convertis donc le texte en codes de la police avec une petite fonction avant de l'afficher. Les caractères absents du Latin-1 peuvent être dessinés par toi et ajoutés avec addChar().
Peut-on piloter un afficheur 7 segments avec un MAX7219 ?
Oui. Le MAX7219 a en fait été conçu pour des afficheurs 7 segments à cathode commune jusqu'à 8 chiffres, et il dispose d'un mode BCD qui décode lui-même les chiffres. Tu peux utiliser facilement les modules d'affichage MAX7219 à 8 chiffres avec la fonction setDigit() de la bibliothèque LedControl. Les afficheurs à anode commune ne peuvent pas, eux, être branchés directement sur cette puce.
Projets à réaliser après cet article
Voir tous les projets
Horloge et calendrier matriciel (MAX7219, DS1307)
Un panneau lumineux pour ton bureau ou ton mur, qui affiche l'heure et la date en texte défilant. Sur l'écran LED 8x32, une horloge à gros chiffres fait clignoter ses deux points chaque seconde ; au d

Horloge matricielle, calendrier et station météo (MAX7219, DS1307)
Un panneau à texte défilant pour ton bureau ou ton mur, qui affiche tour à tour l'heure, la date et la météo de la pièce. Sur l'écran LED 8x32 apparaissent d'abord la température en Celsius et en Fahr

Animation matricielle 4x 32x8 LED et texte
Empile quatre longs modules à matrice de LED et tu obtiens un écran carré de plus de mille points lumineux. D'abord, des lettres tombent du haut comme une pluie de film, puis un rideau s'ouvre et deux

Matrice LED 4x 32x8 - Pack de 6 animations
Quatre panneaux LED 32x8 empilés forment un écran carré sur lequel six animations se succèdent : une pluie numérique qui tombe, une spirale qui grandit, des cellules qui naissent et meurent toutes seu

Serpent à pixels Matrice 8x8
Construis de tes mains le jeu classique du serpent et joue. Sur une matrice lumineuse colorée de 8x8, tu guides un serpent vert avec un joystick et tu manges des pommes rouges ; à chaque pomme, le ser

ESP32 : heure réelle depuis Internet via NTP
L'ESP32 se connecte au Wi-Fi et récupère l'heure réelle avec une précision de la milliseconde depuis des serveurs NTP (Network Time Protocol). Grâce à `configTzTime()`, le fuseau horaire de la Turquie (TRT, UTC+3) est appliqué automatiquement et le passage DST est géré via la chaîne POSIX TZ. L'heure est affichée sur le moniteur série et sur un écran LCD I2C en option. `configTzTime()` démarre le service SNTP ; des resynchronisations périodiques ont lieu tant que l'accès au réseau est disponible

Horloge numérique avec ESP32 et RTC DS1307 (I2C + LCD)
Dans ce projet, nous affichons l'heure et la date sur un écran LCD 16x2 I2C à l'aide du module d'horloge en temps réel (RTC) DS1307. Le DS1307 est une RTC avec batterie de secours qui conserve l'heure même si l'ESP32 s'éteint. Les deux modules partagent la même ligne I2C (SDA/SCL), ce qui nous permet d'apprendre à contrôler plusieurs appareils avec seulement deux fils de signal. Vous decouvrirez ainsi le protocole I2C et le fonctionnement des modules RTC en pratique.

Horloge numérique avec afficheur 7 segments à 4 chiffres
Une horloge numérique lumineuse à quatre chiffres, comme celle du four de la cuisine. Le module horloge DS1302 garde l'heure, et chaque seconde l'Arduino lit les heures et les minutes et les affiche s
Autres articles
Application BlueGrays
Réalise ce montage pas à pas sur ton téléphone
Schéma, code et liste des composants sur un seul écran. Plus de 160 projets Arduino, ESP32 et Pico à réaliser.
Scanne avec ton téléphone
Pointe l’appareil photo vers le code : la boutique d’applications de ton téléphone s’ouvre.
ou ouvre la boutique

