Shift register

De The Linux Craftsman
Aller à la navigation Aller à la recherche

Introduction

Le registre à décalage permet de contrôler, avec seulement 3 entrées digitales d'un microcontrôleur, un nombre beaucoup plus grand (8,16,24,etc...) d'entrées / sorties. Le registre à décalage que nous allons utiliser et le 74HC595 de chez Texas Instrument.

SN74HC595.jpg

Diagramme

Voici le diagramme du 74HC595 ainsi que l'explication du rôle de chacune de ces broches

Diagramme broche nom fonction
74HC595 diagram.png
Q0 à Q7 Parallel data output Sorties pilotables du registre
GND Masse 0V
VCC Positif 7V max
DS Data serial Donnée d'entrée du registre
Niveau haut pour un 1 et bas pour un 0
OE Output Enable Active Q0 à Q7 sur niveau bas (0V)
On relie généralement cette broche au niveau bas (GND) pour activer les sorties de manière permanente
STCP Storage Clock Pin Lorsque cette broche est à un niveau haut, le registre est basculé en mémoire
La bascule permet de positionner et mémoriser l'état des broches Q0 à Q7
SHCP Shift Clock Pin Lorsque la broche est à un état haut, l'état de la broche DS est basculé dans le registre
MR Master Reset Vide la mémoire du registre sur niveau bas (0V)
On relie généralement cette broche au niveau haut (VCC) pour éviter une remise à zéro permanente
Q7S Sortie série Permet de chainer un autre registre à décalage

Fonctionnement

Le registre 74HC595 fonctionne sur 8 bits et pour comprendre son fonctionnement on va faire l'analogie avec un tableau de booléen. Chaque casse du tableau correspond à une broche de sortie (Q0 à Q7). Si la case contient la valeur false la broche est à un état bas (GND) et, si la casse contient true la broche est à un état haut (VCC). Les valeur de ce tableau se positionnent les unes après les autres, chaque nouvelle valeur décalant la précédente d'une case.

Au départ le registre est à zéro :

Q0

Q1

Q2

Q3

Q4

Q5

Q6

Q7

0

0

0

0

0

0

0

0

Lorsque l'on insère un 1, celui-ci prend la place Q0 en décalant tous les autre bit de une case :

Q0

Q1

Q2

Q3

Q4

Q5

Q6

Q7

1

0

0

0

0

0

0

0

Si on insère maintenant un 0, celui-ci prend la place Q0 en décalant tous les autre bit de une case :

Q0

Q1

Q2

Q3

Q4

Q5

Q6

Q7

0

1

0

0

0

0

0

0

On peut continuer notre exemple en insérant maintenant les bits suivants 1, 1, 0, 0, 1 puis 1 :

Q0

Q1

Q2

Q3

Q4

Q5

Q6

Q7

1

1

0

0

1

1

0

1

Concrètement voici un résumé des étapes :

  1. positionnement de la broche STCP à un état bas (GND) pour désactiver la recopie ;
  2. positionnement de la broche SHCP à un état bas (GND) ;
  3. positionnement de la broche DS à un état bas (0) ou haut (1) ;
  4. positionnement de la broche SHCP à un état haut (VCC) pour enregistrer le bit dans le registre et décaler les autres ;
  5. positionnement de la broche STCP à un état haut (VCC) pour recopier l'état du registre en mémoire et positionner les broches Q0 à Q7 en conscéquence ;

Les étapes 2 à 4 peuvent être répétées 8 fois pour positionner les 8 bits du registre. Si plusieurs registres sont chaînés, répéter ces étapes 8 x N, N étant le nombre de registre.

Chaînage

Il est possible de chaîner plusieurs registres à la suite en reliant la broche Q7S du registre précédent avec la broche DS du registre suivant. La particularité de la broche Q7S est de prendre l'état du bit sortant du registre permettant ainsi de l'injecter dans l'entrée du registre suivant.

On peut reprendre notre exemple en insérant maintenant un 0 :

Q0

Q1

Q2

Q3

Q4

Q5

Q6

Q7

Q7S

0

1

1

0

0

1

1

0

1

La séquence est décalée d'une case poussant l'ancienne valeur de Q7 (1) en dehors du registre sur la broche Q7S.

