8-bit shift register 74HC595, Connecté en série
Do not index
Do not index
Hide CTA
Hide CTA
Video preview

Objectifs

Cette vidéo est la seconde couvrante le PIC 74HC595 afin cette fois de montrer l’usage du port Q7S du shift register et vous permettre l’usage de ce contrôleur en série et démultiplier les ports digitaux de votre Arduino ou autre micro contrôleur en cas de besoin.

Affichage 7 segments

Afin de se démarquer du précédent montage, au lieu de 8 LED, nous avons cette fois un affichage 7 segments. C’est au final exactement la même chose, juste en plus fancy ! Forgez 8 LEDs dans un bout de plastic, et vous terminez avec un affichage 7 segments avec son point. Voyez plutôt le schéma technique suivant :
notion image
Sur la partie droite, notez la représentation schématique des deux types d’affichage : Cathode commune en haut, Anode commune pour le bas.

Premier montage électronique

L’objectif ici est de vous permettre de raccorder correctement le premier shift register à un affichage 7 segments. Si vous venez du précédent article, cela représentera une simple mise à jour par remplacement des 8 LEDs.
notion image
Si vous avez raccordé l’affichage selon un ordre différent, il pourra alors être utile de vous demander dans quel ordre insérer les bits dans le shift register avant d’aller à l’étape précédente.
Dans le code source suivant, les deux boucles ne diffère que par l’ordre dans lequel est utilisée la fonction SHIFTOUT(). MSBFIRST OU LSBFIRST ? À vous de le déduire en faisant tourner ce programme et en comparant ce qu’affiche la led témoin arduino et l’affichage digital. Si votre affichage des chiffres lorsque la led est allumée, vous êtes en mode LSBFIRST.
#define PIN_DS_DATA 4
#define PIN_STCP_LATCH 5
#define PIN_SHCP_CLOCK 6

//Valeur décimales qui représentées en binaire permettent 
//d'allumer les led correspondantes aux chiffres de 0 à 9
byte numbers[10] = {238, 40, 205, 109, 43, 103, 231, 44, 239, 111};

void setup() {
   //On définie les 3 ports en mode OUTPUT
  pinMode(PIN_STCP_LATCH, OUTPUT);
  pinMode(PIN_SHCP_CLOCK, OUTPUT);
  pinMode(PIN_DS_DATA, OUTPUT);

  //On setup et initialise la led intégré à la carte qui servira de temoin
  pinMode(LED_BUILTIN, OUTPUT);

}

void loop() {

  //On allume la led integrée == LSBFIRST
  digitalWrite(LED_BUILTIN, HIGH);

  //On execute une boucle de 10 tours pour visiter les 10 chiffres de 0 à 9
  for (byte i = 0; i < 10; i++) {
    //On s'assure que la gachette est a l'etat LOW
    digitalWrite(PIN_STCP_LATCH, LOW);
    
    //On utlise la fonction shiftOut de la librairie 
    //arduino pour lui soumettre la valeur à transmettre au registre
    shiftOut(PIN_DS_DATA, PIN_SHCP_CLOCK, LSBFIRST, numbers[i]);
    
    //On inverse l'etat de la gachette pour mettre à jour le registre
    digitalWrite(PIN_STCP_LATCH, HIGH);
    
    //Un delais d'une demi seconde avant le prochain tour de boucle
    delay(500);
  }

  //On allume la led integrée == MSBFIRST
  digitalWrite(LED_BUILTIN, LOW);

  //On execute une boucle de 10 tours pour visiter les 10 chiffres de 0 à 9 
  for (byte i = 0; i < 10; i++) {
    //On s'assure que la gachette est a l'etat LOW
    digitalWrite(PIN_STCP_LATCH, LOW);
    
    //On utlise la fonction shiftOut de la librairie 
    //arduino pour lui soumettre la valeur à transmettre au registre
    shiftOut(PIN_DS_DATA, PIN_SHCP_CLOCK, MSBFIRST, numbers[i]);
    
    //On inverse l'etat de la gachette pour mettre à jour le registre
    digitalWrite(PIN_STCP_LATCH, HIGH);
    
    //Un delais d'une demi seconde avant le prochain tour de boucle
    delay(500);
  }
}

