[ Arduino annexe A ] Ajouter des sorties numériques à l’Arduino, le 74HC595

Dans ce chapitre « bonus », nous allons vous faire découvrir comment ajouter des sorties numériques à votre carte Arduino. Car en effet, pour vos projets les plus fous, vous serez certainement amené à avoir besoin d’un grand nombre de sorties. Là il y a deux choix : le premier serait d’opter pour une carte Arduino qui dispose de plus de sorties, telle que la Arduino Mega ; mais dans le cas où vous aurez besoin d’un giga super ultra grand nombre de sorties, même la Mega ne suffira pas. Le deuxième choix c’est donc… de lire ce chapitre. 🙄
Ce que vous allez découvrir se révélera fort utile, soyez-en certains.
Prenons l’exemple suivant : dans le cas où vous devrez gérer un grand nombre de LED pour réaliser un afficheur comme l’on en trouve parfois dans les vitrines de magasins, vous serez très vite limité par le nombre de sorties de votre Arduino. Surtout si votre afficheur contient plus de 1000 LED ! Ce chapitre va alors vous aider dans de pareils cas, car nous allons vous présenter un composant spécialisé dans ce domaine : le 74HC595.

Présentation du 74HC595

Principe

Comme je viens de l’énoncer, il peut arriver qu’il vous faille utiliser plus de broches qu’il n’en existe sur un micro-contrôleur, votre carte Arduino en l’occurrence (ou plutôt, l’ATMEGA328 présent sur votre carte Arduino). Dans cette idée, des ingénieurs ont développé un composant que l’on pourrait qualifier de « décodeur série -> parallèle ». D’une manière assez simple, cela consiste à envoyer un octet de données (8 bits) à ce composant qui va alors décoder l’information reçue et changer l’état de chacune de ses sorties en conséquence. Le composant que nous avons choisi de vous faire utiliser dispose de huit sorties de données pour une seule entrée de données. Concrètement, cela signifie que lorsque l’on enverra l’octet suivant : 00011000 au décodeur 74HC595, il va changer l’état (HAUT ou BAS) de ses sorties. On verra alors, en supposant qu’il y a une LED de connectée sur chacune de ses sorties, les 2 LED du « milieu » (géographiquement parlant) qui seront dans un état opposé de leurs congénères. Ainsi, en utilisant seulement deux sorties de votre carte Arduino, on peut virtuellement en utiliser 8 (voir beaucoup plus mais nous verrons cela plus tard).

Le composant

Rentrons maintenant dans les entrailles de ce fameux 595. Pour cela nous utiliserons cette datasheet tout au long du tuto.

Brochage

Lisons ensemble quelques pages. La première nous donne, de par le titre, la fonctionnalité du composant. Elle est importante car l’on sait à ce moment à quel composant nous allons avoir affaire. La seconde apporte déjà quelques informations utiles outre la fonctionnalité. Au-delà du résumé qu’il est toujours bon de lire, les caractéristiques du composant sont détaillées. On apprend également que ce composant peut fonctionner jusqu’à une fréquence de 170MHz. C’est très très rapide par rapport à notre carte Arduino qui tourne à 16MHz, nous sommes tranquilles de ce côté-là. Continuons… C’est la page 4 qui nous intéresse vraiment ici. On y retrouve le tableau et la figure suivante :

Brochage du 74HC595

Avec ce dernier, on va pouvoir faire le lien entre le nom de chaque broche et leur rôle. De plus, nous savons où elles sont placées sur le composant. Nous avons donc les sorties et la masse à gauche et les broches de commande à droite (plus la sortie Q0) et l’alimentation. Voyons maintenant comment faire fonctionner tout cela.

Fonctionnement

