Apprendre à piloter un bargraphe 12 segments bicolores

ou comment fabriquer un indicateur de niveau à LED

f-leb

Dans ce tutoriel, vous allez apprendre à piloter un bargraphe à 12 segments bicolores avec une carte Arduino. Certes, ce genre de composants avec le circuit comportant le contrôleur existent déjà dans les enseignes spécialisées, avec en prime la bibliothèque logicielle. Mais dans la philosophie DIY (Do It Yourself), nous allons piloter ce bargraphe from scratch, ou presque, en plongeant dans les documentations constructeur des composants et des protocoles de communication.

Le plus important ici n'est pas le produit fini, mais la compréhension des principes de fonctionnement qui vont vous permettre, par l'expérimentation sur plaque d'essais, de progresser dans l'apprentissage de l'électronique numérique et de la programmation des systèmes à base de microcontrôleur tel l'Arduino.

À noter que pour démarrer dans de bonnes conditions, il est préférable d'avoir un peu d'expérience sur Arduino. Si vous avez déjà fait clignoter une LED montée en série avec une résistance sur une plaque d'essais (le Hello World, façon Arduino), vous êtes bien parti.

Commentez

- Titre : Apprendre à piloter un bargraphe 12 segments bicolores

- Auteur : f-leb

- Parution : 24 août 2016

- Public visé :

- Licence : Le contenu de cet article est rédigé par f-leb et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 3.0 non transposé. Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright ® 2013 Developpez.com.

Voir également :

- L'univers Arduino - Partie I : Aperçu de la plateforme Arduino et ses cartes d'interface (shields)

- L'univers Arduino - Partie II : Réalisation d'un prototype à base d'Arduino

- Arduino et le bus I2C - Exemple d'application : le capteur de température DS1621

Sommaire

- I. Présentation rapide du matériel et démonstration

- II. Description des composants et principe de fonctionnement

- II-A. Le bargraphe à LED

- II-B. Affichage multiplexé

- II-C. Le contrôleur d'affichage à LED MAX7219

- III. Préparation du montage

- III-A. Schéma de câblage

- III-B. Liaison MAX7219 - bargraphe

- III-B-1. Câblage

- III-B-2. Conséquences sur le codage

- III-C. Liaison SPI Arduino - MAX7219

- III-D. Alimentation du dispositif

- IV. Les registres du MAX7219

- V. Premiers tests

- VI. Codage de l'état des segments avec un tableau

- VII. Exemple d'application : un indicateur de niveau

- VIII. Et avec DEUX bargraphes !

- IX. Conclusion

- X. Sitographie

I - Présentation rapide du matériel et démonstration

Pour commencer une petite démonstration, d'un objet bien utile…

Animation en format "youtube" non supportée.
Contenu uniquement consultable en ligne à cette adresse :
https://www.youtube.com/watch?v=qIginZFcp0w

…qui rappellera les aventures d'un chevalier solitaire des années 80

Sur la plaquette de câblage rapide (breadboard), à gauche sur la photo, sont enfichés et chaînés deux bargraphes à LED (2 x 12 segments bicolores) identiques, et côte à côte pour n'en former plus qu'un en apparence. Pourquoi deux ? Parce que la démonstration n'en est que plus tape-à-l'œil ainsi pour seulement quelques euros de plus, et que le contrôleur MAX7219, la puce enfichée sur la plaquette de droite, peut les prendre en charge tous les deux.

Le MAX7219 (la version en boîtier DIP 28 broches) enfichée sur la plaquette de droite fera donc l'interface entre l'Arduino et les bargraphes. Ce seul composant permet de piloter jusqu'à 64 LED à partir d'une liaison série SPI utilisant seulement trois fils, les trois fils verts qui partent de la carte Arduino sur la photo.

Récapitulons le matériel :

Matériels

Remarques

- Carte Arduino

Ici, j'utiliserai une carte Arduino/Genuino UNO, mais vous devriez pouvoir utiliser n'importe quelle carte Arduino/Genuino compatible.
Prix constaté : environ 20 € pour la UNO.

- Bargraphe à 12 segments bicolores (x2)
Réf : KWL-R1230CDUGB (à cathode commune)

Voir la datasheet des composants de la série KWL-R1230 du constructeur Luckylight.
C'est le modèle KWL-R1239CDUGB qu'il faut prendre, celui à cathode commune.
Prix constaté : j'ai pu en trouver un lot de deux pour environ 4-5 € (chez Lextronic).

- Contrôleur d'afficheurs à LED
Réf. : MAX7219CNG

Voir la datasheet sur le site du constructeur Maxim Integrated : MAX7219
Penser à commander la version en boîtier DIP (MAX7219CNG), pour un prototype à câbler sans soudure.
Prix constaté : environ 10 €.

- Plaquette de câblage rapide

- Fils de câblage mâle-mâle (beaucoup)

- Résistances électriques (29 kΩ, soit 27 et 2,2 kΩ en série)

Tous ces petits matériels, qui font partie de l'attirail de l'apprenti maker, peuvent être trouvés facilement chez un revendeur de matériel électronique ou dans des kits d'électronique pour débutant.

La résistance électrique (27 à 30 kΩ environ) est indispensable au fonctionnement.

II - Description des composants et principe de fonctionnement

II-A - Le bargraphe à LED

