Afficheur à LED 7 segments (classe SegmentLedDisplay)


Les afficheurs LED 7 segments permettent d'afficher des chiffres. Cet article présente les différents aspect de ce composant en commençant par le câblage pour terminer par la programmation.
Un afficheur LED est en fait un réseau de LED, une par segment, chacune des LED étant pilotée par une broche. Il existe plusieurs sortes d'afficheurs. Certains ont une anode commune. Les LEDs sont alors contrôlées par leur cathode. Pour d'autres, c'est la cathode qui est commune. Dans ce cas, les LEDs sont contrôlées par leur anode. Aussi, il est très important de vérifier sur la fiche technique dans quel sens doit être effectué le câblage en polarisation directe.
Dans c'est article, le composant utilisé est un afficheur 5161AS qui est utilisé. Pour ce composant, c'est la cathode qui est commune.

Câblage d'un afficheur LED à 7 segments

Brochage de l'afficheur 5161AS

Dans la figure ci-contre présente le brochage de l'afficheur 5161DS. Ce qui est résumé dans le tableau ci-dessous :
NomDescription
1eSegment E.
2dSegment D.
3GNDCathode commune.
4cSegment C.
5DPPoint DP (la huitième diode du réseau).
6bSegment B
7aSegment A.
8GNDCathode commune.
9fSegment F.
10gSegment G.
L'affichage des chiffres se fait en activant les segments adéquats. Le tableau ci-dessous indique, pour chaque chiffre hexadécimal, les segment à activer :
ChiffreSegment :ABCDEFG
01111110
1
0110000
2
1101101
3
1111001
4
0110011
5
1011011
6
1011111
7
1110000
8
1111111
9
1111011
A
1110111
B
0011111
C
1001110
D
0111101
E
1001111
F
1000111

Câblage de l'afficheur 5161AS directement sur l'Arduino

La façon la plus simple pour utiliser un afficheur à LED c'est de connecter les anodes directement sur les pins de l'Arduino, comme si c'étaient de simples LED, les deux cathodes étant reliées sur GND en passant par une résistance de protection de 220 Ohms.
Le problème de ce montage est qu'il mobilise 8 pins de l'Arduino pour une simple fonction d'affichage. Ce qui n'est pas vraiment optimal, le nombre de pins de sortie de l'Arduino étant limité. C'est pourquoi, l'usage le plus courant passe par l'utilisation d'un convertisseur Série/Parallèle 74HC595, qui permet, pour un coût modique, d'étendre le nombre de sorties. 

Câblage de l'afficheur 5161AS avec un 74HC595

Comme déjà vu dans un précédent article, le 74HC595 est un convertisseur Série/Parallèle qui, à partir de trois entrées Série, offre huit sorties parallèles. En connectant les huit anodes de l'afficheur LED sur les huit sorties du 74HC595, on ne mobilise que 3 pins sur l'Arduino au lieu de 8.
Le schéma est alors le suivant :

Les connexions entre le 74H595 avec l'Arduino sont celles habituelles :
  • Les broches VCC et MR du 74HC595 sont connectées à l'alimentation +5V de l'Arduino.
  • Les broches OE et GND du 74HC595 sont connectées à la masse GND de l'Arduino.
  • La broche DS (Data) du 74HC595 est connectée sur la pin D2 de l'Arduino.
  • La broche ST_CP (Latch) du 74HC595 est connectée sur la pin D3 de l'Arduino.
  • La broche SH_CP (Clock) du 74HC595 est connectée sur la pin D4 de l'Arduino.
Les connexions entre l'afficheur LED et le 74HC595 sont les suivantes :
  • Les deux broches GND de cathodes communes de l'afficher LED sont connectées à la broche GND du 74HC595 (et donc à la masse de l'Arduino).
  • Les huit broches d'anode A à G et DP de l'afficheur LED sont respectivement connectées aux huit broches de sortie Q0 à Q7 du 74HC595.
Ces connexions peuvent être effectuées sur une platine d'expérimentation comme le montre la figure ci-dessous :

Définition de la classe SegmentLedDisplay

La classe SegmentLedDisplay permet de programmer facilement l'affichage d'un chiffre décimal ou hexadécimal sur un afficheur LED à 7 segments. La définition de cette classe se trouve dans le fichier SegmentLedDisplay.h qui doit être inclus par tous les projets dans lequel ce composant est utilisé.
Cette classe utilise le composant IC74hc595.
/ * 1 */
#ifndef SegmentLedDisplay_h
#define SegmentLedDisplay_h

