Un montage électronique à base de microcontrôleur peut  piloter plusieurs types d’actionneurs : des relais, des électrovannes, des moteurs, ou encore des dispositifs de puissance.  Tous ces dispositifs qui exécutent des tâches bien précises sont connectés sur les sorties. 

Dans le cas de la carte Arduino Uno, on a 14 Entrées/Sorties numériques et 6 Entrées/Sorties analogiques, qui peuvent aussi être exploitées comme des Entrées/Sorties numériques, ce qui en fait 20 en tout. Ce nombre peut devenir insuffisant si, pour le projet on a besoin de plus.

Cet article a pour but de présenter l'utilisation du registre à décalage le 74HC595, afin d’augmenter le nombre de sorties, d'une carte Arduino Uno.

 

Dans cet article on verra:

> La présentation du composant;

> Le schéma du montage qui servira de test;

> Un programme utilisé pour le montage test;

> Les résultats de la simulation;

> Une amélioration possible utilisant le 74HC165 avec le 74HC595;

> Un exemple d'utilisation possible des deux composants précédents;

> Puis, un mot pour finir.

 

Présentation :

Le 74HC595 est un registre à décalage à entrée série (SER), et 8 sorties parallèles trois états. Les sorties des registres qui effectuent la fonction "décalage" alimentent à leur tour 8 registres  de mémorisation, dont le rôle est d'éviter que l'information ne soit perdue; chaque groupe de registres ayant sa propre horloge (SRCLK et RCLK); d'autre part ce composant possède une entrée de remise à zéro des sorties (/SRCLR); une sortie de mise en cascade QH’; et une broche nommée /OE. Lorsque /OE est à l’état haut, toutes les sorties sont dans un état haute impédance.

 

Schéma fonctionnel :

 

Diagramme logic 74hc595
Extrait de la documentation technique de Texas Instruments

 

Chronnogrammes:

 

chronnogrammes 74hc595
Extrait de la documentation technique de Texas Instruments

 

On suppose qu’un signal d’horloge permanent est appliqué sur l’entrée SRCLK ; un état logique haut  présent sur l’entrée SER, est mémorisé sur la sortie QA lors d’un front montant de l’impulsion d’horloge RCLK, à condition que /SRCLR soit à l’état haut et /OE à l’état bas. Au prochain front montant, la sortie QB prend l’état précédent de QA, le cycle se poursuit vers les autres sorties tant que les fronts d’horloge sont présents sur RCLK.  Un état haut sur /OE fait passer toutes les sorties vers un état haute impédance.

 

Schéma du montage:

Pour mettre en oeuvre le registre à décalage, on va s'inspirer du schéma d'application proposé par Texas Instruments dans sa documentation technique:

 

Schema test 74hc595ti 1
Modifié à partir de la documentation technique de Texas Instruments

 

A ceci près que c'est la carte Arduino Uno qui servira de contrôleur, et les résistances seront modifiées; ayant à disposition des résistances de 330 Ohms, celles-ci peuvent aussi convenir. La broche /SRCLR sera reliée à +5 Volts, et la broche /OE à la masse.

Après modifications, le schéma a été saisi dans Proteus; les labels des broches du 74HC595 sont différents de ceux utilisés par Texas Instruments; mais les fonctions ne changent pas.

 

Schema test 74hc595 

 

Programmation:

On peiut gérer ce registre à décalage en utlisant la librairie SPI d'Arduino. Mais pour notre exemple on va utiliser la fonction prédéfinie shiftOut(), ainsi le choix des broches sur Arduino est moins restrictif. Pour mettre en oeuvre le 74HC595 on aura besoin des signaux suivants:

                      > SER:  données série en entrée,

                      > SRCLK: horloge des régistres internes à décalages,

                      > RCLK: horloge des bascules à mémoires internes.

 

SER sera relié la broche 11 de l'Arduino;

SRCLK à 12 de l'Arduino, c'est la broche qui sert d'horloge;

puis RCLK à 10, cette broche permet d'activer la mémorisation dans les régistres internes du 74HC595.