Le bargraphe comporte 12 segments repérés de A à L. Pour les connexions, il comprend 14 broches numérotées (PIN) 1 à 14 selon la disposition ci-dessous (remarquez le chanfrein en bas à gauche pour s'orienter).

Doc. Luckylight KWL-R1230CDUGB

Doc. Luckylight KWL-R1230CDUGB

À l'intérieur du bargraphe sont en fait agencées 24 LED, chaque segment comportant deux LED, une rouge et une verte :

Doc. Luckylight KWL-R1230CDUGB

Ainsi, chaque segment peut s'illuminer en rouge, vert ou jaune par synthèse additive du rouge et du vert.

Rappel : la LED ( Light-Emitting Diode )

La diode est un dipôle à semi-conducteur (jonction PN). Les deux bornes sont repérées anode A et cathode K. Elle a la propriété d'être conductrice pour un certain sens du courant et non conductrice pour l'autre sens. On peut donc la faire fonctionner en commutation en la faisant passer de l'état passant à l'état bloqué et inversement. Une LED (Light-Emitting Diode, soit diode électroluminescente en français) a la faculté d'émettre une lumière lorsqu'elle est correctement polarisée dans le sens direct (forward), le courant traversant la diode de l'anode vers la cathode comme sur le schéma ci-dessous :

LED 5mm verte, jaune et rouge. La patte la plus courte est la cathode.

LED SMD (Single Mounted Device), composant à monter en surface.

La courbe caractéristique IF = f(VF) a l'allure suivante :

Dans le sens direct, lorsque la tension est en dessous d'une tension de seuil (Forward voltage), aucun courant ne passe. La LED est bloquée et reste éteinte. Lorsque la tension de seuil est atteinte, le courant passe et la LED s'allume.

Si une tension est appliquée dans le sens indirect, la LED n'est plus passante, mais il ne faut pas dépasser une valeur limite (reverse voltage) sous peine de destruction du composant.

Le courant qui traverse la LED ne doit pas dépasser une valeur limite donnée par le constructeur. Dans le cas des LED rouge et verte de notre bargraphe, la valeur continue d'intensité supportable est de 25 mA (100 mA sous certaines conditions où l'alimentation est modulée en largeur d'impulsion) :

Doc. Luckylight KWL-R1230CDUGB

Cet autre tableau ci-dessous donne les valeurs typiques de tension de seuil et de courant :

Doc. Luckylight KWL-R1230CDUGB

Les caractéristiques typiques pour une polarisation correcte des LED rouge et verte sont :

- LED rouge : VF = 1,8 V ; IF = 20 mA

- LED verte : VF = 2,2 V ; IF = 20 mA

Un exercice classique (mais indispensable) pour correctement polariser une LED consiste à déterminer la valeur de la résistance à mettre en série dans le montage ci-dessous :

La loi des mailles donne : Ve = VF + Rp.IF

Si on prend les caractéristiques de la LED rouge du bargraphe alimentée en continu sous Ve = 5 V, on obtient :

Rp = (5 - 1,8) / 20.10-3 = 160 Ω

II-B - Affichage multiplexé

La problématique est fort simple. Soit 24 LED à contrôler individuellement : doit-on passer par 24 sorties de l'Arduino, avec 24 résistances électriques et certainement de quoi amplifier le courant (24 x 20 = 480 mA consommés lorsque toutes les LED sont allumées) ?

Fort heureusement, non, et il existe depuis longtemps un mécanisme de multiplexage(*) permettant d'économiser à la fois l'énergie consommée et le nombre de sorties nécessaires au niveau de la carte Arduino. Nous allons voir également que la constitution de notre bargraphe est prévue pour ce mode de fonctionnement.

(*) Vous trouverez une description accessible du principe de fonctionnement d'un affichage multiplexé sur le site de sonelec-musique.

On remarque les trois cathodes, chacune étant commune à un paquet de huit LED. On remarque aussi que par paquets de trois LED, les anodes sont aussi communes. Par exemple, l'anode de la broche 2 est commune aux trois LED rouges des segments A, E et I, et ainsi de suite. Cet agencement particulier est propice au fonctionnement multiplexé que nous allons décrire sur un exemple appliqué à notre bargraphe.

Par exemple, comment allumer les segments A à J en rouge en mode multiplexé, K et L restant éteints ?

Dans les schémas ci-dessous, les carrés bleus représentent les broches à l'état bas et les carrés rouges, les broches à l'état haut.

Étape 1 : La broche 1 (ou 14) est à l'état bas, les broches 2, 3, 4 et 5 à l'état haut.
Les quatre segments A, B, C et D s'allument en rouge. Les autres segments restent éteints, car les LED sont en configuration non passante.

Étape 2 : La broche 6 (ou 9) est à l'état bas, les broches 2, 3, 4 et 5 à l'état haut.
Les quatre segments E, F, G et H s'allument en rouge. Les autres segments restent éteints, car les LED sont en configuration non passante.

Étape 3 : La broche 7 (ou 8) est à l'état bas, les broches 2 et 3 à l'état haut.
Les deux segments I et J s'allument en rouge. Les autres segments restent éteints, car les LED sont en configuration non passante.

Pour jouer avec la persistance rétinienne et créer l'illusion des segments A à J allumés, il suffit de répéter les étapes 1 à 3 en boucle à une fréquence suffisamment élevée (25 fois par seconde au moins).

Et on fait tourner… Si tous les digits sont parcourus au moins 25 fois par seconde, la persistance rétinienne crée l'illusion des segments A à J allumés.

Si dans le cas d'un montage non multiplexé il fallait 24 sorties de l'Arduino, dans le cas d'un montage multiplexé il ne faut plus que 11 sorties pour piloter les 8 anodes et 3 cathodes. Une autre conséquence intéressante du multiplexage sur la consommation énergétique est que seulement huit LED au maximum seront allumées simultanément.

11 sorties, cela devient jouable même pour l'Arduino UNO. Par contre, au niveau logiciel, il faut prendre en charge toute la gestion du multiplexage.

C'est jouable, mais il y a encore mieux à faire avec un composant spécialisé dans le pilotage de LED (un contrôleur ou driver d'affichage à LED). C'est là qu'intervient le MAX7219 du fabricant de semi-conducteurs Maxim Integrated.

II-C - Le contrôleur d'affichage à LED MAX7219

Doc. Maxim Integrated - MAX7219/MAX7221

Une application typique du MAX7219 est le pilotage d'afficheur à LED, comme celui d'un radio-réveil qui affiche l'heure par exemple.

L'unique résistance électrique entre ISET et V+ permet de régler le courant qui va traverser chaque LED. Les LED rouge et verte de notre bargraphe n'ayant pas les mêmes caractéristiques, le choix doit se porter sur la valeur de la résistance qui minimise le courant, au risque d'abaisser l'intensité lumineuse pour une couleur. Ici, les caractéristiques sont suffisamment proches, et on ne constate aucune dégradation.

Sur le montage ci-dessus, issu de la documentation de Maxim Integrated, on gère l'affichage de 8 chiffres (8 digits), chaque digit étant constitué de 7 segments (SEG A, SEG B, SEG C, … SEG G), plus un point décimal (SEG DP). Soit 64 LED au maximum, et notre bargraphe n'en comporte que 24.

Le MAX7219 est un composant spécialisé qui prend en charge le multiplexage avec une fréquence de 800 Hz environ, largement suffisante pour jouer avec la persistance rétinienne. Chaque sortie DIG 0, DIG 1… du MAX7219 doit être reliée à la cathode commune de chaque digit. Les sorties SEG A, SEG B, … SEG DP sont reliées aux 8 anodes des segments.

