Dans ce tutoriel, vous allez apprendre à coordonner les animations de zones Parola sur un écran à matrice LED MAX7219. Le MD_Parola library est une bibliothèque populaire qui facilite la programmation d’animations comme le défilement de texte. Elle permet aussi de diviser un écran en plusieurs zones et d’exécuter différentes animations dans ces zones.
Cependant, coordonner les animations dans plusieurs zones n’est pas simple. Par exemple, comment redémarrer une animation dans une zone sans affecter l’animation d’une autre zone ? Ou comment redémarrer toutes les animations uniquement lorsque toutes sont terminées, même si elles tournent à des vitesses différentes ?
Ce tutoriel vous donnera une structure de code pour gérer facilement ce type de scénarios d’animation.
Matériel nécessaire
J’ai utilisé un Arduino Uno pour ce projet, mais n’importe quelle autre carte Arduino, ou une carte ESP8266/ESP32, fonctionnera aussi. J’ai également utilisé un écran à matrice LED MAX7219 avec 4 modules. Mais le code et le câblage pour des écrans avec un nombre différent de modules sont essentiellement les mêmes.

Écran à matrice LED MAX7219

Arduino Uno

Jeu de fils Dupont

Câble USB pour Arduino UNO
Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.
Connexion de l’écran LED MAX7219 à l’Arduino
Dans ce tutoriel, nous allons utiliser un écran à matrice LED MAX7219 pour afficher des animations. Le contrôleur d’affichage MAX7219 communique avec l’Arduino via le SPI (Serial Peripheral Interface). Donc, la première chose à faire est de connecter l’écran à l’Arduino en utilisant l’interface SPI.
Câblage
Le schéma ci-dessous montre le câblage entre l’écran MAX7219 et un Arduino Uno. Assurez-vous de vous connecter du côté entrée (DIN) et non du côté sortie (DOUT) de l’écran.

Commencez par connecter les broches de l’interface SPI : la broche 11 de l’Arduino est reliée à la broche DIN de l’écran. Ensuite, connectez la broche 3 à CS et la broche 13 à CLK. Enfin, reliez le 5V à VCC et GND à GND. Le tableau suivant récapitule les connexions
| Écran | Arduino |
|---|---|
| VCC | 5 V |
| GND | GND |
| DIN | 11 (MOSI) |
| CS | 3 (SS) |
| CLK | 13 (SCK) |
Les broches ci-dessus sont pour le SPI matériel, qui est plus rapide que le SPI logiciel mais nécessite d’utiliser des broches spécifiques qui varient selon les cartes. Pour plus de détails, consultez la MAX7219 LED dot matrix display Arduino tutorial .
Écrivons et lançons maintenant un code de test pour vérifier que les connexions sont correctes.
Installer les bibliothèques MD_Parola et MD_MAX72XX
Tout d’abord, vous devez installer la MD_MAX72XX et la MD_Parola bibliothèque. Ouvrez le Arduino IDE et allez dans Tools > Manage Libraries pour ouvrir le Library Manager. Cherchez « MD_MAX72XX » et les bibliothèques concernées apparaîtront. La capture d’écran ci-dessous montre les deux bibliothèques (en jaune) après leur installation.