Comme tout composant électronique, il faut commencer par l’alimenter pour le faire fonctionner. Le tableau que nous avons vu juste au-dessus nous indique que les broches d’alimentation sont la broche 16 (VCC) et la broche 8 (masse). Quelques pages plus loin dans la datasheet, page 7 précisément, nous voyons la tension à appliquer pour l’alimenter : entre 2V et 5.5V (et idéalement 5.0V).
Une fois que ce dernier est alimenté, il faut se renseigner sur le rôle des broches pour savoir comment l’utiliser correctement. Pour cela il faut revenir sur le tableau précédent et la table de vérité qui le suit. On découvre donc que les sorties sont les broches de 1 à 7 et la broche 15 (Qn) ; l’entrée des données série, qui va commander les sorties du composant, se trouve sur la broche 14 (serial data input) ; une sortie particulière est disponible sur la broche 9 (serial data output, nous y reviendrons à la fin de ce chapitre). Sur la broche 10 on trouve le Master Reset, pour mettre à zéro toutes les sorties. Elle est active à l’état BAS. Vous ferez alors attention, dans le cas où vous utiliseriez cette sortie, de la forcer à un état logique HAUT, en la reliant par exemple au +5V ou bien à une broche de l’Arduino que vous ne mettrez à l’état BAS que lorsque vous voudrez mettre toutes les sorties du 74HC595 à l’état bas. Nous, nous mettrons cette sortie sur le +5V.
La broche 13, output enable input, est un broche de sélection qui permet d’inhiber les sorties. En clair, cela signifie que lorsque cette broche n’a pas l’état logique requis, les sorties du 74HC595 ne seront pas utilisables. Soit vous choisissez de l’utiliser en la connectant à une sortie de l’Arduino, soit on la force à l’état logique BAS pour utiliser pleinement chaque sortie. Nous, nous la relierons à la masse. Deux dernières broches sont importantes.
La n°11 et la n°12. Ce sont des « horloges ». Nous allons expliquer quelle fonction elles remplissent. Lorsque nous envoyons un ordre au 74HC595, nous envoyons cet ordre sous forme d’états logiques qui se suivent. Par exemple l’ordre 01100011. Cet ordre est composé de 8 états logiques, ou bits, et forme un octet. Cet ordre va précisément définir l’état de sortie de chacune des sorties du 74HC595. Le problème c’est que ce composant ne peut pas dissocier chaque bit qui arrive. Prenons le cas des trois zéros qui se suivent dans l’octet que nous envoyons. On envoie le premier 0, la tension sur la ligne est alors de 0V. Le second 0 est envoyé, la tension est toujours de 0V. Enfin le dernier zéro est envoyé, avec la même tension de 0V puis vient un changement de tension à 5V avec l’envoi du 1 qui suit les trois 0. Au final, le composant n’aura vu en entrée qu’un seul 0 puisqu’il n’y a eu aucun changement d’état. De plus, il ne peut pas savoir quelle est la durée des états logiques qu’on lui envoie. S’il le connaissait, ce temps de « vie » des états logiques qu’on lui envoie, il pourrait aisément décoder l’ordre transmis. En effet, il pourrait se dire: « tiens ce bit (état logique) dépasse 10ms, donc un deuxième bit l’accompagne et est aussi au niveau logique 0 ». Encore 10ms d’écoulée et toujours pas de changement, eh bien c’est un troisième bit au niveau 0 qui vient d’arriver. C’est dans ce cas de figure que l’ordre reçu sera compris dans sa totalité par le composant.
Bon, eh bien c’est là qu’intervient le signal d’horloge. Ce signal est en fait là dans l’unique but de dire si c’est un nouveau bit qui arrive, puisque le 74HC595 n’est pas capable de le voir tout seul. En fait, c’est très simple, l’horloge est un signal carré fixé à une certaine fréquence. À chaque front montant (quand le signal d’horloge passe du niveau 0 au niveau 1), le 74HC595 saura que sur son entrée, c’est un nouveau bit qui arrive. Il pourra alors facilement voir s’il y a trois 0 qui se suivent. Ce chronogramme vous aidera à mettre du concret dans vos idées :


Source : Wikipédia – SDA est le signal de données, l’ordre que l’on envoie ; SCL est le signal d’horloge

Pour câbler cette horloge, il faudra connecter une broche de l’Arduino à la broche numéro 11 du 74HC595. Ce signal travaillera donc en corrélation avec le signal de données relié sur la broche 14 du composant. La seconde horloge pourrait aussi s’appeler « verrou ». Elle sert à déterminer si le composant doit mettre à jour les états de ses sorties ou non, en fonction de l’ordre qui est transmis. Lorsque ce signal passe de l’état BAS à l’état HAUT, le composant change les niveaux logiques de ses sorties en fonction des bits de données reçues. En clair, il copie les huit derniers bits transmis sur ses sorties. Ce verrou se présente sur la broche 12.

Montage

Voici un petit montage à titre d’illustration que nous utiliserons par la suite. Je vous laisse faire le câblage sur votre breadboard comme bon vous semble, pendant ce temps je vais aller me siroter un bon petit café. 🙄

Montage du 74HC595 schéma Montage du 74HC595 breadboard Montage du 74HC595 et 8 LEDs Montage du 74HC595 et 8 LEDs (zoom)

Programmons pour utiliser ce composant

Envoyer un ordre au 74HC595

Nous allons maintenant voir comment utiliser le composant de manière logicielle, avec Arduino. Pour cela, je vais vous expliquer la façon de faire pour lui envoyer un ordre. Puis, nous créerons nous-mêmes la fonction qui va commander le 74HC595.

Le protocole

Nous le verrons dans le chapitre sur la liaison série plus en détail, le protocole est en fait un moyen qui permet de faire communiquer deux dispositifs. C’est une sorte de convention qui établit des règles de langage. Par exemple, si deux personnes parlent deux langues différentes, elles vont avoir un mal fou à se comprendre l’une de l’autre. Eh bien le protocole sert à imposer un langage qui leur permettra de se comprendre. En l’occurrence, il va s’agir de l’anglais. Bon, cet exemple n’est pas parfait et a ses limites, c’est avant tout pour vous donner une vague idée de ce qu’est un protocole. Comme je vous l’ai dit, on en reparlera dans la partie suivante. Nous l’avons vu tout à l’heure, pour envoyer un ordre au composant, il faut lui transmettre une série de bits. Autrement dit, il faut envoyer des bits les uns après les autres sur la même broche d’entrée. Cette broche sera nommée « data ». Ensuite, rappelez-vous, le composant a besoin de savoir quand lire la donnée, quand est-ce qu’un nouveau bit est arrivé ? C’est donc le rôle de l’horloge, ce que je vous expliquais plus haut. On pourrait s’imaginer qu’elle dit au composant :  » Top ! tu peux lire la valeur car c’est un autre bit qui arrive sur ton entrée ! « . Enfin, une troisième broche où l’on va amener l’horloge de verrou sert à dire au composant :  » Nous sommes en train de mettre à jour la valeur de tes sorties, alors le temps de la mise à jour, garde chaque sortie à son état actuel « . Quand elle changera d’état, en passant du niveau BAS au niveau HAUT (front montant), cela donnera le « top » au composant pour qu’il puisse mettre à jour ses sorties avec les nouvelles valeurs.