Notre bargraphe ne dispose pas de segments agencés géométriquement pour former des chiffres, mais son câblage interne fonctionne sur le même principe qu'un afficheur 7 segments à cathode commune :

Observez la structure interne d'un afficheur standard 7 segments avec 3 digits à cathode commune. Elle est identique à celle de notre bargraphe.

Pour envoyer des informations au MAX7219 et le configurer, l'Arduino et celui-ci doivent s'entendre sur un protocole d'échange de données. Le MAX7219 ne nous laisse pas le choix, c'est le protocole de communication série SPI (Serial Protocol Interface) qui sera employé ici pour écrire dans les registres du MAX7219. Ce protocole standardisé (à peu près) qui permet d'établir une communication de type maître-esclave entre composants est simple à mettre en œuvre, et l'EDI standard Arduino offre une bibliothèque SPI nous évitant les affres du protocole.

III - Préparation du montage

III-A - Schéma de câblage

Voici une vue générale des constituants du système et du câblage.

Attention de bien faire la différence entre la disposition logique des pattes des composants, qui est là pour faciliter la lecture du schéma, et la disposition physique.

Schéma logique

Schéma physique

III-B - Liaison MAX7219 - bargraphe

III-B-1 - Câblage

Les trois broches DIG0, DIG1 et DIG2 du MAX7219 sont reliées aux trois cathodes du bargraphe. Le MAX7219 gère de son côté l'affichage multiplexé en activant à tour de rôle et de façon cyclique chaque digit à une fréquence d'environ 800 Hz.

Pour relier les broches SEGA, SEGB, … SEGDP, nous avons fait un choix.

L'extrait de la documentation du MAX7219 ci-dessous montre la correspondance entre l'état du registre de données 8 bits et celui des LED d'un digit standard 7 segments. En mode No-Decode(1), on peut choisir de mettre un bit Dx à 1 ou à 0 pour allumer ou éteindre individuellement chaque LED du segment correspondant, tout simplement.

Doc. Maxim Integrated - MAX7219/MAX7221

Le câblage choisi devrait faciliter le codage de l'état des LED du bargraphe :

- les bits de poids faible D0 à D3 géreront l'affichage des 4 LED rouges du digit ;

- les bits de poids fort D4 à D7 géreront l'affichage des 4 LED vertes du digit.

III-B-2 - Conséquences sur le codage

Parmi les nombreux registres de configuration du MAX7219, les registres Digit 0, Digit 1, Digit 2… (respectivement aux adresses 0x01, 0x02, 0x03…) contiendront chacun un octet correspondant à l'état des segments du digit considéré.

On déduit, du câblage effectué, quelques exemples sur la façon d'écrire dans les registres du MAX7219, grâce à une fonction writeRegister(adresse, valeur) que nous décrirons au paragraphe suivant :

Premier segment en rouge

Pour le premier digit, bit D0=1 :

writeRegister(DIGIT0, 0x01);
writeRegister(DIGIT1, 0x00);
writeRegister(DIGIT2, 0x00);

Le premier segment de chaque digit en rouge

writeRegister(DIGIT0, 0x01);
writeRegister(DIGIT1, 0x01);
writeRegister(DIGIT2, 0x01);

Les quatre segments du premier digit en rouge

Pour le premier digit, bits D0 à D3 = 1 :

byte allRed = 0x0F;

writeRegister(DIGIT0, allRed);
writeRegister(DIGIT1, 0x00);
writeRegister(DIGIT2, 0x00);

Les quatre segments du premier digit en vert

Pour le premier digit, bits D4 à D7 = 1 :

byte allRed = 0x0F;
byte allGreen = allRed << 4;

writeRegister(DIGIT0, allGreen);
writeRegister(DIGIT1, 0x00);
writeRegister(DIGIT2, 0x00);

Les quatre segments du premier digit en jaune

Pour le premier digit, il faut allumer les LED rouges et vertes, bits D0 à D7 = 1 :

byte allRed = 0x0F;
byte allGreen = allRed << 4;
byte allYellow = allRed | allGreen; // synthèse additive rouge+vert

writeRegister(DIGIT0, allYellow);
writeRegister(DIGIT1, 0x00);
writeRegister(DIGIT2, 0x00);

Comment remplir un digit, segment par segment (scan) ?

Scan trois couleurs

byte red = 0x00,
green = 0x00,
yellow = 0x00;

for (int i = 0; i < 4; i++){
red |= (1 << i);
green = red << 4;
yellow = red | green;
writeRegister(DIGIT0, red); // scan du premier digit en rouge
writeRegister(DIGIT1, green); // scan du deuxième digit en vert
writeRegister(DIGIT2, yellow); // scan du troisième digit en jaune
delay(1000);
}

Référence du langage Arduino

On pourra voir ou revoir les opérateurs bit à bit, en particulier les opérateurs | (OU logique) et << (décalage de bits à gauche).

III-C - Liaison SPI Arduino - MAX7219

SPI est un acronyme pour Serial Peripheral Interface. Il s'agit d'un bus de transmission de données série synchrone, où les données peuvent circuler simultanément dans les deux sens (Full-duplex), contrairement, par exemple, au bus I2C (Inter-Integrated Circuit). Pour permettre la transmission synchrone de données, le bus SPI utilise normalement quatre fils qui sont :

- MOSI - Master out, Slave In : cette ligne transporte les données de l'Arduino vers le ou les périphériques SPI ;

- MISO - Master in, Slave out : cette ligne transporte les données du ou des périphériques SPI vers l'Arduino ;

- SS - Slave select : cette ligne permet de signifier au périphérique connecté sur le bus que nous souhaitons communiquer avec lui. Chaque périphérique SPI sur le bus dispose de sa ligne SS connectée à l'Arduino ;

- SCLK - Serial clock : l'horloge, un signal rectangulaire périodique généré par le périphérique maître qui, justement, cadence les échanges sur les lignes MOSI et MISO.

Liaison SPI : un maître et un esclave - image Wikipédia

Dans ce tutoriel, on considère que la carte Arduino est le périphérique maître (master) et le périphérique SPI tel le MAX7219 est l'esclave (slave). Sur notre carte Arduino/Genuino UNO et cartes compatibles, les connecteurs utilisés sont :

- SS, connecteur D10 : vous pouvez utiliser une autre sortie numérique, mais le connecteur D10 est celui que l'on prend généralement par défaut, comme il est voisin des autres connecteurs utilisés pour la liaison SPI ;