/ * 2 */
#include "Component.h"
#include "IC74hc595.h"

/ * 3 */
class SegmentLedDisplay : Component {
/ * 4 */
  IC74hc595 __IC74hc595;
/ * 5 */
  byte __segments;
/ * 6 */
  static byte DIGITS[16];

  public:
/ * 7 */
  SegmentLedDisplay(uint8_t, uint8_t, uint8_t);
/ * 8 */
  void begin();
  void loop() { }
/ * 9 */
  void displayDigit(uint8_t);
  void setDot(bool);
  void clear();
};

/ * 1 */
#endif // SegmentLedDisplay_h
  1. Application de la bonne pratique qui consiste à définir les classes d'une bibliothèque entre deux directives #ifndef et #endif afin de prévenir la définition multiple de la même classe dans des projets composites.
  2. Inclusion des définitions des classes utilisées par la classe SegmentLedDisplay par des directives #include :
    • Comme toutes les classes relatives à des composants électroniques, la classe SegmentLedDisplay implémente l'interface Component dont la définition se trouve dans Component.h.
    • La classe SegmentLedDisplay utilise la classe IC74hc595 relative au circuit de conversion Série/Parallèle 74HC595 dont la définition se trouve dans IC74hc595.h
  3. La classe SegmentLedDisplay implémente l'interface Component. Ce qui l'oblige à implémenter les méthodes membres begin() et loop().
  4. L'afficheur à LED est connecté à un 74HC595. Sa programmation utilise nécessairement la classe IC74hc595. Une instance de cette classe __IC74hc595 est déclarée comme attribut privé. Les invocations de la classe SegmentLedDisplay seront interprétées et transformées en invocations de l'instance __IC74hc595.
  5. Certaines instructions permettent de ne modifier qu'un segment de l'afficheur. Comme l'affichage passe par une transmission Série de tous les bits relatifs aux segments, l'état respectif de ceux-ci est mémorisé dans l'attribut  privé __segments.
  6. Le tableau DIGIT est déclaré en constante de classe static. Il contient la définition, pour chaque chiffre hexadécimal, des segments de l'afficheur qui doivent être activés. C'est en fait la traduction en C++ du tableau présenté plus haut.
  7. Le constructeur de la classe SegmentLedDisplay reçoit trois paramètres correspondant aux pins du 74HC595 Data, Latch et Clock mobilisées sur l'Arduino. Celles-ci sont transmises au constructeur de l'instance __IC74hc595.
  8. La classe SegmentLedDisplay  implémentant l'interface Component, elle doit implémenter les méthodes begin() et loop(). La méthode begin() doit être invoquée soit dans la fonction setup() du sketch Arduino,soit dans la méthode begin() du composite utilisant l'afficheur LED. Dans la classe SegmentLedDisplay, la méthode loop() ne fait rien. Elle est implémentée vide dans la définition.
  9. La classe SegmentLedDisplay expose trois méthodes publiques pour gérer l'affichage :
    • diplayDigit() affiche le chiffre passé en paramètre.
    • setDot() modifie la LED DP (le point en bas à droite de l'afficheur). Si le paramètre est true, la LED DP s'allume. L'état des autres LED de l'afficheur n'est pas modifié par cette méthode.
    • clear() éteint toutes les LEDs de l'afficheur, y compris la LED DP.

Implémentation de la classe SegmentLedDisplay

Implémentation du tableau DIGITS.

Le tableau DIGITS est un tableau de 16 entiers non signés de type byte (sur 8 bits). Ces trains de bits sont transmis en Série au 74HC595 qui position ses sorties parallèles pour activer les segments indiqué, chaque position de bit correspondant à un segment LED de l'afficheur. Le bit de poids le plus fort est toujours à 0 car 7 segments suffisent pour afficher un chiffre. Le huitième bit est néanmoins utilisable car il correspond à la pin DP de l'afficheur (la LED du point en bas à droite de l'afficheur). Le bit de poids le plu faible (celui le plus à droite) correspond à la LED a
byte SegmentLedDisplay::DIGITS[16] = {
  B00111111,  // 0
  B00000110,  // 1
  B01011011,  // 2
  B01001111,  // 3
  B01100110,  // 4
  B01101101,  // 5
  B01111101,  // 6
  B00000111,  // 7
  B01111111,  // 8
  B01101111,  // 9
  B01110111,  // A
  B01111100,  // B
  B00111001,  // C
  B01011110,  // D
  B01111001,  // E
  B01110001   // F
};

Constructeur de la classe SegmentLedDisplay

Le circuit 74HC595 mobilise trois pins de l'Arduino. Les numéros de ces trois pins sont passés en paramètre du constructeur de la classe SegmentLedDisplay. Ces trois paramètres sont transmis au constructeur de l'instance __IC74hc595.
  • dataPin est le numéro de la pin de l'Arduino utilisée pour le flux de données. Cette pin doit être reliée à la pin DS (n°14) du 74HC595. 
  • latchPin est le numéro de la pin de l'Arduino  utilisée pour valider le flux de données. Cette pin doit être reliée à la pin ST_CP (n°12) du 74HC595.
  • clockPin est le numéro de la pin de l'Arduino  utilisée pour valider le flux de données. Cette pin doit être reliée à la pin SH_CP (n°11) du 74HC595.
SegmentLedDisplay::SegmentLedDisplay(uint8_t dataPin, uint8_t latchPin, uint8_t clockPin)
  : __IC74hc595(dataPin, latchPin, clockPin)
{  }
  • Le trois numéros de pins, reçus en paramètres, sont transmis au constructeur de l'instance __IC74hc595.

Méthode begin()

La méthode begin() est héritée de l'interface Component qui définit un polymorphisme sur tous les composants C++ en les obligeant à implémenter les méthodes begin() et loop(). Cette méthode doit être invoquée soit dans la méthode setup() du sketch Arduino, soit dans la méthode begin() des composites qui utilisent ce composant.
void SegmentLedDisplay::begin() {
  this->__IC74hc595.begin();
}
  • Cette méthode d'un objet composite doit invoquer la méthode begin() de ses composant. Dans le cas de la classe SegmentLedDisplay, elle invoque la méthode begin() de l'instance __IC74hc595 pour initialiser le 74HC595.

Méthode publique displayDigit()

La méthode displayDigit() affiche le chiffre dont la valeur digit est passée en paramètre. En principe, digit doit avoir une valeur de 0 à 15. Cependant comme le paramètre digit est passé sur 8 bits, celui-ci est tronqué sur 4 bits pour ne pas provoquer  une erreur de dépassement sur la table DIGITS dont la taille est limitée à 16.
void SegmentLedDisplay::displayDigit(uint8_t digit) {
  this->__segments = (this->__segments & 0x80) + DIGITS[digit & 0x0F];
  this->__IC74hc595.write(this->__segments);
}
  • Les 7 bits de poids faible de l'attribut __segments, qui correspondent aux 7 segments d'affichage des chiffres, sont d'abord sont positionnés à 0 pour préserver l'état de la LED DP correspondant au bit de poids fort.
  • digit, tronqué sur les quatre bits de poids le plus faible, correspond à l'index du trains de bits à transmettre via le 74HC595,  dans le tableau DIGITS
  • Le train de bit extrait du tableau DIGITS est ajouté à l'attribut __segments
  • La méthode write() est invoquée sur l'instance __IC74hc595 pour transmettre le train de bits contenu dans __segments via le 74HC595.
  • A la fin, l'attribut __segments contient l'état des 8 LEDs de l'afficheur, l'état de la LED DP n'ayant pas été modifié par cette méthode.

Méthode publique setDot()

La méthode setDot() permet de modifier l'état de la diode DP (le point situé en bas à droite de l'afficheur) sans modifier l'état des autres LEDs. Si le paramètre passé vaut true, le point s'allume.
void SegmentLedDisplay::setDot(bool dotDisplayed) {
  this->__segments = (this->__segments & 0x7F) | (dotDisplayed ? 0x80 : 0);
  this->__IC74hc595.write(this->__segments);
}
  • Les 7 bits de poids faible de l'attribut __segments sont sauvegardés pour préserver l'affichage du chiffre en cours.
  • Le huitième bit est position à 1 ou à 0 en fonction du paramètre dotDisplayed.
  • La méthode write() est invoquée sur l'instance __IC74hc595 pour transmettre le train de bits contenu dans __segments via le 74HC595. Car, même si un seul bit est modifié, la transmission en Série du 74HC595 nécessite de passer le train de 8 bits complet.
  • A la fin, l'attribut __segments contient l'état à jour des 8 LEDs de l'afficheur.

Méthode publique clear()

La méthode clear() éteint toutes les LEDs de l'afficheur en transmettant un train de 8 bits à 0.
void SegmentLedDisplay::clear() {
  this->__segments = 0;
  this->__IC74hc595.write(this->__segments);
}
  • L'attribut __segment est mis à 0.
  • La méthode write() est invoquée sur l'instance __IC74hc595 pour transmettre le train des 8 bits à 0 contenus dans __segments via le 74HC595. 
  • A la fin, toutes les sorties du 74HC595 sont à 0. Donc l'afficheur est éteint. 

Utilisation de la classe SegmentLedDisplay dans un sketch Arduino

L'utilisation de la classe SegmentLedDisplay dans un sketch Arduino s'effectue comme pour tous les autres composants présentés sur ce blog. Dans l'exemple ci-dessous, les quinze chiffres hexadécimaux sont affichés successivement en boucle toutes les secondes, pendant que le point clignote :
/* 1 *
#define IC_DATA 2
#define IC_LATCH 3
#define IC_CLOCK 4

/* 2 */
#include "SegmentLedDisplay.h"

/* 3 */
SegmentLedDisplay ledDisplay(IC_DATA, IC_LATCH, IC_CLOCK);

/* 4 */
uint32_t millis0;
uint8_t digit;
bool dot;

/* 5 */
void setup() {
  ledDisplay.begin();
  millis0 = 0;
  digit = 0;
  dot = false;
  ledDisplay.clear();
}

/* 6 */
void loop() {
  uint32_t now = millis();
  if ((now - millis0) > 500) {
    if (dot) {
      ledDisplay.displayDigit(digit);
      digit++;
    }
    ledDisplay.setDot(dot);
    dot = !dot;
    millis0 = now;
  }
}
  1. Il est d'une bonne pratique que de déclarer en constantes les numéros de pins utilisées tant sur l'Arduino que sur le circuit 74HC595 :
    • IC_DATA est le numéro de pin de l'Arduino sur laquelle est connectée la pin Data du 74HC595.
    • IC_LATCH est le numéro de pin de l'Arduino sur laquelle est connectée la pin Latch du 74HC595.
    • IC_CLOCK est le numéro de pin de l'Arduino sur laquelle est connectée la pin Clock du 74HC595.
  2. Le sketch utilisant la classe SegmentLedDisplay, la définition de celle-ci doit être incluse par une directive #include
  3. La classe SegmentLedDisplay est instanciée par la variable ledDisplay à laquelle on passe les numéros de pins sur lequel est connecté le 74HC595 dans l'ordre exigé par le constructeur.
  4. Trois variables de travail sont déclarées :
    • millis0 est l'origine des temps utilisée pour rythmer le fonctionnement de la fonction loop().
    • digit est le chiffre qui doit être affiché  sur l'afficheur LED.
    • dot est un booléen pour gérer le clignotement du point.
  5. L'instance ledDisplay est initialisée dans la méthode setup() en invoquant sur celle-ci la méthode bégin(). Les trois variables de travail et l'instance ledDisplay sont initialisées respectivement :
    • millis0 est initialisée à 0.
    • digit est initialisée à 0.
    • dot est initialisée à false.
    • L'afficheur est réinitialisé à 0 (toutes LEDs éteintes), en invoquant la méthode clear() sur l'instance ledDisplay au cas où il y aurait un reliquat indésirable de l'état des pins de sortie du 74HC595. 
  6. La fonction loop() fonctionne comme ceci. Pour chaque itération :
    • Le temps est lu par la méthode millis() et affecté à la variable locale now
    • La fonction loop() est rythmée sur un cycle de 500ms. S'il s'est déroulé plus 500 ms depuis la dernière modification de millis0,
      • Tous les deux cycles, 
        • Le chiffre digit est affiché en invoquant la méthode displayDigit() sur l'instance ledDisplay
        • le chiffre digit est incrémenté après affichage. Comme, la méthode displayDigit() tronque le paramètre  sur 4 bits, il n'est pas nécessaire de vérifier si la limite de 15 et dépassée.
      • L'état du point DP est inversé et affiché en invoquant la méthode setDot(). Le point clignote toutes les 500 ms alors que l'affichage du chiffre change toutes les secondes.
      • millis0 prend alors la valeur de now.

Conclusion

Les afficheurs sont très gourmand en pins de pilotage. L'usage de convertisseur Série/Parallèle 74HC595 est donc préconisé.
La classe SegmentLedDisplay qui permet de piloter un afficheur LED en C++ est un bon exemple de composite utilisant la classe IC74hc595 qui pilote le convertisseur. Il peut être utilisé comme modèle pour tout projet consommateur de nombreuses pins de sortie.

Commentaires

Posts les plus consultés de ce blog

Piloter un clavier matriciel sur le bus I2C avec un PCF8574

Piloter un écran LCD sur le bus I2C de l'Arduino avec un PCF8574