Description du port Q7S du shift register

Le port Q7S va agir de comme un port de débordement : tous les bits qui doivent être détruit du registre par écrasement de nouvelles données, va d’abord être une dernière fois émis sur le port Q7S avant d’être définitivement supprimé.
Ainsi, connecter le port Q7S d’un shift register au port DS du shift register suivant permet de sérialiser les contrôleurs ensemble.
notion image
Afin de mettre à jour tous les shift register au même moment, il conviendra alors de mettre la gâchette à l’état bas, envoyer un octet par affichage présent dans le circuit, et renvoyer un coup de gâchette à l’état haut. Voici une rapide démonstration qui envoie le même octet deux fois d’affiler dans le but de mettre en œuvre le principe de débordement.
#define PIN_DS_DATA 4
#define PIN_STCP_LATCH 5
#define PIN_SHCP_CLOCK 6

//Valeur décimales qui représentées en binaire permettent 
//d'allumer les led correspondantes aux chiffres de 0 à 9
byte numbers[10] = {238, 40, 205, 109, 43, 103, 231, 44, 239, 111};

void setup() {
   //On définie les 3 ports en mode OUTPUT
  pinMode(PIN_STCP_LATCH, OUTPUT);
  pinMode(PIN_SHCP_CLOCK, OUTPUT);
  pinMode(PIN_DS_DATA, OUTPUT);

}

void loop() {

  //On execute une boucle de 10 tours pour visiter les 10 chiffres de 0 à 9
  for (byte i = 0; i < 10; i++) {

    //On s'assure que la gachette est a l'etat LOW
    digitalWrite(PIN_STCP_LATCH, LOW);
    
    //On utlise la fonction shiftOut de la librairie 
    //arduino pour lui soumettre la valeur à transmettre au registre
    //Cette fois ci on envoie deux fois le meme nombre pour mettre en evidence le concept de débordement
    shiftOut(PIN_DS_DATA, PIN_SHCP_CLOCK, MSBFIRST, numbers[i]);
    shiftOut(PIN_DS_DATA, PIN_SHCP_CLOCK, MSBFIRST, numbers[i]);

    //On inverse l'etat de la gachette pour mettre à jour le registre
    digitalWrite(PIN_STCP_LATCH, HIGH);
    
    //Un delais d'une demi seconde avant le prochain tour de boucle
    delay(500);
  }

}
 

Second montage électronique

notion image
Le premier shift register se raccorde sans changement par rapport a un raccordement habituel. Le second, quant à lui, vient connecter sa gâchette et son horloge directement en parallèle au premier shift, puis cette fois, vient connecter son port DS (data) au port Q7S du shift précédent.
Aussi, comme vous pouvez le constater, mais si du côté contrôleur, on est parfaitement dans le bon ordre (Q7 → Q0 en ordre décroissant), cela n’est pas du tout le cas coté afficheur.
Ainsi, j’ai voulu automatiser le calcul des nombres requis à envoyer au shift pour que celui-ci nous affiche un digit compris entre 0 et 9. Vous pouvez retrouver le fichier excel ici
notion image
Si on envoie à l’aide de la fonction ShiftOut() d’arduino les nombres en colonne R, devrai s’afficher le digit correspondant de la colonne H sur l’afficheur digital 7 segments.
C’est au travers de cette méthode que j’ai pu initialiser la variable des codes sources vu précédemment :
byte numbers[10] = {238, 40, 205, 109, 43, 103, 231, 44, 239, 111};

Usage des 2 affichages digitaux