Si jamais vous voulez économiser une broche sur votre Arduino, l’horloge de verrou peut être reliée avec l’horloge de données. Dans ce cas l’affichage va « scintiller » lors de la mise à jour car les sorties seront rafraîchies en même temps que la donnée arrive. Ce n’est pas gênant pour faire de l’affichage sur des LEDs mais ça peut l’être beaucoup plus si on a un composant qui réagit en fonction du 595.

Création de la fonction d’envoi

Passons à la création de la fonction d’envoi des données. C’est avec cette fonction que nous enverrons les ordres au 74HC595, pour lui dire par exemple d’allumer une LED sur sa sortie 4. On va donc faire un peu de programmation, aller zou ! Commençons par nommer judicieusement cette fonction : envoi_ordre(). Cette fonction va prendre quatre paramètres. Le premier sera le numéro de la broche de données. Nous l’appellerons « dataPin ». Le second sera similaire puisque ce sera le numéro de la broche d’horloge. Nous l’appellerons « clockPin ». Le troisième sera le « sens » d’envoi des données, je reviendrai là-dessus ensuite. Enfin le dernier paramètre sera la donnée elle-même, donc un char (sur 8 bits, exactement comme l’ordre qui est à envoyer), que nous appellerons « donnee ». Le prototype de la fonction sera alors le suivant :

Le code de la fonction ne sera pas très compliqué. Comme expliqué plus tôt, il suffit de générer une horloge et d’envoyer la bonne donnée pour que tout se passe bien. Le 74HC595 copie le bit envoyé dans sa mémoire lorsque le signal d’horloge passe de 0 à 1. Pour cela, il faut donc débuter le cycle par une horloge à 0. Ensuite, nous allons placer la donnée sur la broche de donnée. Enfin, nous ferons basculer la broche d’horloge à l’état haut pour terminer le cycle. Nous ferons ça huit fois pour pouvoir envoyer les huit bits de l’octet concerné (l’octet d’ordre). Schématiquement le code serait donc le suivant :

Envoyer un char en tant que donnée binaire

Maintenant que l’on a défini une partie de la fonction envoi_ordre(), il va nous rester un léger problème à régler : envoyer une donnée de type char en tant que suite de bit (ou donnée binaire). Prenons un exemple : le nombre 231 s’écrit aussi sous la forme 11100111 en base 2 (et oui, c’est le moment de se rappeler ce que l’on a vu ici 🙄 ). Seulement, en voulant envoyer ce nombre sur la broche de donnée pour commander le 74HC595, cela ne marchera pas d’écrire :

En faisant de cette façon, la carte Arduino va simplement comprendre qu’il faut mettre un état HAUT (car 231 est différent de 0) sur sa broche de sortie que l’on a nommée dataPin. Pour pouvoir donc envoyer ce nombre sous forme binaire, il va falloir ajouter à la fonction que l’on a créé un morceau de code supplémentaire. Ce que nous allons va faire va être une vraie boucherie : on va découper ce nombre en huit tranches et envoyer chaque morceau un par un sur la sortie dataPin. :mrgreen: Pour découper ce nombre, ça va pas être de la tarte… euh… je m’égare. 🙄 On va utiliser une technique qui se nomme, tenez-vous bien, le masquage. On va en fait utiliser un masque qui va cacher la véritable valeur du nombre 231. Bon bon, je vous explique. Tout d’abord, on va considérer que le nombre 231 est vu sous sa forme binaire, qui je le rappel est 11100111, par votre carte Arduino. Donc, lorsque l’on va passer en paramètre donnee le nombre 231, le programme verra la suite de 1 et de 0 : 11100111. Jusque-là, rien de bien sorcier. Voilà donc notre suite de 1 et de 0 que l’on va devoir découper. Alors, il n’existe pas de fonction toute prête spécialement conçue pour découper un nombre binaire. Non, ça va être à nous de faire cela. Et c’est pourquoi je vous parlais du masquage. Cette technique ne porte pas son nom par hasard, en effet, nous allons réellement utiliser un masque. Quelques précisions s’imposent, je le sens bien. Reprenons notre suite binaire :

Notre objectif étant d’envoyer chaque bit un par un, on va faire croire à l’Arduino que cette suite n’est composée que d’un seul bit. En clair, on va cacher les 7 autres bits en utilisant un masque :

Ce qui, au final, donnera :

L’Arduino ne verra donc qu’un seul bit.

Et les autres, il les voit pas, comment on peut envoyer les 8 bits alors ? o_O

Bien sûr, les autres, l’Arduino ne les voit pas. C’est pourquoi l’on va faire évoluer le masque et révéler chaque bit un par un. En faisant cela huit fois, on aura envoyé les 8 bits à la suite :