Chained shift registers.png

Exemples d'utilisation

Warning manual.jpg

Soyez sûr de comprendre la section sur comment écrire un sketch avant de poursuivre. Le code ci-dessous fait référence à des parties bien spécifiques, détaillées et expliquées dans la section suscitée.

Pilotage de 16 sorties

Dans cette exemple nous allons utiliser deux registres à décalages avec un ESP8266 conjointement avec des leds et des résistances.

Définition des broches en fonction d'un tableau de booléens

Dans un premier temps nous allons définir les broches utilisées, dans la partie des variables statiques ajoutez les lignes suivantes :

// Définition des broches utilisées
const uint8_t DS_PIN = D5;
const uint8_t STCP_PIN = D6;
const uint8_t SHCP_PIN = D7;
// Taille du registre, ici deux registres de 8 bits
const uint8_t REGISTER_SIZE = 16;
// Tableau d'états des broches
bool states[REGISTER_SIZE] = {false};

Dans la fonction setup() on positionne les broches en sortie et on bascule les registres à un état bas:

void setup(){
	// Positionnement des broches
	pinMode(DS_PIN, OUTPUT);
	pinMode(STCP_PIN, OUTPUT);
	pinMode(SHCP_PIN, OUTPUT);
	// Basculement des registres
	shiftRegister();
}

void loop(){
}

Voici le code de la fonction shiftRegister() qui va permettre de positionner l'état des registres en fonction du tableau de booléens:

void shiftRegister(){
	// Désactivation la recopie
	digitalWrite(STCP_PIN, LOW);
	for(uint8_t i = REGISTER_SIZE; i > 0; i--){
		// Horloge registre à l'état bas
		digitalWrite(SHCP_PIN, LOW);
		// Ecriture d'un état du registre
		digitalWrite(DS_PIN, states[i-1]);
		// Enregistrement de l'état dans le registre
		digitalWrite(SHCP_PIN, HIGH);
	}
	// Active la recopie et bascule le registre en mémoire
	digitalWrite(STCP_PIN, HIGH);
}

Bascule des registres

Bascule des registres

Pour l'instant se code ne fait pas grand chose, mais pour modifier l'état des registre il suffit de modifier l'état du tableau et d'appeler la fonction shiftRegister(). Testons avec la fonction suivante:

void shifting_direct() {
  static uint8_t pin = 0;
  if (pin > 0 ) {
    states[pin - 1] = false;
  }
  if (pin == REGISTER_SIZE) {
    // RAZ de i
    pin = 0;
  }
  states[pin++] = true;
  shiftRegister();
  delay(100);
}

Il suffit d'appeler shifting_direct() dans la fonction loop() pour obtenir le résultat suivant :

Shiting register direct.gif

On peut également le faire dans l'autre sens :

void shifting_reverse() {
  static int8_t pin = REGISTER_SIZE - 1;
  if (pin < REGISTER_SIZE - 1) {
    states[pin + 1] = false;
  }
  if (pin < 0) {
    // RAZ de i
    pin = REGISTER_SIZE - 1;
  }
  states[pin--] = true;
  shiftRegister();
  delay(100);
}

Il suffit d'appeler shifting_reverse() dans la fonction loop() pour obtenir le résultat suivant :

Shiting register reverse.gif

On peut même introduire une persistance :

void shifting_persistance() {
  static int8_t pin = 0;
  static bool direction = true;
  if (pin == -1) {
    pin++;
    direction = true;
  }else if(pin == REGISTER_SIZE){
    pin--;
    direction = false;
  }else if(direction){
    states[pin++] = true;
  }else{
    states[pin--] = false;
  }
  shiftRegister();
  delay(100);
}

Il suffit d'appeler shifting_persistance() dans la fonction loop() pour obtenir le résultat suivant :

Shiting register persistance.gif

Pour finir, on peut simplement tout allumer ou tout éteindre :

void shiftAll(bool state){
  for(uint8_t i = 0; i < REGISTER_SIZE; i++){
    states[i] = state;
  }
  shiftRegister();
}

Pilotage de 8 entrées

Dans cet exemple, nous allons utiliser le registre à décalage pour détecter un appuis sur des boutons.