Dans le dernier exemple, deux fonctions font leur apparition. L’une permet de décomposer un nombre entier en un tableau de chiffres séparés. La seconde, permet la rapide mise à jour des shift register sur le circuit. Plusieurs opportunités d’aller plus loin sont présentées en commentaire en bas de code. Si vous souhaitez de l’entrainement pour comprendre les classes et rendre le shift register plus facile d’usage.
#include <math.h>
#define PIN_DS_DATA 4
#define PIN_STCP_LATCH 5
#define PIN_SHCP_CLOCK 6

#define NUMBER_OF_DISPLAY 2

//Valeur décimales qui représentées en binaire permettent 
//d'allumer les led correspondantes aux chiffres de 0 à 9
byte numbers[10] = {238, 40, 205, 109, 43, 103, 231, 44, 239, 111};



//Fonction qui convertie un entier en un tableau de nombre correspondant au different nombre de la variable numbers
byte* convert_number_to_array(int to_convert){
  //Initialise un tableau qui va stocker les differents nombres
  static byte to_display[NUMBER_OF_DISPLAY];

  //Commence la decoupe du nombre
  int rest = to_convert;

  //Boucle sur chaque digit du nombre a decouper
  for(byte i = 0; i < NUMBER_OF_DISPLAY; i++){
    //Recupere le digit en cours, et stocke le reste pour le prochain tour de boucle
    int digit = rest / pow(10, ((NUMBER_OF_DISPLAY - 1) - i));
    rest = fmod(rest , pow(10, ((NUMBER_OF_DISPLAY - 1) - i)));
    to_display[i] = numbers[digit];
  }
  return to_display;
}


void update_shift(byte* to_display){
  //On s'assure que la gachette est a l'etat LOW
  digitalWrite(PIN_STCP_LATCH, LOW);
  //Serial.println(to_display[0]);
  //Serial.println(to_display[1]);
  //On boucle sur tableau donné QUI DOIT ETRE DE TAILLE = NUMBER_OF_DISPLAY 
  //Si vous donné un tableau trop petit, erreur de type : index out of range
  //Si vous donné un tableau trop grand, la lecture sera tronqué à la taille de NUMBER_OF_DISPLAY
  //Dans la mesure du possible, toujours evité l'allocation dynamique de memoire sur une bestiole comme Arduino
  for (byte display_index = 0; display_index < NUMBER_OF_DISPLAY; display_index++) {
    shiftOut(PIN_DS_DATA, PIN_SHCP_CLOCK, MSBFIRST, to_display[display_index]);
  }

  //On inverse l'etat de la gachette pour mettre à jour le registre
  digitalWrite(PIN_STCP_LATCH, HIGH);
}

void setup() {
   //On définie les 3 ports en mode OUTPUT
  pinMode(PIN_STCP_LATCH, OUTPUT);
  pinMode(PIN_SHCP_CLOCK, OUTPUT);
  pinMode(PIN_DS_DATA, OUTPUT);
}

void loop() {
  // On genere 1 tableau qui est le resultat de la fonction convert_number_to_array
  byte* nombre_1 = convert_number_to_array(42);

  // On envoie le tableau fraichement generé à la fonction update_shift pour qu'elle mette à jour tout les shifts déclarés
  update_shift(nombre_1);

  // On attend une tite seconde
  delay(1000);

  // On reproduit l'opération ci dessus plus rapidement de 0 à 100
  byte* nombre_dynamique;
  for (byte j = 0; j < 100; j++){
    nombre_dynamique = convert_number_to_array(j);
    update_shift(nombre_dynamique);
    delay(100);
  }
  
  byte clear[2] = {0, 0};
  update_shift(clear);
  delay(3000);

}

/* 

Des pistes à explorer pour aller plus loin :

- Fabriquer les classes ShiftRegister, et ShiftRegisterManager pour permettre une gestion aisée et dynamique des shift register
- Implementer une fonction qui permet d'exploiter le point
- Si votre classe permet de stoker les etats individuels des shift register, vous pouvez ajouter une fonctionalité qui 
  permettrait d'editer un display de maniere individuelle sans toucher aux autres.


*/

Le code source est aussi disponible sur Github.

 
Cyril

Written by

Cyril

Hobbyiste en électronique, programmation et IA