Pour avoir plus d'informations sur la fonction shiftOut() il faudra se reférer au site arduinocc.

 

Dans le programme proposé ci-après; les instructions d'initialisation contenues dans setup() consistent à définir le rôle des broches de la carte Arduino qui vont servir à piloter le 74HC595. Dans loop(), on va afficher en boucle, tous les nombres de 0 à 255; les valeurs binaires seront représentées par les 8 diodes LEDs; c'est la fonction shiftOut(), de la librairie Arduino qui se charge de cette opération. Une temporisation de 500ms a été rajoutée à la fin de la boucle, afin de bien observer les changements sur les sorties.

 

/* Main.ino file generated by New Project wizard
 *
 * Created:   Thu Dec 23 2021
 * Processor: ATmega328P
 * Compiler:  Arduino AVR
 */
const int clockPin = 12;
const int ledData = 11;
const int ledLatchPin = 10; void setup() { pinMode(ledLatchPin, OUTPUT); pinMode(clockPin, OUTPUT); pinMode(ledData, OUTPUT); } void loop() { for (int valToDisplay = 0; valToDisplay < 256; valToDisplay++) { digitalWrite(ledLatchPin, LOW); shiftOut(ledData, clockPin, MSBFIRST, valToDisplay); digitalWrite(ledLatchPin, HIGH); delay(500); } }

 

Simulation:

Le programme précédent a été copié et collé dans l'environnement Proteus VSM. La capture d'écran ci-après illustre le résultat obtenu lors de la simulation:

 

test 74hc595 2

 

Améliorations:

Le 74HC595 possède une broche de sortie série pour une mise en cascade, ce qui permettrai d'augmenter le nombre de sorties d'un montage, si on ajoute un composant supplémentaire, voire plus.

Orientons nous vers une autre voie pour proposer une application mettant en oeuvre le 74HC595 et le 74HC165 déjà présenté dans un autre article de ce site. On disposera ainsi des entrées et des sorties suplémentaires pour la carte Arduino Uno.

 

La figure ci-après propose le shéma du montage réalisé sous Proteus:

 

schema test 74hc165 et 74hc595

 

Programmation:

Pour la démonstration, tout appui sur un bouton poussoir connecté sur une entrée du 74HC165, sera traduit par l'allumage d'une LED branchée sur le 74HC595. Les connexions du programme précédent restent inchangées pour le 74HC595. La broche 9 de l'Arduino sera reliée à la broche 1 du 74HC165. La broche 2 du 74HC165 sera reliée à la broche 12 de la carte Arduino, et la broche 9 du 74HC165 sera reliée à la broche 8 de la carte Arduino.

L'état des boutons poussoir est lu par la fonction read_shift_register(), c'est en fait un copié coller du programme de test du 74HC165 déjà présenté dans un autre article de ce site. Cet état est stocké dans la variable pinValues;  et envoyée au 74HC595 grâce à la fonction prédéfinie shiftOut() de la librairie Arduino. 

 

/* Main.ino file generated by New Project wizard
 *
 * Created:   Thu Dec 23 2021
 * Processor: ATmega328P
 * Compiler:  Arduino AVR
 */
/* Main.ino file generated by New Project wizard
 *
 * Created:   Thu Dec 23 2021
 * Processor: ATmega328P
 * Compiler:  Arduino AVR
 */
const int clockPin = 12;
const int ledData = 11;
const int ledLatchPin = 10;
const int buttonLoad = 9;
const int buttonData = 8;
unsigned int pinValues;

byte buttonVal;

void setup()
{
    Serial.begin(9600);
    pinMode(ledLatchPin, OUTPUT);
    pinMode(clockPin, OUTPUT);
    pinMode(ledData, OUTPUT);  
    pinMode(buttonLoad, OUTPUT);
    pinMode(buttonData, INPUT);
    
}

void loop()
{
    
      
      pinValues = read_shift_register();
      
        digitalWrite(ledLatchPin, LOW);
        shiftOut(ledData, clockPin, LSBFIRST, ~pinValues);
        digitalWrite(ledLatchPin, HIGH);
      
     delay(30);
}