On peut aussi faire évoluer le masque dans le sens opposé :

L’étape qui suit est donc d’identifier le bit à envoyer en premier. C’est là que rentre en jeu le paramètre sens. On a le choix d’envoyer soit le bit de poids fort (on l’appelle MSB, Most Significant Bit) en premier et finir par le bit de poids faible (Least Significant Bit, LSB) ; soit dans le sens opposé, du LSB vers le MSB. On parle alors d’envoi MSB First (pour « bit de poids fort en premier ») ou LSB First. À présent, voyons comment appliquer la technique de masquage que je viens de vous présenter

Les masques en programmation

Maintenant que vous connaissez cela, nous allons pouvoir voir comment isoler chacun des bits pour les envoyer un par un. En programmation, il est évident que l’on ne peut pas mettre un masque papier sur les bits pour les cacher. 😛 Il existe donc un moyen de les cacher. Cela va faire appel à la logique binaire. Nous n’entrerons pas dans le détail, mais sachez que nous allons employer des opérateurs logiques. Il en existe plusieurs, dont deux très utilisés, même dans la vie courante, l’opérateur ET et OU. Commençons par l’opérateur logique ET (je vous laisse regarder le OU tout seul, nous n’en aurons pas besoin ici). Il s’utilise avec le symbole & que vous trouverez sous la touche 1 au-dessus de la lettre « a » sur un clavier azerty. Pour envoyer le premier bit de notre donnée, nous allons effectuer le masquage avec cet opérateur logique dont la table de vérité se trouve être la suivante :

Table de vérité du ET
Bit 1 Bit 2 Résultat
0 0 0
0 1 0
1 0 0
1 1 1

Je ne comprends pas trop où tu veux en venir ? 🙄

Je vais vous expliquer. Pour faire le masquage, on va faire une opération avec ce fameux ET logique. Il s’agit de la même chose que si l’on additionnait deux nombres ensemble, ou si on les multipliait. Dans notre cas l’opération est « un peu bizarre ». Disons que c’est une opération évoluée. Cette opération va utiliser deux nombres : le premier on le connaît bien, il s’agit de la suite logique 11100111, quant au second, il s’agira du masque. Pour l’instant, vous ne connaissez pas la valeur du masque, qui sera lui aussi sous forme binaire. Pour définir cette valeur, on va utiliser la table de vérité précédente. Afin que vous ne vous perdiez pas dans mes explications, on va prendre pour objectif d’envoyer le bit de poids faible de notre nombre 11100111 (celui tout à droite). Le code qui suit est un pseudo-code, mis sous forme d’une opération mathématique telle que l’on en ferait à l’école :

Pour comprendre ce qui vient de se passer, il faut se référer à la table de vérité de l’opérateur ET : on sait que lorsque l’on fait 1 et 0 le résultat est 0. Donc, pour cacher tous les bits du nombre à masquer, il n’y a qu’à mettre que des 0 dans le masque. Là, l’Arduino ne verra que le bit 0 puisque le masque aura caché au complet le nombre du départ. On sait aussi que 1 ET 1 donne 1. Donc, lorsque l’on voudra montrer un bit à l’Arduino, on va mettre un 1 dans le masque, à l’emplacement du bit qui doit être montré. Pour monter ensuite le bit supérieur au bit de poids faible, on procède de la même manière :

Pour le quatrième bit en partant de la droite :

Dans le cas où vous voudriez montrer deux bits à l’Arduino (ce qui n’a aucun intérêt dans notre cas, je fais ça juste pour vous montrer) :

L’évolution du masque

Ce titre pourrait être apparenté à celui d’un film d’horreur, mais n’indique finalement que nous allons faire évoluer le masque automatiquement à chaque fois que l’on aura envoyé un bit. Cette fois, cela va être un peu plus simple car nous n’avons qu’à rajouter un opérateur spécialisé dans le décalage. Si l’on veut déplacer le 1 du masque (qui permet de montrer un bit à l’Arduino) de la droite vers la gauche (pour le LSBFirst) ou dans l’autre sens (pour le MSBFirst), nous avons la possibilité d’utiliser l’opérateur << pour décaler vers la gauche ou >> pour décaler vers la droite. Par exemple :

Et dans le sens opposé :

Avouez que ce n’est pas très compliqué maintenant que vous maîtrisez un peu les masques. 😉 On va donc pouvoir isoler un par un chacun des bits pour les envoyer au 74HC595. Comme le sens dépend d’un paramètre de la fonction, nous rajoutons un test pour décaler soit vers la droite, soit vers la gauche. Voici la fonction que nous obtenons à la fin :

Oula ! Hé ! Stop ! C’est quoi ce 0x01 et ce 0x80 ? Qu’est-ce que ça vient faire là, c’est pas censé être le masque que l’on doit voir ?

Si, c’est bien cela. Il s’agit du masque… écrit sous sa forme hexadécimale. Il aurait été bien entendu possible d’écrire : 0b00000001 à la place de 0x01, ou 0b10000000 à la place de 0x80. On a simplement opté pour la base hexadécimale qui est plus facile à manipuler.