- MOSI, connecteur D11 ;

- MISO, connecteur D12 ;

- SCLK, connecteur D13.

Pour les utilisateurs de l'Arduino Mega, MISO est sur le connecteur D50, MOSI le D51, SCLK le D52 et SS est d'habitude le D53.

- Le connecteur MOSI de l'Arduino doit être relié à la broche IN du MAX7219.

- Le connecteur SCLK de l'Arduino doit être relié à la broche CLK du MAX7219.

- Le connecteur SS de l'Arduino doit être relié à la broche LOAD du MAX7219.

Comme il n'y a pas de retour d'informations de l'esclave (le MAX7219) vers le maître (l'Arduino), le connecteur MISO de l'Arduino n'est pas utilisé.

Liaison SPI entre l'Arduino UNO et le MAX7219 avec 3 fils

Pour plus de détails sur les connecteurs, référez-vous au document SPI library.

Ci-dessous, les déclarations minimales d'usage d'un programme écrit dans l'EDI d'Arduino lorsqu'il s'agit de communiquer via la liaison SPI (voir SPI settings) :

#include <SPI.h>

#define LOAD          10   /* Entrée LOAD du MAX72219 */

void setup() {
pinMode(LOAD, OUTPUT);
digitalWrite(LOAD, HIGH);
SPI.begin();
SPI.setBitOrder(MSBFIRST); /* bits de poids fort en premier /*
}

Les commandes à envoyer au MAX7219 sont des paires d'octets (adresse de registre, valeur) :

Doc. Maxim Integrated - MAX7219/MAX7221

Ci-dessous, la fonction writeRegister utilisée pour écrire dans les registres du MAX7219 :

void writeRegister(byte thisRegister, byte thisValue) // Écrire dans un registre du MAX7219
{
// Mettre l'entrée LOAD à l'état bas
digitalWrite(LOAD, LOW);

SPI.transfer(thisRegister); // Adresse du registre
SPI.transfer(thisValue); // Contenu du registre

// Basculer l'entrée LOAD à l'état haut pour verrouiller et transférer les données
digitalWrite(LOAD, HIGH);
}

Pour communiquer avec un périphérique SPI tel le MAX7219, on met sa broche LOAD à l'état bas (LOW), on échange avec lui, puis on remet sa broche LOAD à l'état haut (HIGH).

III-D - Alimentation du dispositif

Les alimentations sont masquées dans les schémas vus plus haut :

- La broche V+ du MAX7219 doit être reliée au connecteur 5 V de l'Arduino.

- Les deux broches GND (4 et 9) du MAX7219 et un connecteur GND de l'Arduino doivent être reliés (masse commune).

Bien entendu, vous attendrez le dernier moment, quand tout sera préparé et vérifié, avant d'alimenter votre dispositif.

- Pour limiter le courant qui traverse chaque LED, une résistance externe RSET doit être câblée entre les broches V+ et ISET du MAX7219 :

La valeur de cette résistance ne doit rien au hasard, il y va de la protection de votre MAX7219 et du bargraphe. Le constructeur fournit un tableau pour cela :

Doc. Maxim Integrated - MAX7219/MAX7221

On rappelle les caractéristiques des LED rouge et verte du bargraphe :

- LED rouge : VF = 1,8 V ; IF = 20 mA

- LED verte : VF = 2,2 V ; IF = 20 mA

Ce qui nous donne un RSET entre 27 et 29 kΩ. Par sécurité, il faut prendre la plus grande valeur et on obtient de bons résultats en termes de luminosité avec RSET = 29 kΩ (la résistance normalisée supérieure la plus proche étant de 33 kΩ, on associera deux résistances en série de 27 et 2,2 kΩ).

Faisons un bilan du courant total consommé, en se plaçant dans le cas le plus défavorable.

Le courant maximal traversant chaque LED étant fixé grâce à la résistance RSET, et sachant que dans le fonctionnement multiplexé seules huit LED peuvent être allumées simultanément : 8 x 20 = 160 mA, auxquels on rajoute environ 10 mA consommés par le MAX7219, soit environ 170 mA. Si on prend en compte la consommation propre de la carte Arduino, environ 40 mA, l'alimentation générale de votre dispositif doit pouvoir fournir jusqu'à 210 mA pour fonctionner correctement.

En d'autres termes, vous ne risquez rien si vous alimentez votre dispositif avec le port USB de votre PC ou votre portable (courant maxi = 500 mA). Attention toutefois, certains notebooks ont des stratégies de limitation de courant plus sévères sur leur port USB, et il vous faudra passer par un hub USB externe ou par un autre mode d'alimentation.

IV - Les registres du MAX7219

Passons en revue les registres principaux du MAX7219. Pour plus de détails, référez-vous à la datasheet.

Lors de la mise en alimentation, les LED sont toutes éteintes et les registres sont effacés. Le MAX7219 est en mode shutdown.

Adresse

Registre

Description

0x0C

Shutdown

0x00 : shutdown mode
0x01 : normal operation

0x0F

Display-test

Mode Test par défaut avec toutes les LED allumées (0x01). Mettre à 0x00 (normal operation) pour quitter le mode Test.

0x09

Decode-Mode

Comme nous n'avons pas affaire à un afficheur 7 segments (pas de transcodage DCB vers 7 segments), il faut passer en mode no-decode (0x00).

0x0B

Scan limit

Le nombre de digits à prendre en compte pour le multiplexage. Pour notre bargraphe, fixer la valeur à 0x02 (DIG0, DIG1 et DIG2).

0x0A

Intensity

Limiter la luminosité des LED par modulation en largeur d'impulsions. 0x00 à 0x0F pour la luminosité maximale.

0x01

Digit 0

Valeur du premier digit.

…

…

0x08

Digit 7

Valeur du huitième digit.

V - Premiers tests

Un premier programme de test, sans prétention, qui allume trois fois tous les segments selon la séquence : rouge, vert et jaune :

test.ino

#include <SPI.h>

#define LOAD          10   /* Entrée LOAD du MAX72219 */

#define DISPLAY_TEST  0x0F /* Registre Display-Test */
#define SHUTDOWN      0x0C /* Registre Shutdown */
#define DECODE_MODE   0x09 /* Registre Decode-mode */
#define SCAN_LIMIT    0x0B /* Registre Scan-limit */
#define INTENSITY     0x0A /* Registre Intensity */
#define DIGIT0        0x01 /* Registre Digit 0 */
#define DIGIT1        0x02 /* Registre Digit 1 */
#define DIGIT2        0x03 /* Registre Digit 2 */

void setup() {
pinMode(LOAD, OUTPUT);
digitalWrite(LOAD, HIGH);
SPI.begin();
SPI.setBitOrder(MSBFIRST); /* bits de poids fort en premier */

writeRegister(DISPLAY_TEST, 0x00); /* Normal operation */
writeRegister(DECODE_MODE, 0x00);  /* No decode */
writeRegister(SCAN_LIMIT, 0x02);   /* Display digits 0, 1, 2 */
writeRegister(INTENSITY, 0x08);    /* LED brightness, max=0x0F */
writeRegister(SHUTDOWN, 0x01);     /* Normal operation */

test(); /* Lancer le test */

writeRegister(SHUTDOWN, 0x00);  /* Shutdown mode */
}

void test() {
byte allRed = 0x0F;
byte allGreen = allRed << 4;
byte allYellow = allRed | allGreen; /* synthèse additive rouge+vert */

for (int i = 0 ; i < 3 ; i++) {
writeRegister(DIGIT0, allRed);
writeRegister(DIGIT1, allRed);
writeRegister(DIGIT2, allRed);

delay(1000);

writeRegister(DIGIT0, allGreen);
writeRegister(DIGIT1, allGreen);
writeRegister(DIGIT2, allGreen);

delay(1000);

writeRegister(DIGIT0, allYellow);
writeRegister(DIGIT1, allYellow);
writeRegister(DIGIT2, allYellow);

delay(1000);
}
}

void writeRegister(byte thisRegister, byte thisValue) // Écrire dans un registre du MAX7219
{
// Mettre l'entrée LOAD à l'état bas
digitalWrite(LOAD, LOW);

SPI.transfer(thisRegister); // Adresse du registre
SPI.transfer(thisValue); // Contenu du registre

// Basculer l'entrée LOAD à l'état haut pour verrouiller et transférer les données
digitalWrite(LOAD, HIGH);
}

void loop()
{
//
}

VI - Codage de l'état des segments avec un tableau

Le but est d'allumer le bargraphe en décrivant l'état des segments dans un tableau :

enum color_t {NOCOLOR, RED, GREEN, YELLOW};

const byte nb_digits = 3;   /* nombre de digits du bargraph */
const byte nb_segments_digit = 4; /* nombre de segments par digit */

color_t bargraph[nb_digits * nb_segments_digit] = {
GREEN, YELLOW, RED, RED, YELLOW, GREEN,
GREEN, YELLOW, RED, RED, YELLOW, GREEN
};

bargraphDraw(bargraph);

Avec ce tableau, le bargraphe sera dans l'état suivant :

L'état du bargraphe décrit avec un tableau.

Ci-dessous, la fonction bargraphDraw qui va calculer et transférer les valeurs aux registres en fonction du tableau passé en paramètre :

void bargraphDraw(color_t const *mybargraph) {
byte c;
for (byte d = 0; d < nb_digits; d++) { /* pour chaque digit */
c = 0;
for (byte s = 0; s < nb_segments_digit; s++) { /* pour chaque segment du digit */
switch (mybargraph[d * nb_segments_digit + s]) {
case NOCOLOR : break;
case RED : c |= (1 << s); break;
case GREEN : c |= (1 << (s + 4)); break;
case YELLOW :  c |= ((1 << s) | (1 << (s + 4))); break;
default: break;
}
}
writeRegister(d + 1, c);
}
}

Enfin, à titre de démonstration, voici une séquence animée qui fait défiler en boucle une structure en décalant les segments vers la gauche :

demo_tableau.ino

#include <SPI.h>

#define LOAD          10   /* Entrée LOAD du MAX72219 */

#define DISPLAY_TEST  0x0F /* Registre Display-Test */
#define SHUTDOWN      0x0C /* Registre Shutdown */
#define DECODE_MODE   0x09 /* Registre Decode-mode */
#define SCAN_LIMIT    0x0B /* Registre Scan-limit */
#define INTENSITY     0x0A /* Registre Intensity */

enum color_t {NOCOLOR, RED, GREEN, YELLOW};
void bargraphDraw(color_t const *mybargraph);

const byte nb_digits = 3;   /* nombre de digits du bargraph */
const byte nb_segments_digit = 4; /* nombre de segments par digit */

void setup() {
pinMode(LOAD, OUTPUT);
digitalWrite(LOAD, HIGH);
SPI.begin();
SPI.setBitOrder(MSBFIRST); /* bits de poids fort en premier */

writeRegister(DISPLAY_TEST, 0x00); /* Normal operation */
writeRegister(DECODE_MODE, 0x00); /* No decode */
writeRegister(SCAN_LIMIT, nb_digits - 1); /* Display digits 0, 1, 2 */
writeRegister(INTENSITY, 0x08);   /* LED brightness, max=0x0F */
writeRegister(SHUTDOWN, 0x01);    /* Normal operation */

demo();  /* Lancer la démo */

writeRegister(SHUTDOWN, 0x00);  /* Shutdown mode */
}

void demo() {
const byte nb_segments = nb_digits * nb_segments_digit;
color_t bargraph[nb_segments] = {
GREEN, YELLOW, RED, RED, YELLOW, GREEN,
GREEN, YELLOW, RED, RED, YELLOW, GREEN
};

bargraphDraw(bargraph);
delay(1000);

for (int i = 0; i < 10 * nb_segments; i++) {
/* décalage à gauche */
color_t c = bargraph[0];
for (int j = 0; j < nb_segments - 1; j++) {
bargraph[j] = bargraph[j + 1];
}
bargraph[nb_segments - 1] = c;
/* fin décalage à gauche */

bargraphDraw(bargraph);
delay(80);
}

delay(3000);
}

void bargraphDraw(color_t const *mybargraph) {
byte c;
for (byte d = 0; d < nb_digits; d++) { /* pour chaque digit */
c = 0;
for (byte s = 0; s < nb_segments_digit; s++) { /* pour chaque segment du digit */
switch (mybargraph[d * nb_segments_digit + s]) {
case NOCOLOR : break;
case RED : c |= (1 << s); break;
case GREEN : c |= (1 << (s + 4)); break;
case YELLOW :  c |= ((1 << s) | (1 << (s + 4))); break;
default: break;
}
}
writeRegister(d + 1, c);
}
}

void writeRegister(byte thisRegister, byte thisValue) // Écrire dans un registre du MAX7219
{
// Mettre l'entrée LOAD à l'état bas
digitalWrite(LOAD, LOW);

SPI.transfer(thisRegister); // Adresse du registre
SPI.transfer(thisValue); // Contenu du registre

// Basculer l'entrée LOAD à l'état haut pour verrouiller et transférer les données
digitalWrite(LOAD, HIGH);
}

void loop()
{
//
}

VII - Exemple d'application : un indicateur de niveau

Les indicateurs de niveau à LED permettent de rendre compte du niveau de charge d'une batterie, du niveau sonore d'un dispositif audio (VU-mètre), du niveau d'eau d'une citerne ou de carburant d'un réservoir, etc.

Un indicateur de niveau de batterie que l'on trouve dans le commerce.

Pour clore cet article, il ne manquait plus qu'une fonction pour réaliser un indicateur personnalisé. La fonction levelGauge proposée prend en paramètre le niveau à afficher en pourcentage entre 0 % et 100 %. Lorsque le niveau s'approche des 100 %, la couleur tend vers le jaune d'abord, puis le rouge :

Indicateur à 100 %

Syntaxe d'appel :

levelGauge(50); /* niveau=50% */

Ci-dessous un programme de démonstration avec un balayage croissant puis décroissant du niveau entre 0 % et 100 % :

demo_niveau.ino

#include <SPI.h>

#define LOAD          10   /* Entrée LOAD du MAX72219 */

#define DISPLAY_TEST  0x0F /* Registre Display-Test */
#define SHUTDOWN      0x0C /* Registre Shutdown */
#define DECODE_MODE   0x09 /* Registre Decode-mode */
#define SCAN_LIMIT    0x0B /* Registre Scan-limit */
#define INTENSITY     0x0A /* Registre Intensity */

enum color_t {NOCOLOR, RED, GREEN, YELLOW};
void bargraphDraw(color_t const *mybargraph);
void levelGauge(unsigned int percentage);

const byte nb_digits = 3;   /* nombre de digits du bargraph */
const byte nb_segments_digit = 4; /* nombre de segments par digit */

void setup() {
pinMode(LOAD, OUTPUT);
digitalWrite(LOAD, HIGH);
SPI.begin();
SPI.setBitOrder(MSBFIRST); /* bits de poids fort en premier */

writeRegister(DISPLAY_TEST, 0x00); /* Normal operation */
writeRegister(DECODE_MODE, 0x00); /* No decode */
writeRegister(SCAN_LIMIT, nb_digits - 1); /* Display digits 0, 1, 2 */
writeRegister(INTENSITY, 0x08);   /* LED brightness, max=0x0F */
writeRegister(SHUTDOWN, 0x01);    /* Normal operation */

demo();  /* Lancer la démo */

writeRegister(SHUTDOWN, 0x00);  /* Shutdown mode */
}

void demo() {
for (int i = 0; i < 5; i++) {
for (int percent = 0; percent <= 100; percent += 5) {
levelGauge(percent);
delay(20);
}
for (int percent = 100; percent >= 0; percent -= 5) {
levelGauge(percent);
delay(20);
}
}

delay(3000);
}

void bargraphDraw(color_t const *mybargraph) {
byte c;
for (byte d = 0; d < nb_digits; d++) { /* pour chaque digit */
c = 0;
for (byte s = 0; s < nb_segments_digit; s++) { /* pour chaque segment du digit */
switch (mybargraph[d * nb_segments_digit + s]) {
case NOCOLOR : break;
case RED : c |= (1 << s); break;
case GREEN : c |= (1 << (s + 4)); break;
case YELLOW :  c |= ((1 << s) | (1 << (s + 4))); break;
default: break;
}
}
writeRegister(d + 1, c);
}
}

void levelGauge(unsigned int percentage) { /* indicateur de niveau, percentage entre 0 et 100 */
unsigned int level ,
levelRed = nb_digits * nb_segments_digit - 2,
levelYellow = levelRed - 2;

color_t bargraph[nb_digits * nb_segments_digit] = {NOCOLOR}; /* parce que NOCOLOR=0, toutes les autres valeurs non indiquées prendront la valeur 0 */

if (percentage > 100)
return;

if (percentage > 0) {
level = map(percentage, 0, 100, 0, nb_digits * nb_segments_digit - 1);

if (level >= levelRed) { /* niveau dans le rouge */
for (int i = levelRed; i <= level; i++) {
bargraph[i] = RED;
}
}
if (level >= levelYellow) { /* niveau dans le orange */
for (int i = levelYellow; i <= min(level, levelRed - 1); i++) {
bargraph[i] = YELLOW;
}
}
for (int i = 0; i <= min(level, levelYellow - 1); i++) {
bargraph[i] = GREEN;
}
}
bargraphDraw(bargraph);
}

void writeRegister(byte thisRegister, byte thisValue) // Écrire dans un registre du MAX7219
{
// Mettre l'entrée LOAD à l'état bas
digitalWrite(LOAD, LOW);

SPI.transfer(thisRegister); // Adresse du registre
SPI.transfer(thisValue); // Contenu du registre

// Basculer l'entrée LOAD à l'état haut pour verrouiller et transférer les données
digitalWrite(LOAD, HIGH);
}

void loop()
{
//
}

Scan du niveau entre 0 et 100 %

Il ne reste plus qu'à inclure cette fonction dans votre application et de l'adapter à votre convenance.

La fonction map intégrée dans le langage Arduino permet de réétalonner un nombre compris dans une fourchette de valeurs vers une fourchette de destination.

map(value, fromLow, fromHigh, toLow, toHigh)

Ci-dessous une démonstration avec un potentiomètre 10 k sur l'entrée analogique A0 :

Animation en format "youtube" non supportée.
Contenu uniquement consultable en ligne à cette adresse :
https://www.youtube.com/watch?v=whQhr33y4r8

Lecture du port analogique A0

#include <SPI.h>

#define LOAD          10   /* Entrée LOAD du MAX72219 */

#define DISPLAY_TEST  0x0F /* Registre Display-Test */
#define SHUTDOWN      0x0C /* Registre Shutdown */
#define DECODE_MODE   0x09 /* Registre Decode-mode */
#define SCAN_LIMIT    0x0B /* Registre Scan-limit */
#define INTENSITY     0x0A /* Registre Intensity */

#define SENSOR_ANALOG_PIN      A0  /* capteur analogique sur A0 */

enum color_t {NOCOLOR, RED, GREEN, YELLOW};
void bargraphDraw(color_t const *mybargraph);
void levelGauge(unsigned int percentage);

const byte nb_digits = 3;   /* nombre de digits du bargraph */
const byte nb_segments_digit = 4; /* nombre de segments par digit */

void setup() {
pinMode(LOAD, OUTPUT);
digitalWrite(LOAD, HIGH);
SPI.begin();
SPI.setBitOrder(MSBFIRST); /* bits de poids fort en premier */

writeRegister(DISPLAY_TEST, 0x00); /* Normal operation */
writeRegister(DECODE_MODE, 0x00); /* No decode */
writeRegister(SCAN_LIMIT, nb_digits - 1); /* Display digits 0, 1, 2 */
writeRegister(INTENSITY, 0x08);   /* LED brightness, max=0x0F */
writeRegister(SHUTDOWN, 0x01);    /* Normal operation */
}

void loop()
{
unsigned int analogLevel = map(analogRead(SENSOR_ANALOG_PIN), 0, 1023, 0, 100);
levelGauge(analogLevel);
delay(50);
}

void bargraphDraw(color_t const *mybargraph) {
byte c;
for (byte d = 0; d < nb_digits; d++) { /* pour chaque digit */
c = 0;
for (byte s = 0; s < nb_segments_digit; s++) { /* pour chaque segment du digit */
switch (mybargraph[d * nb_segments_digit + s]) {
case NOCOLOR : break;
case RED : c |= (1 << s); break;
case GREEN : c |= (1 << (s + 4)); break;
case YELLOW :  c |= ((1 << s) | (1 << (s + 4))); break;
default: break;
}
}
writeRegister(d + 1, c);
}
}

void levelGauge(unsigned int percentage) { /* indicateur de niveau, percentage entre 0 et 100 */
unsigned int level ,
levelRed = nb_digits * nb_segments_digit - 2,
levelYellow = levelRed - 2;

color_t bargraph[nb_digits * nb_segments_digit] = {NOCOLOR}; /* parce que NOCOLOR=0, toutes les autres valeurs non indiquées prendront la valeur 0 */

if (percentage > 100)
return;

if (percentage > 0) {
level = map(percentage, 0, 100, 0, nb_digits * nb_segments_digit - 1);

if (level >= levelRed) { /* niveau dans le rouge */
for (int i = levelRed; i <= level; i++) {
bargraph[i] = RED;
}
}
if (level >= levelYellow) { /* niveau dans le orange */
for (int i = levelYellow; i <= min(level, levelRed - 1); i++) {
bargraph[i] = YELLOW;
}
}
for (int i = 0; i <= min(level, levelYellow - 1); i++) {
bargraph[i] = GREEN;
}
}
bargraphDraw(bargraph);
}

void writeRegister(byte thisRegister, byte thisValue) // Écrire dans un registre du MAX7219
{
// Mettre l'entrée LOAD à l'état bas
digitalWrite(LOAD, LOW);

SPI.transfer(thisRegister); // Adresse du registre
SPI.transfer(thisValue); // Contenu du registre

// Basculer l'entrée LOAD à l'état haut pour verrouiller et transférer les données
digitalWrite(LOAD, HIGH);
}

Défi

Le capteur à ultrasons SRF-05 est très répandu en petite robotique. Il fonctionne comme un sonar et permet de mesurer la distance d'un obstacle devant lui. En prime, il s'interface facilement avec l'Arduino.

Pour plus de détails sur le fonctionnement et la programmation de ce capteur, je vous renvoie à ce tutoriel.

Le défi consiste à reprendre le principe de l'indicateur de niveau vu précédemment pour informer visuellement de la proximité d'un obstacle.

Voici une vidéo du résultat attendu :

Animation en format "youtube" non supportée.
Contenu uniquement consultable en ligne à cette adresse :
https://www.youtube.com/watch?v=_ZRUBF4duzk

Vous avez tous les éléments pour relever le défi, à vous de jouer !

Proposition de code à adapter

#include <SPI.h>

#define LOAD          10   /* Entrée LOAD du MAX72219 */

#define DISPLAY_TEST  0x0F /* Registre Display-Test */
#define SHUTDOWN      0x0C /* Registre Shutdown */
#define DECODE_MODE   0x09 /* Registre Decode-mode */
#define SCAN_LIMIT    0x0B /* Registre Scan-limit */
#define INTENSITY     0x0A /* Registre Intensity */

#define ECHO_PIN      6  /* broche ECHO du SRF05 sur D6 */
#define TRIGGER_PIN   7  /* broche TRIGGER du SRF05 sur D7 */

enum color_t {NOCOLOR, RED, GREEN, YELLOW};
void bargraphDraw(color_t const *mybargraph);
void levelGauge(unsigned int percentage);

const byte nb_digits = 3;   /* nombre de digits du bargraph */
const byte nb_segments_digit = 4; /* nombre de segments par digit */

const unsigned int rangeSensor = 20; /* portée de mesure du capteur = 20cm */

void setup() {
pinMode(LOAD, OUTPUT);
digitalWrite(LOAD, HIGH);
SPI.begin();
SPI.setBitOrder(MSBFIRST); /* bits de poids fort en premier */

pinMode(ECHO_PIN, INPUT);     /* la broche ECHO de la carte est une entrée numérique */
pinMode(TRIGGER_PIN, OUTPUT); /* la broche TRIGGER de la carte est une sortie numérique */

writeRegister(DISPLAY_TEST, 0x00); /* Normal operation */
writeRegister(DECODE_MODE, 0x00); /* No decode */
writeRegister(SCAN_LIMIT, nb_digits - 1); /* Display digits 0, 1, 2 */
writeRegister(INTENSITY, 0x08);   /* LED brightness, max=0x0F */
writeRegister(SHUTDOWN, 0x01);    /* Normal operation */
}

void loop()
{
/* déclenchement de la mesure */
digitalWrite(TRIGGER_PIN, HIGH);    /* signal TRIGGER à l'état HAUT (5V)*/
delayMicroseconds(12);              /* durée de l'état haut = 12 microsecondes */
digitalWrite(TRIGGER_PIN, LOW);     /* signal TRIGGER à l'état BAS (0V) */

// lecture de la broche ECHO
unsigned long echoPulseTime = pulseIn(ECHO_PIN, HIGH);    /* attend le retour du signal ECHO au niveau BAS et retourne la durée du signal */
unsigned int distance = echoPulseTime / 58 ;  /* On divise par 58 pour avoir une distance en cm. */
unsigned int levelDistance = 0 ;

if (distance <= rangeSensor) { /* distance inférieure à la portée de mesure */
/* calcul du niveau de l'indicateur en pourcentage : 2cm=100%, rangeSensor=0% */
levelDistance = 100 - map(distance, 2, rangeSensor, 0, 100);
}

levelGauge(levelDistance);

delay(50);
}

void bargraphDraw(color_t const *mybargraph) {
byte c;
for (byte d = 0; d < nb_digits; d++) { /* pour chaque digit */
c = 0;
for (byte s = 0; s < nb_segments_digit; s++) { /* pour chaque segment du digit */
switch (mybargraph[d * nb_segments_digit + s]) {
case NOCOLOR : break;
case RED : c |= (1 << s); break;
case GREEN : c |= (1 << (s + 4)); break;
case YELLOW :  c |= ((1 << s) | (1 << (s + 4))); break;
default: break;
}
}
writeRegister(d + 1, c);
}
}

void levelGauge(unsigned int percentage) { /* indicateur de niveau, percentage entre 0 et 100 */
unsigned int level ,
levelRed = nb_digits * nb_segments_digit - 2,
levelYellow = levelRed - 2;

color_t bargraph[nb_digits * nb_segments_digit] = {NOCOLOR}; /* parce que NOCOLOR=0, toutes les autres valeurs non indiquées prendront la valeur 0 */

if (percentage > 100)
return;

if (percentage > 0) {
level = map(percentage, 0, 100, 0, nb_digits * nb_segments_digit - 1);

if (level >= levelRed) { /* niveau dans le rouge */
for (int i = levelRed; i <= level; i++) {
bargraph[i] = RED;
}
}
if (level >= levelYellow) { /* niveau dans le orange */
for (int i = levelYellow; i <= min(level, levelRed - 1); i++) {
bargraph[i] = YELLOW;
}
}
for (int i = 0; i <= min(level, levelYellow - 1); i++) {
bargraph[i] = GREEN;
}
}
bargraphDraw(bargraph);
}

void writeRegister(byte thisRegister, byte thisValue) // Écrire dans un registre du MAX7219
{
// Mettre l'entrée LOAD à l'état bas
digitalWrite(LOAD, LOW);

SPI.transfer(thisRegister); // Adresse du registre
SPI.transfer(thisValue); // Contenu du registre

// Basculer l'entrée LOAD à l'état haut pour verrouiller et transférer les données
digitalWrite(LOAD, HIGH);
}

VIII - Et avec DEUX bargraphes !

À dire vrai, un MAX7219 devient intéressant lorsque vous avez beaucoup de LED à piloter. Le MAX7219 peut gérer jusqu'à 8 digits x 8 segments = 64 LED. Notre bargraphe n'en comportant que 24, on peut très bien accoler un deuxième bargraphe et donner l'illusion d'un bargraphe unique à 2 x 12 = 24 segments.

Deux bargraphes, côte à côte

L'opération n'est pas bien compliquée avec un peu de rigueur, car votre plaque de câblage va commencer à ressembler à un plat de nouilles…

Il suffit de relier les cathodes du deuxième bargraphe aux broches DIG3, DIG4 et DIG5 du MAX7219, et à relier les anodes des segments SEG A, SEG B, … SEG DP entre elles en suivant le schéma ci-dessous :

Deux bargraphes chaînés

Au niveau de la programmation, il suffit d'étendre la commande aux trois digits supplémentaires DIG3, DIG4 et DIG5. C'est tout…

IX - Conclusion

Dans ce tutoriel, nous avons vu comment piloter un bargraphe à LED grâce au principe du multiplexage et à l'aide d'un composant spécialisé. Ce driver de LED communique avec l'Arduino grâce à une liaison SPI, un protocole de communication série répandu à l'instar du protocole I^2C, et qui ne consommera que trois connecteurs de votre carte Arduino. En suivant ces mêmes principes, vous êtes à même de piloter d'autres dispositifs à LED : afficheur 7 segments, matrice ou cube de LED.

Lumières d'ambiance avec un cube de LED piloté par Arduino et MAX7219, d'après JolliCube - an 8x8x8 LED Cube (SPI) - instructables.com

Il est à noter qu'il existe bien d'autres moyens pour piloter quantité de LED : d'autres drivers spécialisés comme le Holtek HT16K33 qui fonctionne avec une liaison I^2C, ou avec des composants plus généralistes comme les très répandus registres à décalage. Le MAX7219 présente des avantages : peu de composants supplémentaires (ici, une seule résistance), et pas de gestion du multiplexage à programmer, puisque le MAX7219 s'en charge tout seul.

Pour aller plus loin, vous pourriez passer à un prototype durable en soudant vos composants (le MAX7219 sera inséré dans un support standard 28 broches, et c'est le support qui sera soudé), fils de câblage, capteurs et connecteurs sur une plaque veroboard et construire un shield personnalisé, que vous pourriez exploiter pour fabriquer un indicateur de niveau fonctionnel et autonome.

Mais l'essentiel reste d'avoir pu progresser dans la pratique de l'électronique numérique et des microcontrôleurs, le tout dans la philosophie Do It Yourself qui a motivé ce tutoriel.

Je remercie Auteur et Winjerome pour leur aide précieuse dans la rédaction de cet article, ainsi que Claude LELOUP pour ses corrections orthographiques.

X - Sitographie

- Documentation constructeur (datasheet)

- 12 Segment Light Bar Displays - Technical Data Sheet

- Bi-Color (Red/Green) 12-LED Bargraph - Pack of 2 - Adafruit PRODUCT ID : 1719

- Maxim Integrated MAX7219 Datasheet

- Le multiplexage

- Sonelec-musique.com - Affichage et multiplexage

- MAX7219/7221 - Playground Arduino

- The MAX7219 and MAX7221 Led drivers

- Controlling a Led matrix or 7-segments displays with the MAX7219 or MAX7221

- LedControl : a Arduino Library for the MAX7221 and MAX7219

- La liaison SPI

- Serial Peripheral Interface

- Tutorial : Arduino and the SPI bus

- Arduino SPI Library

(1)Dans l'autre mode Code B, un décodeur DCB-7 segments est activé. On envoie dans le registre le chiffre à afficher en binaire naturel codé sur 4 bits, et le décodeur fera la correspondance pour activer les segments qui réaliseront le dessin du chiffre.