//
unsigned int read_shift_register()
{
    int bitVal;
    unsigned int octetRead = 0;
    digitalWrite (buttonLoad, LOW);
    delayMicroseconds(5);
    digitalWrite (buttonLoad, HIGH);
    delayMicroseconds(5);

    for(int i = 0; i < 8; i++)
    {
        bitVal = digitalRead(buttonData);
        octetRead |= (bitVal << (7 - i));

        digitalWrite(clockPin, HIGH);
        delayMicroseconds(5);
        digitalWrite(clockPin, LOW);
    }
    return(octetRead);
}

 

Simulation et test du montage:

Le montage a été réalisé simulé dans Proteus VSM, on obtient les résultats attendus.  A l'issue de cette phase de simulation, s'en est suivi une phase de mise en oeuvre physique pour les tests.

Nous avons opté pour une réalisation sur plaque à essais; 8 boutons poussoirs connectés sur les entrées du 74HC165, et 8 LEDs munies de résistances de 330 Ohms branchées sur les sorties du 74HC595. Le résultat de ce test est proposé par la vidéo ci-après:

 

 

Autre amélioration possible:

Ce serait plutôt intéressant de d'utiliser ce montage comme une petit système de pilotage de jeux lumières commandés par des boutons poussoirs. Pour simuler ce fonctionnement, on va garder en lieu et place les diodes LEDs, ainsi que les boutons poussoirs et les deux circuits intégrés, le 74HC165 et 74HC595.

Le montage ne change pas. Ce n'est que le programme qui devra subir quelques retouches.

Le programme modifié:

Pour le programme on a rajouté un tableau qui contiendra les combinaisons de LEDs allumées  ou éteintes.  Ainsi, selon les cas on pourra allumer certaines LEDs et éteindre les autres. Les différents cas de figures à prendre en compte dépendent de la variable pinValues. Par exemple si appuie sur le premier bouton poussoir, la combinaison logique correspondante sera 11111110 (les boutons poussoir étant reliés à +5V par des résistances de pull-up); ce qui vaut 254. Pour les huits boutons poussoirs suivants on aura respectivement: 253, 251, 247, 239, 233, 191, et 127.

La fonction shiftOut() enverra les valeurs du tableau vers le 74HC595.

Exemple de programme:

/* Main.ino file generated by New Project wizard
 *
 * Created:   Thu Dec 23 2021
 * Processor: ATmega328P
 * Compiler:  Arduino AVR
 */
/* Main.ino file generated by New Project wizard
 *
 * Created:   Thu Dec 23 2021
 * Processor: ATmega328P
 * Compiler:  Arduino AVR
 */
const int clockPin = 12;
const int ledData = 11;
const int ledLatchPin = 10;
const int buttonLoad = 9;
const int buttonData = 8;
int pinValues;
int ledToDisplay[8];

byte buttonVal;

void setup()
{
    
    pinMode(ledLatchPin, OUTPUT);
    pinMode(clockPin, OUTPUT);
    pinMode(ledData, OUTPUT);  
    pinMode(buttonLoad, OUTPUT);
    pinMode(buttonData, INPUT);
    
}