Cette technique de masquage peut sembler difficile au premier abord mais elle ne l’est pas réellement une fois que l’on a compris le principe. Il est essentiel de comprendre comment elle fonctionne pour aller loin dans la programmation de micro-contrôleur (pour paramétrer les registres par exemple), et vous en aurez besoin pour les exercices du chapitre suivant. Pour plus d’informations un bon tuto plus complet mais rapide à lire est rédigé ici… en PHP, mais c’est pareil.

Un petit programme d’essai

Je vous propose maintenant d’essayer notre belle fonction. Pour cela, quelques détails sont à préciser/rajouter. Pour commencer, il nous faut déclarer les broches utilisées. Il y en a trois : verrou, horloge et data. Pour ma part elles sont branchées respectivement sur les broches 11, 12 et 10. Il faudra donc aussi les déclarer en sortie dans le setup(). Si vous faites de même vous devriez obtenir le code suivant :

Ensuite, nous allons nous amuser à afficher un nombre allant de 0 à 255 en binaire. Ce nombre peut tenir sur un octet, ça tombe bien car nous allons justement transmettre un octet ! Pour cela, nous allons utiliser une boucle for() allant de 0 à 255 et qui appellera notre fonction. Avant cela, je tiens à rappeler qu’il faut aussi mettre en place le verrou en encadrant l’appel de notre fonction. Rappelez-vous, si nous ne le faisons pas, l’affichage risque de scintiller.

Et voici le code complet que vous aurez surement deviné :

Et voila le travail ! :

La fonction magique, ShiftOut

Vous êtes content ? vous avez une belle fonction qui marche bien et fait le boulot proprement ? Alors laissez-moi vous présenter une nouvelle fonction qui s’appelle shiftOut(). Quel est son rôle ? Faire exactement la même chose que la fonction dont l’on vient juste de finir la création.

*#@ »e !! 😡

Alors oui je sais, c’est pas sympa de ma part de vous avoir fait travailler mais admettez que c’était un très bon exercice de développement non ? À présent vous comprenez comment agit cette fonction et vous serez mieux capable de créer votre propre système que si je vous avais donné la fonction au début en disant : « voilà, c’est celle-là, on l’utilise comme ça, ça marche, c’est beau… mais vous avez rien compris ». Comme je vous le disais précédemment, cette fonction sert à faire ce que l’on vient de créer, mais elle est déjà intégrée à l’environnement Arduino (donc a été testée par de nombreux développeurs, ne laissant pas beaucoup de place pour les bugs !). Cette fonction prend quatre paramètres :

  • La broche de donnée
  • La broche d’horloge
  • Le sens d’envoi des données (utiliser avec deux valeurs symboliques, MSBFIRST ou LSBFIRST)
  • L’octet à transmettre

Son utilisation doit maintenant vous paraître assez triviale. Comme nous l’avons vu plutôt, il suffit de bloquer le verrou, envoyer la donnée avec la fonction puis relâcher le verrou pour constater la mise à jour des données. Voici un exemple de loop avec cette fonction :

Exercices : encore des chenillards !

Je vous propose maintenant trois exercices pour jouer un peu avec ce nouveau composant et tester votre habileté au code. Le but du jeu est d’arriver à reproduire l’effet proposé sur chaque vidéo. Le but second est de le faire intelligemment… Autrement dit, tous les petits malins qui se proposeraient de faire un « tableau de motif » contenant les valeurs « affichages binaires » successives devront faire autrement. 😉 Amusez vous bien ! PS : Les corrections seront juste composées du code de la loop avec des commentaires. Le schéma reste le même ainsi que les noms de broches utilisés précédemment. PPS : La bande son des vidéos est juste là pour cacher le bruit de la télé… je n’y ai pas pensé quand je faisais les vidéos et Youtube ne permet pas de virer la bande audio…

« J’avance et repars ! »

Consigne

Pour ce premier exercice, histoire de se mettre en jambe, nous allons faire une animation simple. Pour cela, il suffit de faire un chenillard très simple, consistant en une LED qui « avance » du début à la fin de la ligne. Arrivée à la fin elle repart au début. Si ce n’est pas clair, regardez la vidéo ci-dessous ! (Éventuellement vous pouvez ajouter un bouton pour inverser le sens de l’animation).

Correction

Secret: Réponse SelectionnerAfficher

« J’avance et reviens ! »

Consigne

Cette seconde animation ne sera pas trop compliquée non plus. La seule différence avec la première est que lorsque la « lumière » atteint la fin de la ligne, elle repart en arrière et ainsi de suite. Là encore si ce n’est pas clair, voici une vidéo :

Correction

Secret: Réponse SelectionnerAfficher

Un dernier pour la route !

Consigne

Pour cette dernière animation, il vous faudra un peu d’imagination. Imaginez le chenillard numéro 1 allant dans les deux sens en même temps… C’est bon ? si non alors voici la vidéo :

Correction

Secret: Réponse SelectionnerAfficher

Exo bonus

Consigne

Ici le but du jeu sera de donner un effet de « chargement / déchargement » en alternance… Comme d’habitude, voici la vidéo pour mieux comprendre…

Correction

Secret: Réponse SelectionnerAfficher

Pas assez ? Augmenter encore !