La bibliothèque MD_MAX72XX est en fait le pilote logiciel pour l’écran LED MAX7219. La bibliothèque MD_Parola l’utilise pour créer des animations comme le défilement et les effets de texte sprite. Si vous voulez en savoir plus sur les animations disponibles, consultez la MAX7219 LED dot matrix display Arduino tutorial .
Code de test
Le code suivant est un exemple minimal pour tester le câblage et le fonctionnement de l’écran. Il fait simplement défiler le texte « Test » sur l’écran.
#include "MD_Parola.h"
#include "MD_MAX72xx.h"
#include "SPI.h"
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 3
MD_Parola disp = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
void setup() {
disp.begin();
disp.setIntensity(0);
disp.displayClear();
disp.displayText("Test", PA_CENTER, 100, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
}
void loop() {
if (disp.displayAnimate()) {
disp.displayReset();
}
}
Si vous téléversez et exécutez ce code, vous devriez voir le résultat suivant sur votre écran MAX7219 :

Pour plus de détails sur ce code de test, consultez le tutoriel Control Parola Animations on MAX7219 LED Display , où nous utilisons le même code de test.
Notez que si vous utilisez un autre type d’écran LED MAX7219 ou un écran avec plus ou moins de modules, vous devrez ajuster les définitions suivantes :
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW #define MAX_DEVICES 4
De même, si vous utilisez le SPI logiciel au lieu du SPI matériel, vous devrez modifier la façon dont l’objet écran est créé :
MD_Parola disp = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
Plus d’informations à ce sujet dans la MAX7219 LED dot matrix display Arduino tutorial .
Dans les sections suivantes, nous allons examiner de plus près les zones, comment les créer et les utiliser, et surtout comment coordonner les animations qui tournent dans différentes zones.
Qu’est-ce qu’une zone Parola ?
La bibliothèque Parola considère un écran LED MAX7219 comme une séquence de modules LED 8×8, numérotés de 0 à n-1 . Une « zone » est une section de modules consécutifs. Chaque zone peut être contrôlée indépendamment des autres. L’exemple ci-dessous montre un écran MAX7219 avec quatre modules (0…3) et deux définitions de zones.

La zone 0 inclut les modules 0 et 1, et la zone 1 inclut les modules 2 et 3. Notez que la numérotation des modules commence à 0 et du côté entrée (côté droit) de l’écran. Dans chaque zone, vous pouvez lancer différentes animations avec différentes polices, effets de texte, chaînes de texte, vitesses et même luminosités.
Les zones ne doivent pas se chevaucher, peuvent avoir des longueurs différentes et l’index de zone n’a pas besoin d’être dans le même ordre séquentiel que les modules. Par exemple, l’exemple suivant montre une autre définition de zone valide. Ici, nous avons trois zones (0,1,2) mais elles ont des longueurs différentes et les indices de zone ne sont pas dans l’ordre (0,2,1).

Comment définir des zones Parola
Supposons que nous voulons définir les zones d’affichage suivantes. La zone 0 va du module 0 au module 1, et la zone 1 va du module 2 au module 3 :

Dans la fonction setup, commencez par appeler begin() avec le nombre total de zones (ici 2). Ensuite, vous définissez les zones individuelles en appelant setZone(z, start, end) . Le premier argument z est l’identifiant de la zone (0 ou 1, dans notre cas), puis l’index du premier et du dernier module de cette zone.
#define MAX_ZONES 2
void setup() {
disp.begin(MAX_ZONES);
disp.setZone(0, 0, 1);
disp.setZone(1, 2, 3);
}
Comme mentionné précédemment, les zones ne doivent pas se chevaucher, mais c’est possible. Cependant, si elles se chevauchent, vous devez vous assurer que les zones qui se chevauchent ne lancent pas d’animations en même temps, sinon vous obtiendrez des artefacts étranges.
Une fois les zones définies, vous pouvez leur attribuer des animations. Par exemple, la ligne de code suivante définit une animation pour la zone 0 qui fait défiler le texte « Left » vers la gauche. Plus d’infos à ce sujet dans la section suivante.
disp.displayZoneText(0, "Left", PA_CENTER, 100, 0, PA_SCROLL_RIGHT, PA_SCROLL_RIGHT);
Comment animer les zones Parola
La plupart des fonctions d’animation Parola existent en deux versions. Une version qui agit sur tout l’écran, et une autre qui agit sur une zone spécifique. Consultez la Parola Documentation pour un aperçu.
Par exemple, vous pouvez régler la luminosité de tout l’écran ou d’une zone spécifique en appelant setIntensity soit sans, soit avec un index de zone.
setIntensity(intensity); // entire display setIntensity(z, intensity); // zone z
C’est pareil pour la plupart des autres fonctions pour définir les polices, effets de texte, chaînes de texte, vitesses, etc. L’extrait de code suivant montre comment afficher et animer différents textes dans deux zones. Dans la première zone (0), on fait défiler le texte « 0 » vers la droite, et dans la seconde zone (1), on fait défiler le texte « 1 » vers la gauche.
#define SPEED 100
void setup() {
disp.begin(MAX_ZONES);
disp.setZone(0, 0, 1);
disp.setZone(1, 2, 3);
disp.displayZoneText(0, "0", PA_CENTER, SPEED, 0, PA_SCROLL_RIGHT, PA_SCROLL_RIGHT);
disp.displayZoneText(1, "1", PA_CENTER, SPEED, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
}
Dans la fonction loop, on appelle simplement la fonction habituelle displayAnimate() pour savoir si l’une des deux animations est terminée et, si c’est le cas, on réinitialise l’affichage pour toutes les zones via displayReset() .
void loop() {
if (disp.displayAnimate()) {
disp.displayReset();
}
}
Notez que vous pouvez aussi réinitialiser les zones individuellement en appelant displayReset(z) avec un identifiant de zone. Nous verrons cela plus tard.
void loop() {
if (disp.displayAnimate()) {
disp.displayReset(0);
disp.displayReset(1);
}
}
Cela fonctionne bien, surtout parce que les deux animations ici tournent à la même vitesse (100). Mais si les animations tournent à des vitesses différentes ou ont des textes de longueurs différentes, alors une animation se terminera avant l’autre. Comment gérer ce cas et spécifier ce qui doit se passer ?
La coordination entre les animations sur plusieurs zones est le sujet de la section suivante.
Comment coordonner les zones Parola
Comme mentionné plus haut, la boucle Parola par défaut appelle displayAnimate() , qui renvoie true si une animation dans n’importe quelle zone est terminée. Vous pouvez savoir laquelle est terminée en appelant getZoneStatus(z) avec l’identifiant de la zone z .
Par exemple, si vous avez deux zones, vous pouvez redémarrer les animations dans les deux zones lorsque les deux sont terminées en écrivant le code suivant :
void loop() {
if (disp.displayAnimate()) {
if(disp.getZoneStatus(0) && disp.getZoneStatus(1)) {
disp.displayReset();
}
}
}
Cela fonctionne bien et c’est parfait pour ce cas simple. Mais si vous avez des scénarios un peu plus complexes ou plus de zones, vous vous retrouvez vite avec un code très confus. Par exemple, supposons que nous avons deux animations dans deux zones et qu’une animation est plus rapide que l’autre. Cela donne au moins six scénarios d’animation possibles
- Laisser les deux animations tourner une seule fois
- Laisser la première animation tourner une fois, répéter l’autre
- Laisser la seconde animation tourner une fois, répéter l’autre
- Répéter les deux animations quand les deux sont terminées
- Répéter l’animation la plus rapide pendant que la plus lente tourne encore
- Redémarrer l’animation la plus lente quand la plus rapide est terminée
Dans les sections suivantes, nous allons implémenter ces six scénarios d’animation. Mais pour simplifier, nous allons d’abord définir une fonction utilitaire getStatus() .
Fonction getStatus
Au lieu d’appeler getZoneStatus(z) pour chaque zone, la fonction getStatus() suivante retourne un vecteur de bits qui indique le statut de toutes les zones en une seule fois.
byte getStatus() {
static byte status = 0;
disp.displayAnimate();
for (int z = 0; z < MAX_ZONES; z++) {
disp.getZoneStatus(z) ? bitSet(status, z) : bitClear(status, z);
}
return status;
}
En interne, la fonction parcourt toutes les zones et définit le statut de la zone dans l’octet status . Cela signifie que le nombre maximal de zones est limité à 8, mais c’est généralement largement suffisant.
L’image suivante montre un exemple de vecteur de bits ou de statut que getStatus() retourne. Dans cet exemple, les animations des zones 1 et 3 sont terminées :

Si vous appelez getStatus() dans la boucle principale, vous pouvez facilement afficher le vecteur de statut.
void loop() {
Serial.println(getStatus(), BIN);
}
Notez que la fonction getStatus() appelle aussi en interne displayAnimate() , donc il n’est plus nécessaire de l’appeler dans la fonction loop.
Nous allons utiliser getStatus() dans les sections suivantes pour implémenter les six scénarios d’animation mentionnés plus haut.
Exemple de code avec deux zones
Commençons par un exemple de code qui contient tout sauf l’implémentation de la fonction loop.
#include "MD_Parola.h"
#include "MD_MAX72xx.h"
#include "SPI.h"
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define MAX_ZONES 2
#define CS_PIN 3
MD_Parola disp = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
byte getStatus() {
static byte status = 0;
disp.displayAnimate();
for (int z = 0; z < MAX_ZONES; z++) {
disp.getZoneStatus(z) ? bitSet(status, z) : bitClear(status, z);
}
return status;
}
void setup() {
disp.begin(MAX_ZONES);
disp.setZone(0, 0, 1);
disp.setZone(1, 2, 3);
disp.setIntensity(0);
disp.displayClear();
disp.displayZoneText(0, "0", PA_CENTER, 100, 0, PA_SCROLL_RIGHT, PA_SCROLL_RIGHT);
disp.displayZoneText(1, "1", PA_CENTER, 200, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
}
void loop() {
// TODO
}
Dans ce code, on inclut d’abord les bibliothèques nécessaires et on définit les constantes pour l’écran MAX7219. Si vous avez un autre type d’écran ou un nombre différent de modules, vous devez modifier ces constantes.
Ensuite, on crée l’objet écran disp et on implémente la fonction getStatus() comme montré plus haut.
Dans la fonction setup, on définit deux animations dans deux zones. La première animation dans la zone 0 fait défiler le texte « 0 » vers la droite. La seconde animation dans la zone 1 fait défiler le texte « 1 » vers la gauche. L’image ci-dessous montre les deux zones avec leurs indices.

Notez que la première animation dans la zone 0 tourne plus vite (vitesse=100) que la seconde animation (vitesse=200) dans la zone 1. La courte vidéo ci-dessous montre le résultat.

On peut garder le code ci-dessus identique pour les six scénarios d’animation et seulement changer l’implémentation de la fonction loop.
Laisser les deux animations tourner une seule fois
Commençons par le cas le plus simple. Nous voulons que les deux animations tournent une seule fois jusqu’à leur fin. Dans ce cas, la fonction loop doit juste appeler getStatus() et n’a rien d’autre à faire.
void loop() {
getStatus();
}
Vous n’aurez probablement pas souvent besoin de ce cas, mais si vous l’implémentez et l’exécutez, cela donne ceci :

Notez cependant que, comme la vidéo est en boucle, on a l’impression que l’animation redémarre. Ce n’est en fait pas le cas : l’animation tourne une seule fois puis l’écran reste vide. Utile peut-être pour un message de démarrage qui n’apparaît qu’une fois.
Laisser la première animation tourner une fois, répéter l’autre
Dans le scénario suivant, on laisse la première animation dans la zone 0 tourner une seule fois, mais on répète la seconde. Cela signifie que chaque fois que l’animation de la zone 1 se termine, on doit réinitialiser l’écran pour cette zone. Voici le code de la fonction loop pour ce scénario.
void loop() {
if(getStatus() & 0b00000010) {
disp.displayReset(1);
}
}
On récupère le statut et on effectue une opération bitwise AND (&) pour vérifier si l’animation de la zone 1 est terminée. Si c’est le cas, on appelle displayReset(1) pour cette zone afin de répéter l’animation. Le clip suivant montre le résultat :

Là encore, comme la vidéo est en boucle, on a l’impression que la première animation se répète, mais ce n’est pas le cas.
Laisser la seconde animation tourner une fois, répéter l’autre
Dans le scénario suivant, on inverse les rôles de la première et de la seconde animation. On laisse la seconde animation tourner une fois et on répète la première. Le code de la fonction loop est quasiment le même que précédemment, on change juste la zone concernée.
void loop() {
if(getStatus() & 0b00000001) {
disp.displayReset(0);
}
}
Le clip vidéo ci-dessous montre l’animation correspondante.

Répéter les deux animations quand les deux sont terminées
Maintenant, attendons que les deux animations soient terminées, puis réinitialisons-les toutes les deux. C’est très simple. Il suffit de vérifier si les deux bits de statut sont activés. Notez que dans ce cas, on ne fait pas un ET binaire (&) mais on vérifie l’égalité (=) !
void loop() {
if(getStatus() == 0b00000011) {
disp.displayClear();
disp.displayReset();
}
}
Dans le clip suivant, vous pouvez voir le résultat de cette animation.

Répéter l’animation la plus rapide pendant que la plus lente tourne encore
Comme les deux animations tournent à des vitesses différentes, il faut décider quoi faire quand l’animation la plus rapide se termine. Veut-on la redémarrer tout de suite ou attendre que la plus lente soit terminée ? Le cas où on attend a été traité dans la section précédente.
Voici le code qui couvre le premier cas. On vérifie simplement pour chaque zone si elle est terminée et, si oui, on redémarre l’animation correspondante.
void loop() {
if(getStatus() & 0b00000001) {
disp.displayReset(0);
}
if(getStatus() & 0b00000010) {
disp.displayReset(1);
}
}
Voici le clip vidéo qui montre ce scénario en action.

Redémarrer l’animation la plus lente quand la plus rapide est terminée
Le dernier scénario d’animation est l’inverse du précédent. Ici, on veut redémarrer l’animation la plus lente dès que la plus rapide est terminée. Notez que le code est assez différent du précédent.
void loop() {
if(getStatus() & 0b00000001) {
disp.displayReset(1);
disp.displayClear(1);
disp.displayReset(0);
}
}
En particulier, il faut effacer la zone 1, car on redémarre l’animation de la zone 1 avant qu’elle ne soit terminée. Si vous n’effacez pas l’écran, il restera des artefacts.
Le clip vidéo ci-dessous montre cette animation. Notez que le défilement vers la gauche du « 1 » est interrompu et réinitialisé dès que le défilement vers la droite du « 0 » est terminé.

Conclusions
Dans ce tutoriel, vous avez appris à coordonner des animations Parola qui tournent dans plusieurs zones. Les exemples ci-dessus n’utilisent que deux zones et restent assez simples. Cependant, dès que vous avez plus de deux zones, la fonction getStatus() va grandement simplifier votre code.
Par exemple, vous pouvez lister tous les statuts possibles des zones dans une instruction switch et les gérer en conséquence. Voici un exemple pour deux zones que vous pouvez facilement étendre à plus de zones.
void loop() {
switch (getStatus()) {
case 0b00000001:
...
break;
case 0b00000010:
...
break;
case 0b00000011:
...
break;
}
}
Nous n’avons pas utilisé cette structure dans les exemples de code ci-dessus, car avec deux zones cela ne simplifie pas vraiment le code, mais avec plus de zones, oui.
Si vous souhaitez enchaîner plusieurs animations ou les contrôler via des entrées externes, jetez un œil au tutoriel Control Parola Animations on MAX7219 LED Display .
Si vous voulez manipuler des pixels individuels de la matrice LED, la bibliothèque Parola n’est pas le bon choix et il vaut mieux utiliser FastLED ou quelque chose de similaire. Pour un exemple, voir l’article Game of Life on a Dot Matrix Display with MAX7219 .
J’espère que ce tutoriel vous sera utile. N’hésitez pas à laisser un commentaire si vous avez des questions.