void loop()
{
    
      
      pinValues = read_shift_register();

      switch (pinValues)
      {
        case 254:
         ledToDisplay[0] = 0b10000000;
         ledToDisplay[1] = 0b11000000;
         ledToDisplay[2] = 0b01100000;
         ledToDisplay[3] = 0b00110000;
         ledToDisplay[4] = 0b00011000;
         ledToDisplay[5] = 0b00001100;
         ledToDisplay[6] = 0b00000110;
         ledToDisplay[7] = 0b00000011;
        break;
        
        case 253:
         ledToDisplay[0] = 0b10000001;
         ledToDisplay[1] = 0b11000011;
         ledToDisplay[2] = 0b11100111;
         ledToDisplay[3] = 0b11111111;
         ledToDisplay[4] = 0b11100111;
         ledToDisplay[5] = 0b11000011;
         ledToDisplay[6] = 0b10000001;
         ledToDisplay[7] = 0b00000000;
        break;
        
        case 251:
         ledToDisplay[0] = 0b10000000;
         ledToDisplay[1] = 0b01000000;
         ledToDisplay[2] = 0b00100000;
         ledToDisplay[3] = 0b00010000;
         ledToDisplay[4] = 0b00001000;
         ledToDisplay[5] = 0b00000100;
         ledToDisplay[6] = 0b00000010;
         ledToDisplay[7] = 0b00000001;
        break;
        
        case 247:
         ledToDisplay[0] = 0b00000001;
         ledToDisplay[1] = 0b00000010;
         ledToDisplay[2] = 0b00000100;
         ledToDisplay[3] = 0b00001000;
         ledToDisplay[4] = 0b00010000;
         ledToDisplay[5] = 0b00100000;
         ledToDisplay[6] = 0b01000000;
         ledToDisplay[7] = 0b10000000;
        break;
        
        case 239:
         ledToDisplay[0] = 0b00011000;
         ledToDisplay[1] = 0b00111100;
         ledToDisplay[2] = 0b01111110;
         ledToDisplay[3] = 0b11111111;
         ledToDisplay[4] = 0b01111110;
         ledToDisplay[5] = 0b00111100;
         ledToDisplay[6] = 0b00011000;
         ledToDisplay[7] = 0b00010000;
        break;
        
        case 223:
         ledToDisplay[0] = 0b11111111;
         ledToDisplay[1] = 0b00000000;
         ledToDisplay[2] = 0b11111111;
         ledToDisplay[3] = 0b00000000;
         ledToDisplay[4] = 0b11111111;
         ledToDisplay[5] = 0b00000000;
         ledToDisplay[6] = 0b11111111;
         ledToDisplay[7] = 0b00000000;
        break;
        
        case 191:
         ledToDisplay[0] = 0b10000001;
         ledToDisplay[1] = 0b01000010;
         ledToDisplay[2] = 0b00100100;
         ledToDisplay[3] = 0b00011000;
         ledToDisplay[4] = 0b00101000;
         ledToDisplay[5] = 0b01000100;
         ledToDisplay[6] = 0b01000010;
         ledToDisplay[7] = 0b10000001;
        break;
        
        case 127:
         ledToDisplay[0] = 0b11111111;
         ledToDisplay[1] = 0b11110111;
         ledToDisplay[2] = 0b11100111;
         ledToDisplay[3] = 0b11000011;
         ledToDisplay[4] = 0b10000001;
         ledToDisplay[5] = 0b00000000;
         ledToDisplay[6] = 0b00011000;
         ledToDisplay[7] = 0b00111100;
        break;
        
        default:

        break;
         
      }
      for (int i=0; i < 8; i++)
      {
        digitalWrite(ledLatchPin, LOW);
        shiftOut(ledData, clockPin, LSBFIRST, ledToDisplay[i]);
        digitalWrite(ledLatchPin, HIGH);
        delay(125);
      }
     
}

//
unsigned int read_shift_register()
{
    int bitVal;
    unsigned int octetRead = 0;
    digitalWrite (buttonLoad, LOW);
    delayMicroseconds(5);
    digitalWrite (buttonLoad, HIGH);
    delayMicroseconds(5);

    for(int i = 0; i < 8; i++)
    {
        bitVal = digitalRead(buttonData);
        octetRead |= (bitVal << (7 - i));

        digitalWrite(clockPin, HIGH);
        delayMicroseconds(5);
        digitalWrite(clockPin, LOW);
    }
    return(octetRead);
}

Test et vidéo de fonctionnement du montage :

 

 

Pour finir:

A travers les exemples proposés dans cet article, avec la carte Arduino Uno, nous venons de montrer qu'il est possible d'utiliser deux circuits intégrés à bas coûts; le 74HC595 et le 74HC165, pour augmenter le nombre d'entrées-sorties numériques d'un microcontrôleur.