Si jamais 8 nouvelles sorties ne vous suffisent pas (bien que cela n’en face que 5 au total puisque trois sont prises pour communiquer avec le composant), les ingénieurs ont déjà tout prévu. Ainsi il est possible de mettre en cascade plusieurs 74HC595 ! Pour cela, le 595 dispose d’une broche appelée « débordement ». Lorsque vous envoyez un seul octet au 74HC595, rien ne se passe sur cette broche. Cependant, si vous envoyez plus d’un octet, les huit derniers bits seront conservés par le composant, tandis que les autres vont être « éjectés » vers cette fameuse sortie de débordement (numéro 9). Le premier bit envoyé ira alors vers le 74HC595 le plus loin dans la chaine. Souvenez-vous, elle s’appelle « serial data output » et j’avais dit qu’on reviendrait dessus. D’une manière très simple, les bits éjectés vont servir aux éventuels 74HC595 qui seront mis en aval de celui-ci.

Branchement

Il suffit dons de mettre deux 595 bout-à-bout en reliant la broche de débordement du premier sur la broche de donnée du second. Ainsi, les bits « en trop » du premier arriveront sur le second. Afin que le second fonctionne, il faut aussi également relier les mêmes broches pour l’horloge et le verrou (reliées en parallèle entre les deux).

Les images proviennent d’une explication du site Arduino. Attention, dans ce schéma les LEDs sont branchées « à l’envers » de ce que nous avons l’habitude de faire.

Deux 74HC595 en cascade, schéma Deux 74HC595 en cascade, breadboard

Exemple d’un affichage simple

Au niveau du programme, il suffira de faire appel deux fois de suite à la fonction shiftOut pour tout envoyer (2 fois 8 bits). Ces deux appels seront encadrés par le verrou pour actualiser l’affichage des données. On commence par envoyer la donnée qui doit avancer le plus pour atteindre le second 595, puis ensuite on fait celle qui concerne le premier 595. Voici un exemple :

Exemple d’un chenillard

Voici maintenant un petit exemple pour faire un chenillard sur 16 LEDs. Pour cela, j’utiliserai un int qui sera transformé en char au moment de l’envoi. Il faudra donc le décaler vers la droite de 8 bits pour pouvoir afficher ses 8 bits de poids fort. Voici une loop pour illustrer mes propos (le setup étant toujours le même). (Attention cependant, contrairement au montage précédent en cathode commune, j’utilise pour ma part un montage à anode commune et donc toutes les sorties sont inversé).

Ce composant peut vous paraître un peu superflu mais il existe en fait de très nombreuses applications avec. Par exemple, si vous voulez réaliser un cube de LED (disons 4x4x4 pour commencer gentiment). Si vous vouliez donner une broche par LED vous seriez bloqué puisque Arduino n’en possède pas autant (il vous en faudrait 64). Ici le composant vous permet donc de gérer plus de sorties que vous ne le pourriez initialement.

61 commentaires

  1. Merci pour toturiel 😉
    Est-ce qu’il existe un composant similaire qui permet d’avoir directement 10 bits en sortie (décimal à la place d’octal), ou faut-il passer par 2 composants 595 ?
    Deuxième question : peut-on directement piloter un MosFet à partir du 595 ?
    Merci bien pour votre aide.

    • Est-ce qu’il existe un composant similaire qui permet d’avoir directement 10 bits en sortie (décimal à la place d’octal), ou faut-il passer par 2 composants 595 ?

      Pas a ma connaissance, mais google saura peut-etre mieux que moi 🙂

      Deuxième question : peut-on directement piloter un MosFet à partir du 595 ?

      Comme avec toute sortie numerique, oui si tu utilises un transistor (ou pont en H complet) pour faire passer la puissance.

      • Merci bien pour cette réponse très rapide.
        Deux 74HC595 sera très bien, même si je n’utilise pas toutes les sorties 😉
        Par contre, j’utilise un autre composant sur le même montage qui utilise aussi un système d’horloge (un MAX7219 pour piloter l’affichage d’un LED-Matrix). Est-ce que ca peut poser des problèmes ? Si j’ai bien compris le fonctionnement de l’horloge non, car c’est juste un enchainement de changement d’état logique (traduit en tension) et cadencé au rythme de l’horloge interne de l’Arduino. Pouvez-vous me le confirmer?
        Merci encore pour votre temps.

        • A priori pas de souci, tu mets le max7219 sur un ensemble de broches et tu mets les 74hc595 en cascade sur un autre. Si je dis pas de betises il devrait meme etre possible de mettre les 74hc595 en cascade avec le MAX je crois (puisqu’au final ils ont un comportement similaire).

          • Merci pour cette confirmation.
            J’ai donc bien compris comment ca fonctionne. 😎

            Je préfère gérer les 2 circuits séparément :
            – le 74hc595 commandera la partie puissance (via des MOSFET P pilotés par un ULN2803 (montage en inverseur je crois) et une Zener et 2 résistances)
            – le MAX c’est juste de l’affichage.

            J’ai une autre question sur le montage anode commune : les diodes s’allument quand l’état logique passe à 0 (mise à la masse). C’est bien ca (c’est donc un montage inverseur) ? Cela permet de réduire la puissance dissipée dans le 595 par rapport au montage cathode commune ?

          • A l’heure actuelle c’est surtout historique. Il y a longtemps, les microcontrôleurs n’étaient pas capable d’avoir des sorties fournissant assez de courant, donc on les mettait en « drain » plutôt qu’en source de courant en pilotant par l’état bas. Maintenant ce n’est plus vraiment vrai, donc tu peux activer a l’état haut si cela te plait.

  2. Ré-bonjour,

    Je viens de penser :
    Ne vaudrait il pas mieu utiliser un transistor avec une source d’alimentation externe.

    Parce que avec 10 LED, les 40 mA maximum par broche sont vites utilisés…

    • Désolé, j’ai écrit trop vite :honte:,

      Je n’avais pas vu que les leds étaient branchés sur le 5V et la masse et non directement alimentés par la broche.

      Mais n’y a t il pas une limite quand même, sur les broche 5V et COM ?

      • Si bien sur qu’il y a des limites !

        Le régulateur de l’Arduino doit pouvoir balancer 1A au max (ce qui sous-entend qu’il est alimente par une alimentation pouvant délivrer elle-même plus de 1A). Si en revanche on est alimente par USB, alors la limite est celle du port USB, soit 500 mA.

  3. Bonjour,
    J’ai un petit soucis avec mes registres à décalage, principalement avec le condensateur qui se trouve entre la broche de verrou (latchPin) et la masse.
    Si je ne le met pas, tout se passe à merveille, l’affactation de mes sorties sur les 2 registres est franc et net.
    Si je le mets (c’est 1uF tantale), je « vois » le décalage des bits sur les broches (c’est comme si le verrou ne restait pas bloqué).
    Est-ce nécessaire de connecter ce condo ? Si oui, quelle serait la bonne valeur, il est surement trop important (10nF serait peut-etre mieux).
    Merci pour votre aide.

    PS : je pilote des nMOS TTL avec un des registres (chaque sortie est connectée à une résistance reliée à la masse ; c’est un montage PullDown je crois), et des pMOS avec l’autre registre (chaque sortie est connectée à un 28LN03. Avec ces MOS je réalise une matrice 8×8, me permettant de piloter 64 lignes de forte puissance (1,5 A).

    • Perso je fais sans ce condensateur sur le verrou et tout va bien… Je dois reconnaître que je ne suis pas bien sur de son rôle dans ce cas present… (pour une fois que je prend un schema qui n’est pas de moi 😀 )

  4. Pingback: Philwat | Pearltrees

  5. Salut ! C’est encore moi 😀 Et toujours pour t’embêter.. Mais il me semble que tu as oublié un « else » dans un de tes codes, dans celui où tu masques de droite à gauche ou de gauche à droite pour pouvoir envoyer les bits un à un, tu as mis le if(sens), donc je suppose si sens = 1 on va dans un sens, mais du coup il te faut le else pour l’autre sens.. Voilà voilà 🙂 Sinon encore merci pour tous tes efforts !

  6. Un grand MERCI Eskimon pour cet excellent tuto.
    Pour ma part, j’ai essayé de faire le montage tel que vous l’avé décrit, et j’ai implémenté le code, mais chez moi ça ne m’affiche que certains nombres à savoir 128, 224, 252 puis s’arrête à 255, g beau cherché ou se trouve le problème en vain. Vous auriez pas d’idée d’où peut-il se trouver?
    Bien Cordialement

  7. Pingback: 👍 comment fonctionne 74hc595

  8. Pingback: [ Arduino Annexe B ] Gestion de la mémoire - Le blog d'Eskimon

  9. Bonjour, tout d’abord merci pour cet article génial. Cependant j’ai une question peut-on cramer un registre à décalage, car j’ai réalisé tout les montage comme il le faut et j’ai bien rajouter le code cependant se sont toujours les mêmes LED qui s’allument. Même si je change le code.

        • Me revoilà. Bon je ne comprend pas tout. En effet après de multiples essais (un seul de réussi), je me suis rendu compte de certaines choses étranges. Premièrement si on bouge un peu la plaquette la combinaison de LED change, je pense que cela vient peut être de petites coupures dans la liaison entre un fil et la plaquette. De plus, et là j’en pers mon latin, si je coupe l’INPUT VCC … rien ne se passe. Idem quand je met à l’état bas CLEAR. Je ne comprend vraiment pas. Je met toujours en cause mes expérimentations cependant si tu avais une idée peut être que ça m’aiderais. MERCI 😉

          • Salut !

            Est-ce que tu pourrais ouvrir un sujet dans le forum « Système et Matériel » du site Zeste de Savoir sur lequel je passe régulièrement (ainsi que d’autre passionné) et y joindre une photo du montage ? Ce sera plus simple que cette zone de commentaire un peu étriqué et pas très pratique d’utilisation 😉

  10. Pingback: ARDUINO | Pearltrees

  11. Bonjour, d’abord un grand merci pour ce super topic 😉
    j’ai ajouté un troisième registre, mais après avoir transféré le programme sur l’Arduino, voilà ce qu’il se passe :
    les leds clignotent une à une sur les deux premiers registres (comme dans la vidéo du chenillard à deux registres), mais quand on arrive sur la dernière led du deuxième registres, toutes celles du troisièmes clignotent une fois et plus rien … il y a un temps (surement celui durant lequel les leds du troisième registre devraient clignoter…)

    Voilà mon code :

    const int verrou = 11;
    const int donnee = 10;
    const int horloge = 12;

    void setup()
    {
    pinMode(verrou, OUTPUT);
    pinMode(donnee, OUTPUT);
    pinMode(horloge, OUTPUT);
    }

    void loop()
    {
    int masque = 0;
    for(int i=0; i<24; i++)
    {
    masque = 0x01 <> 8));
    shiftOut(donnee, horloge, LSBFIRST, ~((masque & 0xFF0000) >> 16));
    digitalWrite(verrou, HIGH);
    delay(250);
    }
    }

    Je ne sait pas d’où peut venir l’erreur … Si vous pouviez m’aider ?
    merci d’avance 🙂

    • le code n’était pas passé correctement désolé :/ le revoilà :

      const int verrou = 11;
      const int donnee = 10;
      const int horloge = 12;

      void setup()
      {
      pinMode(verrou, OUTPUT);
      pinMode(donnee, OUTPUT);
      pinMode(horloge, OUTPUT);
      }

      void loop()
      {
      int masque = 0;
      for(int i=0; i<24; i++)
      {
      masque = 0x01 <> 8));
      shiftOut(donnee, horloge, LSBFIRST, ~((masque & 0xFF0000) >> 16));
      digitalWrite(verrou, HIGH);
      delay(250);
      }
      }

      • const int verrou = 11;
        const int donnee = 10;
        const int horloge = 12;

        void setup()
        {
        pinMode(verrou, OUTPUT);
        pinMode(donnee, OUTPUT);
        pinMode(horloge, OUTPUT);
        }

        void loop()
        {
        int masque = 0;
        for(int i=0; i<24; i++)
        {
        masque = 0x01 <> 8));
        shiftOut(donnee, horloge, LSBFIRST, ~((masque & 0xFF0000) >> 16));
        digitalWrite(verrou, HIGH);
        delay(250);
        }
        }

  12. Pingback: Sand glass traffic light – Roysone

  13. Hello,

    Tout d’abord merci à Eskimon, son travail sur l’arduino est une vrai bible pour moi.
    Un petite question cependant qui me turlupine (en tant que novice en électronique qui cherche à comprendre). Si on allume 8 leds en même temps, est-ce qu’on n’a pas un problème de puissance / courant au niveau de l’arduino ?

    Merci,

    A+

    • Hum… question déjà en partie répondue, les leds sont alimentées par le 5V et pas par les pins de l’arduino… OK… mais les pin de l’arduino absorbent le courant non ? Est-ce que ce n’est pas équivalent en terme de limitation ? J’ai l’impression que c’est une question bête mais bon…

      Merci,

      A+

  14. Bonjour Eskimon,

    Super tuto qui m’a beaucoup appris sur les registres à décalage.
    J’ai cependant une petite question sur le code du chenillard à 16 leds.
    Quand je mets LSBFIRST, la led va bien de droite à gauche comme sur la vidéo mais avec MSBFIRST la led commence à la position 9 au départ une fois puis c’est correct de gauche à droite de 1 à 16.
    J’ai essayé de modifier le code mais je bloque sur ce problème.

    Merci d’avance pour votre aide.
    Benoit

  15. Pingback: Leds | Pearltrees

  16. Pingback: Leds | Pearltrees

  17. Pingback: Leds | Pearltrees

  18. Salut Eskimon, comment dire.. super tuto qui m’aide beaucoup dans mon projet actuel, Cependant j’essaie donc de réaliser le coté électronique de la porte d’atlantis de la série stargate. j’ai utiliser le code pour le chenillard avec deux 74hc595 comme la derniere vidéo le montre avec quelque modif facile mais j’arrive pas à aller plus loin. Pourriez vous m’aidez ? s’il vous plait

  19. Bonjour,
    Cela fait plusieurs mois que j’ai réalisé des cartes avec des 595 (commande d’aiguillages et de feux) grâce aux renseignements de ce blog.
    Tout s’est bien passé aussi bien sur l’aspect hard que soft.
    Je viens de faire une nouvelle carte pour piloter des feux et là, problème.
    En MSBFIRST, quand j’envoi 1, j’allume Q7 (ce qui me va), mais quand j’envoi 2, j’allume Q7 et Q6 et là c’est pas bon. en ainsi de suite: 4 = Q6 + Q5, 8 = Q5 + Q4, 16 = Q4 + Q3, 32 = Q3 + Q2, 64 = Q2 + Q1, et (?), 128 = Q0 tout seul. Même topo en LSBFIRST.
    Il ne peut pas s’agir de court-circuit entre les pins sinon tout s’allumerais en même temps. Le programme de l’ARDUINO est identique à un autre déjà fait.
    Qui aurait une idée sur ce qui peut se passer?

  20. J’ai résolu mon problème en utilisant une alim 5V séparée pour ma carte.
    Probablement que je tirais trop sur le 5V de l’ARDUINO avec mes 6 x 595 et autant d’ULN
    Par contre, j’ai constaté un truc bizarre: les 0V de l’ARDUINO et de ma carte étant reliés, dès que je branche le fil du LATCH, qui est HIGH donc à 5V, je me retrouve avec 3,8V entre VCC et GND.
    Est-ce normal?

Laisser un commentaire