Aller au contenu

Tutorial PCF8574 : comment ajouter des entrées / sorties à son arduino ? (avec exemples de code)

Tutorial PCF8574 arduino, pour ajouter des entrées sorties en i2c, explication fonctionnement module PCF 8574, 8574A, et 8575, avec exemples de code

Vous êtes en manque d’entrées sorties sur votre Arduino ? Alors cette puce pourrait fort vous intéresser ! En effet, le PCF8574 permet d’ajouter jusqu’à 8 entrées/sorties digitales supplémentaires, pilotées en i2c, qui fonctionneront exactement (ou presque !) comme les pins D0 et D13 de votre Arduino Uno ou Nano, par exemple.

Mais cela va plus loin encore ! Car on peut « chaîner » jusqu’à 8 modules PCF 8574, pour atteindre les 64 entrées / sorties additionnelles. De quoi rendre son Arduino monstrueusement suréquipé ! Et sans parler du fait que tout cela est pilotable avec 2 fils seulement (les lignes SDA et SCL du bus i2c). Sympa, non ? Alors par ici pour découvrir tout cela plus en détail 😉

Ce contenu vous plaît ? Alors abonnez-vous à la Newsletter pour ne rien louper !

Le but de cet article est de vous initier à l’utilisation du PCF8574, afin d’étendre le port GPIO de votre arduino, ou tout autre microcontrôleur disposant d’un bus I2C. C’est pourquoi nous verrons en « détail » ici : comment brancher un PCF8574 sur le bus i2c, comment lui attribuer une adresse spécifique, et comment utiliser chacune des broches en entrée ou en sortie. Comme toujours, n’hésitez pas à poster vos remarques et/ou questions en bas d’articles, et me signaler toute erreur ou coquille qui se serait glissée dans ce tuto ! Du reste, bonne lecture à vous !

À quoi sert un PCF8574 ? (domaines d’application)

Avant de présenter en détail ce circuit intégré, vous vous demandez peut-être dans quels cas utiliser un PCF8574 ?

Comme laissé entendre en intro, une des utilisations phares du PCF 8574 est l’ajout d’entrées/sorties à un microcontrôleur. En effet, on peut facilement ajouter 8 entrées/sorties supplémentaires à son µC en utilisant cette puce. Qui plus est, on peut utiliser plusieurs PCF 8574 en parallèle (avec pour chacun une adresse unique), ce qui permet d’ajouter jusqu’à 64 E/S additionnelles au final, à son Arduino ou autre. Enfin, si on est « bidouilleur » et qu’on souhaite aller encore plus loin, on peut également rajouter un multiplexeur I2C pour multiplier encore plus le nombre de PCF 8574, et ainsi, multiplier d’autant le nombre d’E/S supplémentaires possible ! Imaginez un peu 😉

Mais outre le fait de permettre l’ajout d’entrées/sorties à son microcontrôleur, le PCF 8574 a bien d’autres usages :

  • gestion I2C d’un clavier (keypad), comportant de nombreuses touches
  • pilotage de multiples relais, en parallèle
  • pilotage de nombreuses LED en simultané
  • pilotage I2C d’un écran LCD à bus parallèle
  • création d’une interface homme machine, avec multiples boutons poussoirs et voyants lumineux

Par contre, autant vous le dire tout de suite : un PCF8574 ne peut malheureusement pas délivrer beaucoup de courant en sortie (1 ou 25 mA max, suivant la configuration). C’est pourquoi il est parfois couplé à un driver (de type UDN2982, par exemple), afin de pouvoir délivrer beaucoup plus de courant en sortie.

Cela étant dit, le PCF 8574 est le genre de composant électronique idéal lorsqu’on souhaite piloter beaucoup d’éléments, avec 2 fils de commande seulement !

Caractéristiques (issues du datasheet) + pinout puce et module

Aperçu

Le PCF8574 se présente sous la forme d’un circuit intégré, vendu seul, ou monté sur une plaquette PCB, avec quelques composants additionnels tout autour.

ModèlePCF8574 « seul »PCF8574 « monté sur pcb »
Aperçu Photo puce PCF 8574 au format SOIC, du fabricant Texas Instruments, circuit intégré add-on de input et output sur son Arduino, avec pilotage I2C port série Photo module PCF 8574 arduino monté sur PCB, avec composants additionnels soudés dessus, tels que résistances de pull-up I2C sur lignes SDA et SCL
FormatDIP, SOIC, SSOP, QFN, …Circuit imprimé PCB, avec sélecteur d’adresse I2C intégré (sous forme cavaliers ou microswitch, principalement)
AvantagesIdéal pour l’intégrer exactement où on souhaite, sans perte d’espaceIdéal pour faire ses premiers pas avec, en utilisant des fils dupont pour faire ses essais
InconvénientsNécessite plusieurs composants additionnels, pour fonctionnerPrend beaucoup de place en pratique, surtout si on en utilise plusieurs
Lien (description/prix)Version « PCF8574 format DIP » Lien externe produit ou composant électronique, pour projet ou montage à faire soi-même, external link passion élec
Version « PCF8574 format SOIC (SOP-16) » Lien externe produit ou composant électronique, pour projet ou montage à faire soi-même, external link passion élec
Version « PCF 8574 monté sur PCB » Lien externe produit ou composant électronique, pour projet ou montage à faire soi-même, external link passion élec

Cette puce électronique est fabriquée par TEXAS INSTRUMENTS. Vous trouverez ici :

Brochage (pinout)

Comme vous l’aurez compris, le PCF8574 peut s’acheter « seul », à souder sur son circuit imprimé, ou s’acheter en version « plaquette PCB », que l’on peut facilement interfacer avec son Arduino. Pour chacun d’eux, voici des exemples de brochages (pinout, en anglais), afin de bien visualiser les choses :

Pinout PCF8574 version chip ou mini plaquette PCB, indication des entrées et sorties, pour alimentation électrique, communication I2C, et broches libres

Nous verrons tout au long de cet article à quoi servent chacune de ces broches, et comment les relier au reste de l’environnement.

Alimentation électrique

La puce PCF 8574 s’alimente avec une tension de 2,5 à 6 volts, typiquement. Ce qui en fait le composant idéal si vous travaillez avec des Arduino ou tout autre « petit microcontrôleur basique », car il est donc compatible 3,3V et 5V.

À l’extrême, ce circuit intégré supporte une plage d’alimentation pouvant aller de -0,5 à +7 volts. Mais je vous conseille plutôt de (toujours) rester dans les spécifications recommandées par le fabricant, à savoir : 2,5 à 6V.

Entrées/sorties (notées P0 à P7) : quelle tension ? quel courant ?

Chacune des entrées/sorties peut être configurée soit en entrée, soit en sortie (Lapalisse n’aurait pas dit mieux… d’ailleurs !).

Lorsqu’une broche du PCF8574 est définie en « sortie » :

  • la tension délivrée sera :
    • quasi égale à 0 volt, pour signifier un état bas
    • quasi égale à +Vcc, pour signifier un état haut
  • le courant de sortie, quant à lui, sera de :
    • 25 mA max, lorsque c’est le PCF 8574 qui « reçoit » le courant
    • 1 mA max, lorsque c’est le PCF 8574 qui « débite » du courant

Concernant ce dernier point, voici un petit schéma explicatif, pour bien comprendre cette histoire de courant entrant ou sortant du PCF8574 :

Courant max sortie PCF8574 sur pins P0 à P7, selon branchement entrant ou sortant, avec note intensité maximale, données issues du datasheet fabricant

Comme vous pouvez d’ores et déjà le constater, les « 1 mA » max en sortie sont insuffisants pour alimenter correctement une charge (LED ou autre). C’est pourquoi il faudra toujours réfléchir à un moyen de faire autrement, en utilisant par exemple la sortie « à l’envers » (pour avoir « accès » aux 25 mA max), ou en faisant appel à un circuit amplificateur de courant (driver).

À noter que cette limite de courant de sortie est directement liée au fait que cette sortie peut également faire office d’entrée, comme nous allons le voir à présent.

Lorsqu’une broche du PCF8574 est définie en « entrée » :

  • la tension à appliquer doit être :
    • supérieure à 0,7 x Vcc, pour être considérée comme un état haut (sans toutefois excéder Vcc+0,5 volts)
    • inférieure à 0,3 x Vcc, pour être considérée comme un état bas (sans descendre en dessous de -0,5 volt)
  • tout en sachant qu’une entrée libre (déconnectée) du PCF 8574 aura un niveau égal à +Vcc (comme si la puce avait activé une pull-up interne, si vous voulez)

Remarque : les entrées/sorties d’un PCF8574 sont de type « tout-ou-rien » (digitales, donc). C’est pourquoi cette puce ne peut reconnaître que des états hauts (Vcc) ou des états bas (0V), et rien d’autre. Ce qui signifie qu’on ne pourra jamais avoir la moindre entrée analogique supplémentaire ici, mais uniquement des entrées/sorties numériques.

Vitesse de fonctionnement des E/S du PCF8574

Le circuit intégré PCF 8574, de par sa conception, est un composant piloté via bus I2C. Et c’est la vitesse de ce bus qui conditionnera sa vitesse. En effet, vous ne pourrez pas faire basculer l’état de vos sorties (ou lire le niveau de vos entrées) aussi vite que vous le souhaiterez.

À ce propos, la vitesse recommandée par le fabricant, au niveau de l’horloge i2c, est de 100 kHz (ligne SCL, du bus I2C). En pratique, on peut aller au-delà, mais des problèmes peuvent apparaître si vous dépassez les 200 kHz, environ.

Du reste, outre cette « lenteur I2C » somme toute relative, le PCF est assez rapide (puisqu’il lui faut généralement que 4 µs pour faire changer l’état d’une sortie, ou déclencher une interruption, par exemple).

Adressage I2C

Un des points forts du PCF8574 est de pouvoir attribuer une des 8 adresses I2C différentes, en configurant les broches A2, A1, et A0 de cette puce. Ainsi :

  • si 1 x PCF8574 permet d’avoir 8 entrées/sorties supplémentaires
  • alors 8 x PCF8574 permettent d’avoir au global pas moins de 64 entrées/sorties supplémentaires 😉

Et bien sûr, le pilotage s’effectue toujours avec 2 fils seulement, que vous ayez 1 ou plusieurs de ces modules ! C’est d’ailleurs là toute sa force, et ce qui laisse entrevoir tout son potentiel !

Ligne d’interruption (INT)

Autre atout du PCF 8574 : une ligne d’interruption (broche INT) signalant tout changement d’état des broches configurées en entrée. Ainsi, toute entrée passant de l’état haut à l’état bas, ou de l’état bas à l’état haut, induira la génération d’une interruption physique, disponible sur la pin /INT du PCF 8574.

À noter que cette broche INT, est :

  • de type « à drain ouvert », c’est à dire qu’elle nécessite l’ajout d’une résistance de pull-up externe (par exemple reliée au +Vcc), pour l’amener à l’état haut en l’absence d’interruption (son état « normal », en quelques sorte)
  • active à l’état bas, c’est à dire que le PCF8574 reliera celle-ci à la masse, pour signaler toute interruption

En bref, la tension sur la borne INT est de 0 volt en cas d’interruption, et toute autre tension, dans le cas contraire.

Important : notion d’entrées / sorties QUASI bidirectionnelles (broches P0 à P7)

Avant d’aller plus loin, il y a une notion très importante à bien comprendre ici, sans quoi vous n’arriverez pas à saisir le fonctionnement pratique du PCF8574.

Il s’agit de la notion d’entrée/sortie « quasi bi-directionnelle », qui comme vous l’aurez compris, laisse entendre que ce n’est pas du 100 % bidirectionnel 😉

En fait, le fabricant de cette puce a fait le choix d’une architecture interne bien spécifique. En effet, les entrées/sorties ne sont en fait… que des sorties, en quelque sorte ! Et pour que ces dernières puissent fonctionner en entrée, il aura fallu que l’état haut de ces sorties soit faible, c’est à dire pouvant aisément être ramené à l’état bas.

Du coup, on a donc des sorties avec :

  • un état haut « faible » (c’est à dire pouvant « facilement » être ramené à l’état bas)
  • un état bas « fort » (c’est à dire ne pouvant pas être relevé à l’état haut, sans dommage)

Au final :

  • les entrées/sorties du PCF8574 ne sont en fait que des sorties
  • lorsqu’on souhaite se servir d’une broche en SORTIE, on la met :
    • à l’état haut, pour avoir du +Vcc en sortie
    • à l’état bas, pour avoir 0 volt en sortie
  • lorsqu’on souhaite se servir d’une broche en ENTRÉE, on la met uniquement à l’état haut, pour qu’elle puisse :
    • rester à l’état haut, si du +Vcc lui est soumis en entrée
    • passer à l’état bas, si du 0V lui est soumis en entrée

En espérant que toutes ces explications soient suffisamment claires, car je ne saurais vous l’expliquer plus simplement 😉

Du reste, gardez bien à l’esprit que tout ceci est propre au PCF8574. D’ailleurs, les broches d’E/S d’un Arduino ne sont, quant à elles, pas conçues ainsi. En effet, les microcontrôleurs ATmega montés sur les platines Arduino disposent de registres de contrôle permettant de faire de « vrais aiguillages » (le fameux « pinMode() », dans le code arduino), ce qui permet de raccorder chaque broche soit à une interface d’entrée, soit à une interface de sortie. Dans ce cas, nous sommes vraiment en présence d’entrées/sorties bidirectionnelles. Mais là, dans le cas du PCF 8574, il a été fait le choix de faire autrement, et il faut faire avec ! Sachez le simplement, afin de bien comprendre les limites de celui-ci, quand vous l’utiliserez !

Choix de l’adresse I2C, en fonction des broches A2, A1, et A0

L’adressage I2C est somme toute assez simple, ici. Car le PCF8574 nous met à disposition 3 broches externes, notées A0/A1/A2, qui, selon si elles sont mises à 0 (la masse) ou à 1 (+Vcc), permettent de sélectionner l’une ou l’autre des adresses possibles.

Voici d’ailleurs le tableau de correspondance des adresses I2C utilisables du PCF8574, en fonction des entrées de sélection d’adresse A0, A1, et A2 :

Adresses I2C du PCF8574 selon branchement des entrées A2, A1, et A0, au GND ou à Vcc, avec valeurs binaires / hexadécimales en codage 7 bits sur le bus

À noter que ces adresses i2c à 7 bits sont celles que vous devrez renseigner dans votre code arduino, afin de cibler votre module PCF 8574, et de pouvoir communiquer avec lui. Et comme vous pouvez le constater sur l’image ci-dessus, cette adresse, codée sur 7 bits, est décomposable de la manière suivante :

  • les 4 premiers chiffres (0100) représentent « officiellement » la puce PCF8574
  • les 3 suivants représentent respectivement les entrées A2, A1, et A0

Petite parenthèse technique, pour les plus curieux d’entre vous : si vous regardez bien le datasheet du fabricant, vous verrez que ces adresses ne sont pas celles indiquées ci-dessus. En fait, tout est question de référentiel. En effet, les adresses spécifiées ci-dessus sont les « vraies » adresses 7 bits I2C, que l’on peut utiliser pour dialoguer avec un PCF8574. Mais en pratique, cette adresse 7 bits est suivie soit d’un 0, soit d’un 1, selon si l’on souhaite « écrire » (0 = write) au destinataire, ou « lire » (1 = read) une donnée du destinataire.

Ainsi, si on fixe par exemple les lignes A2, A1, et A0 à 0, alors l’adresse I2C sera :

  • égale à 0100 000 en « binaire 7-bits » (soit 0x20 en hexadécimal)
    • le « 0100 » du début étant l’identifiant du PCF 8574
    • les « 000 » suivants correspondant aux entrées A2, A1, A0
  • égale à 0100 0000 en « binaire 8-bits » en ÉCRITURE (soit 0x40 en hexadécimal)
    • le « 0100 » du début étant toujours l’identifiant du PCF 8574
    • les « 000 » suivants correspondant encore aux entrées A2, A1, A0
    • et le dernier « 0 » signifiant qu’on souhaite faire une écriture, à destination du destinataire
  • égale à 0100 0001 en « binaire 8-bits » en LECTURE (soit 0x41 en hexadécimal)
    • le « 0100 » du début étant encore l’identifiant du PCF 8574
    • les « 000 » suivants correspondant toujours aux entrées A2, A1, A0
    • et le « 1 » final signifiant qu’on souhaite faire une lecture, auprès du destinataire

Vous voyez donc 3 adresses pointant vers le même destinataire, mais selon un point de vue différent. En effet :

  • la 1ère adresse est l’adresse I2C (format normalisé 7-bits) du PCF8574 ; c’est elle qui sera à renseigner dans votre programme Arduino
  • la 2ème adresse est l’adresse d’écriture I2C sur 8-bit (c’est elle qu’on retrouve dans la documentation constructeur)
  • la 3ème adresse est l’adresse de lecture I2C sur 8-bit (c’est elle qu’on retrouve également dans le datasheet du fabricant)

Bon … j’espère que tout ceci ne vous a pas donné mal à la tête ! Sinon, retenez juste l’adresse 7 bits du PCF 8574, pour cibler ce dernier depuis votre code de programmation arduino. Le reste n’étant ici qu’informel, afin que vous puissiez mieux comprendre pourquoi les fabricants notent des valeurs « différentes » de celles qu’on doit saisir dans nos programmes arduino.

Comment raccorder le module PCF8574 à un Arduino ?

Le raccordement d’un PCF8574 à un Arduino est assez simple, au final. Car il suffit de :

  • raccorder l’alimentation (+Vcc et GND)
  • raccorder les lignes du bus i2c (lignes SDA et SCL)
  • [optionnel] raccorder la ligne INT sur une des entrées arduino le permettant (si vous souhaitez capter les interruptions issues du PCF)
  • et configurer physiquement l’adresse I2C souhaitée, pour votre puce PCF 8574

En pratique, voici un exemple de branchement d’une puce PCF 8574 à un Arduino Uno :

Schéma de raccordement PCF 8574 avec Arduino Uno, incluant résistances de pull-up i2c ainsi que condensateur de découplage d'alimentation Vcc

Et si vous utilisez un module PCF8574 « monté sur PCB » (c’est à dire comprenant la puce + ses composants additionnels), voici comment cela pourrait se câbler :

Câblage Arduino Uno et PCF8574 avec fils de liaison i2c et alimentation électrique, ainsi que entrée interruption câblée et résistance pull-up interne

En sachant ici que, si vous optez pour un module « tout prêt » tel que visible juste au-dessus :

  • les résistances de pull-up I2C sont déjà intégrées au module
  • ainsi que le « bloc » de sélection d’adresse I2C (les fameuses broches A2, A1, et A0, du PCF8574), au travers de microswitchs ici

À noter l’absence de condensateur de découplage sur cette mini-plaquette PCB (alors que bien noté dans le datasheet, même si aucune valeur n’est précisée), ce qui peut éventuellement altérer le bon fonctionnement de cette puce. Sans parler de la résistance de pull-up indispensable sur la sortie /INT, si vous prévoyez de l’utiliser !

Le chaînage, pour ajouter encore plus d’entrées ou sorties à son Arduino

Juste un mot sur le chaînage possible de ces modules : en pratique, vous pourrez brancher en série jusqu’à 8 de ces modules. Cela se fait de la manière suivante :

Mise de série de modules PCF8574, branchements à la suite des puces PCF 8574 en Vcc, GND, SDA, et SCL, jusqu'à 8 circuits intégrés chaînés ensembles

C’est d’ailleurs toute la « force » de ces petits modules « prêts à l’emploi », qui vous permettent d’obtenir ainsi jusqu’à 8×8, soit 64 entrées/sorties supplémentaires.

Cela étant dit, bien que ce soit un atout pour faire ses essais, ce n’est pas vraiment l’idéal en pratique (car cela prend beaucoup de place !). D’autant plus que ce chaînage pourrait endommager votre Arduino, si vous le faisiez ainsi. En effet, le talon d’Achille de ces modules est de ne pas pouvoir déconnecter manuellement les résistances de pull-up i2c. Or, si vous connectez 8 modules ainsi, ce sont 8 pull-up qui seront mises en parallèles, consommant donc 8 fois plus de courant sur le bus I2C. Autant vous dire que cela peut faire trop… et potentiellement endommager votre microcontrôleur.

Si toutefois vous souhaitez chaîner plusieurs de ces modules, je vous conseille de :

  • laisser les résistances de pull-up du 1er module en place
  • et de retirer (en les dessoudant) celles présentes sur les autres modules

Ainsi, vous éviterez toute surconsommation électrique au niveau du bus i2c, avec toutes les conséquences qui peuvent en découler !

Remarque : histoire d’être plus précis sur les mots, il faut savoir ici que chaîner des modules en série signifie mettre les PCF 8574 en parallèle. En effet, même si le raccordement physique se fait en série, et laisse penser à un branchement série des PCF8574, ce sont bien des alims et des puces mises en parallèle que l’on obtient au final.

Quelle librairie utiliser pour piloter ces modules d’extension d’entrées et sorties ?

Au niveau des librairies utilisables pour piloter un module PCF8574, il en existe plusieurs. Mais avant de parler d’elles, il faut savoir qu’il existe 2 manières de procéder, pour piloter un PCF8574 :

  • soit utiliser la librairie généraliste « Wire », native dans Arduino, pour « manuellement » interroger le PCF 8574 à sa guise (ce qui donne un contrôle « total » de la communication Arduino/PCF8574, mais qui complexifie grandement le codage, et sa maintenance)
  • soit utiliser une librairie spécialisée, telle que la libraire « PCF8574 » de Renzo Mischianti, par exemple, qui est disponible dans le gestionnaire de librairies Arduino (ce qui permet d’assouplir le codage, mais aux dépens de la maîtrise du protocole d’échange entre l’Arduino, et le PCF 8574)

Histoire de vous donner la possibilité de juger par vous même laquelle de ces deux méthodes serait la plus efficace ou appropriée, je vous mettrai par la suite des exemples mettant en œuvre l’une ou l’autre de ces solutions. Ainsi, vous pourrez décider laquelle de ces méthodes vous sied le mieux. Bien entendu, il existe de nombreuses autres librairies pouvant interagir avec un PCF8574, qu’elles soient disponibles directement sous Arduino IDE ou non (via GitHub, par exemple). Ce qui vous laisse une possibilité de choix encore plus large 😉

Du reste, je vais vous montrer ici comment installer la librairie PCF 8574 de Renzo Mischianti, disponible sous l’IDE Arduino, afin de permettre aux débutants de se familiariser avec l’installation de cette librairie, via le gestionnaire de bibliothèques. À noter que vous pourrez trouver le détail de celle-ci sous GitHub, à l’adresse suivante : https://github.com/xreef/PCF8574_library

Pour ouvrir le gestionnaire de librairie de l’IDE Arduino, il suffit de cliquer sur le menu Outils > Gérer les bibliothèques (raccourcis : CTRL + MAJ + i). Vous devriez ainsi voir une fenêtre apparaître à l’écran. Il vous suffit alors de taper « PCF8574 » dans le champ de recherche, et d’appuyer ensuite sur la touche ENTRÉE. Ainsi, vous devriez obtenir une liste des librairies comportant ce nom, avec celle qui nous intéresse « quelque part au milieu ! » (comme visible ci-dessous).

Recherche librairie PCF8574 dans gestionnaire de bibliothèques de l'IDE Arduino, afin d'installer la version permettant de tester des exemples i2c

Il ne vous reste alors plus qu’à cliquer sur « Installer », afin qu’elle soit importée dans votre IDE Arduino. Une fois fait, vous devriez voir la mention « INSTALLED » au niveau de cette librairie (descendre dans la liste présente à l’écran, si jamais vous étiez automatiquement remonté en haut de celle-ci, lors de l’installation).

Installation librairie PCF8574.h dans IDE Arduino, depuis gestionnaire de bibliothèques intégré, pour intégration dans code de programmation de tests

Voilà ! Tout est bon pour passer à la pratique, et voir ensemble plusieurs exemples d’applications concrètes. Alors en avant !

Code arduino #1 : ajouter des entrées à son arduino, et afficher leur état (PCF 8574 + librairie Wire)

La première application pratique du PCF8574 que je vous propose de découvrir, permet d’ajouter 8 entrées à votre Arduino. Ainsi, nous allons configurer les broches P0 à P7 du PCF 8574 en « entrées ». Celles-ci étant de type logique (0 ou 1), elles seront donc soit mises à l’état haut (un « 1 » logique, donc), soit mises à l’état bas (« 0 » logique).

Pour ce faire, je vous propose de partir sur le montage suivant :

Branchement module PCF8574 sur Arduino Nano, avec broches configurées en entrée, sur pins P0 à P7, incluant réseau de résistances 10k en pull-up à +5V

Pour info, les composants utilisés sont les suivants :

Comme vous pouvez le voir sur le schéma ci-dessus, les microswitchs (interrupteurs « tout ou rien ») ont été branchés sur les broches P0 à P7 d’un PCF8574. Ceux-ci permettront d’abaisser les entrées P0 à P7 à l’état bas, lorsque souhaité. Le reste du temps, ces entrées seront à l’état haut, du fait de la présence de résistances pull-up (logées ici au sein d’un seul et même réseau de résistances, pour gagner de la place).

À noter qu’en théorie ces résistances de pull-up ne sont pas indispensables. Car, pour rappel, les broches P0 à P7 sont en fait des SORTIES qui doivent être mises à un état haut « faible » (interne au PCF 8574), afin qu’elles puissent ensuite servir en ENTRÉES. C’est ainsi qu’elles pourront être forcées à l’état bas, à chaque fois qu’on le désire. Cela étant dit, en pratique, il vaut mieux toujours ajouter des résistances de pull-up externes, telles que dessinées sur le schéma précédent, afin que les sorties P[0..7] soient plus dynamiques.

Côté programme, nous allons utiliser ici la librairie générique « Wire », par défaut intégrée à l’environnement Arduino IDE (ne nécessite pas d’installation, donc). Côté fonctionnel, nous allons interroger le PCF8574 à intervalles réguliers, afin de connaître l’état de ses entrées (0 ou 1, donc), et afficher cela sur le moniteur série Arduino. Voici d’ailleurs le programme, permettant de faire cela :

/*
   ______               _                  _///_ _           _                   _
  /   _  \             (_)                |  ___| |         | |                 (_)
  |  [_|  |__  ___  ___ _  ___  _ __      | |__ | | ___  ___| |_ _ __ ___  _ __  _  ___  _   _  ___
  |   ___/ _ \| __|| __| |/ _ \| '_ \_____|  __|| |/ _ \/  _|  _| '__/   \| '_ \| |/   \| | | |/ _ \
  |  |  | ( ) |__ ||__ | | ( ) | | | |____| |__ | |  __/| (_| |_| | | (_) | | | | | (_) | |_| |  __/
  \__|   \__,_|___||___|_|\___/|_| [_|    \____/|_|\___|\____\__\_|  \___/|_| |_|_|\__  |\__,_|\___|
                                                                                      | |
                                                                                      \_|
  Fichier :       prg1-LectureDesEntreesDuPCF8574-AvecLibrairieWire.ino
  
  Description :   Programme permettant de lire les entrées P0 à P7 d'un expander PCF8574,
                  en utilisant la librairie Wire (native sous "Arduino IDE")
                  
  Auteur :        Jérôme TOMSKI (https://passionelectronique.fr/)
  Créé le :       26.06.2022

*/

#include <Wire.h>
#define adresseDeLaPucePCF8574 0x20       // Adresse I2C du module PCF8574 (attention, cela varie suivant la configuration des broches A2/A1/A0 de cette puce)

// ========================
// Initialisation programme
// ========================
void setup() {

  // Initialisation de la liaison série (arduino nano -> PC)
  Serial.begin(9600);
  Serial.println(F("========================================================="));
  Serial.println(F("Exemple 1 (tuto PCF8574) : lecture des ENTREES P0 à P7,  "));
  Serial.println(F("                           en utilisant la librairie Wire"));
  Serial.println(F("========================================================="));
  Serial.println("");

  // Initialisation du contrôleur I2C arduino
  Wire.begin();

  // Test si la puce PCF 8574 répond bien (dans ce cas, elle renverra la valeur "0" en "endTransmission", si c'est le cas) 
  Wire.beginTransmission(adresseDeLaPucePCF8574);
  if(Wire.endTransmission() != 0) {
    Serial.print(F("Le PCF8574 ne répond pas à l'adresse 0x"));
    Serial.println(adresseDeLaPucePCF8574, HEX);
    Serial.println(F("Arrêt du programme."));
    while(1);
  }

  // Passage des toutes les E/S du PCF8574 en "entrée"
  // ... à noter que les 3 lignes suivantes ne sont pas indispensables, car c'est le mode de démarrage par défaut du PCF8574
  Wire.beginTransmission(adresseDeLaPucePCF8574);
  Wire.write(0b11111111);                             // Mise à 1 des pins P7 à P0 du PCF8574
  Wire.endTransmission();
          // Remarques :
          //    - mettre à "1" une E/S du PCF8574 revient à permettre d'utiliser cette broche en ENTRÉE
          //    - on aura tout de même une tension +Vcc présente sur cette broche, si celle-ci n'est reliée à rien
          //    - cet état haut est dit "faible", en ce sens où on peut l'amener à la masse sans créer de court-circuit
          //      (c'est l'équivalent d'une pull-up, qui serait activée sur cette broche, si vous préférez)
    
}


// =================
// Boucle principale
// =================
void loop() {

  byte reponseI2C;

  // Envoi d'une demande de lecture de données, auprès du PCF8574
  Wire.requestFrom(adresseDeLaPucePCF8574, 1);                    // Le "1" signifie qu'on envisage de lire 1 seul octet en retour

  // Récupération de l'octet en question
  if(Wire.available()) {
    reponseI2C = Wire.read();                                     // Lecture de l'octet qu'on attendait en retour
    afficheLes8bitsDeLaValeur(reponseI2C);                        // Affichage sur le moniteur série de l'IDE Arduino
                                                                            // Les "1" diront que l'entrée est à l'état haut (+Vcc, par exemple)
                                                                            // Les "0" diront que l'entrée est à l'état bas (0 volt, par exemple)
  } else {
    Serial.println(F("[ERREUR] Impossible de récupérer la valeur I2C renvoyée par le PCF8574"));
	  Serial.println(F("Arrêt du programme."));
    while(1);
  }

  // … et on reboucle à l'infini (avec une petite pause au passage, pour ne pas surcharger le moniteur série)
  delay(1000);

}
  

// =========================================================================================
// Fonction : afficheLes8bitsDeLaValeur
//    - permet d'afficher tous les 0 et 1 des 8 bits composant la valeur jointe en paramètre
// =========================================================================================
void afficheLes8bitsDeLaValeur(byte valeurAafficher) {

  // Affichage des bits un à un, sur le moniteur série
  Serial.print((valeurAafficher >> 7) & 0b00000001);      // On décale 7 fois le 8ème bit pour l'amener en position 0, puis on fait un "ET logique" pour le comparer à la valeur 1
  Serial.print((valeurAafficher >> 6) & 0b00000001);      // On décale 6 fois le 7ème bit pour l'amener en position 0, puis on fait un "ET logique" pour le comparer à la valeur 1
  Serial.print((valeurAafficher >> 5) & 0b00000001);      // On décale 5 fois le 6ème bit pour l'amener en position 0, puis on fait un "ET logique" pour le comparer à la valeur 1
  Serial.print((valeurAafficher >> 4) & 0b00000001);      // On décale 4 fois le 5ème bit pour l'amener en position 0, puis on fait un "ET logique" pour le comparer à la valeur 1
  Serial.print((valeurAafficher >> 3) & 0b00000001);      // On décale 3 fois le 4ème bit pour l'amener en position 0, puis on fait un "ET logique" pour le comparer à la valeur 1
  Serial.print((valeurAafficher >> 2) & 0b00000001);      // On décale 2 fois le 3ème bit pour l'amener en position 0, puis on fait un "ET logique" pour le comparer à la valeur 1
  Serial.print((valeurAafficher >> 1) & 0b00000001);      // On décale 1 fois le 2ème bit pour l'amener en position 0, puis on fait un "ET logique" pour le comparer à la valeur 1
  Serial.print((valeurAafficher >> 0) & 0b00000001);      // On décale 0 fois le 1er  bit pour l'amener en position 0, puis on fait un "ET logique" pour le comparer à la valeur 1
  Serial.println();

  // À noter qu'un "1" affiché indiquera que l'entrée en question est à l'état haut (et inversement : si un 0 s'affiche, c'est alors qu'elle est à l'état bas)
}

Comme vous pouvez le constater, les broches P7…P0 sont tout d’abord mises à l’état haut, pour ensuite pouvoir s’en servir en « entrée ». Ceci se fait avec la commande suivante, dans le programme : Wire.write(0b11111111).

Ensuite, on demande au PCF 8574 de nous renvoyer un octet (8 bits, donc), qui contiendra tout simplement l’état de nos 8 entrées. Ainsi fait, il nous restera plus qu’à afficher l’état de ces entrées sur le moniteur série (un « 1 » signifiant que l’entrée mesurée est à l’état haut, et un « 0 » indiquant qu’elle est à l’état bas). Et le tout, à raison d’un cycle de mesure complet, toutes les secondes !

Côté moniteur série, voici ce que j’ai obtenu de mon côté, à l’occasion de mes essais (après avoir forcé les entrées P4 et P5 à la masse, et laissé les autres à l’état haut, via leurs résistances de pull-up) :

Exemple lecture entrée PCF8574 depuis Arduino, avec affichage niveau haut ou niveau bas sur le moniteur série de l'IDE, mesures toutes les secondes

À noter que si jamais l’arduino ne trouve pas le PCF8574 à l’adresse spécifiée dans le code, alors une erreur est affichée. Pour preuve : en entrant l’adresse 0x30 dans le code, au lieu de l’adresse 0x20 (qui est l’adresse de mon PCF 8574), voici ce que l’on obtient :

Erreur adresse PCF8574 sur bus I2C détecté par programme de scan Arduino, affichage moniteur série de la valeur erronée, lors du test du code

À présent, refaisons le même montage, mais en utilisant cette fois-ci la librairie PCF8574, disponible sous l’IDE Arduino (via le gestionnaire de bibliothèques).

Code arduino #2 : lecture du niveau d’entrée des broches P7 à P0, cette fois-ci avec la librairie PCF8574.h

Dans l’exemple précédent, nous avons vu comment lire les entrées du PCF8574, en utilisant la libraire Wire de l’IDE Arduino. C’était efficace, certes, mais pas très explicite au niveau du code. Du coup, ce programme serait sans doute difficile à reprendre (ou à comprendre), ne serait-ce que quelques semaines ou mois plus tard. C’est pourquoi je vais à présent vous montrer une façon bien plus simple, et plus parlante, de faire les choses 😉

Au niveau du montage support à cet exemple, nous allons repartir sur le schéma précédent (celui de l’exemple #1). Voici ce que ça donne, câblé sur breadboard, de mon côté :

Câblage PCF 8574 sur Arduino type Nano, avec microswitch de test des lignées P0 à P7 pour mise à la masse GND, sinon pull-up 10k en réseau intégré

En fait, les changements vont uniquement se porter ici sur la partie logicielle. Car au lieu de nous servir de la bibliothèque « Wire.h », nous allons faire appel à la librairie « PCF8574.h » (dont, pour rappel, vous trouverez les explications d’installation dans la partie 7, nommée « Quelle librairie utiliser ? »).

Et le nouveau code de programmation, mettant en œuvre cette librairie, est le suivant :

/*
   ______               _                  _///_ _           _                   _
  /   _  \             (_)                |  ___| |         | |                 (_)
  |  [_|  |__  ___  ___ _  ___  _ __      | |__ | | ___  ___| |_ _ __ ___  _ __  _  ___  _   _  ___
  |   ___/ _ \| __|| __| |/ _ \| '_ \_____|  __|| |/ _ \/  _|  _| '__/   \| '_ \| |/   \| | | |/ _ \
  |  |  | ( ) |__ ||__ | | ( ) | | | |____| |__ | |  __/| (_| |_| | | (_) | | | | | (_) | |_| |  __/
  \__|   \__,_|___||___|_|\___/|_| [_|    \____/|_|\___|\____\__\_|  \___/|_| |_|_|\__  |\__,_|\___|
                                                                                      | |
                                                                                      \_|
  Fichier :       prg2-LectureDesEntreesDuPCF8574-AvecLibrairieIDEarduino.ino
  
  Description :   Programme permettant de lire le niveau des entrées P7 à P0 d'un module PCF 8574, en utilisant la
                  librairie "PCF8574" de Renzo Mischianti (téléchargeable depuis le gestionnaire de bibliothèque arduino)
                  
  Auteur :        Jérôme TOMSKI (https://passionelectronique.fr/)
  Créé le :       26.06.2022

*/

#include <PCF8574.h>
#define adresseDuModulePCF8574 0x20           // Adresse i2c du PCF8574 (attention : dépend de la configuration des broches A2/A1/A0 de cette puce)

PCF8574 pcf8574(adresseDuModulePCF8574);

// ========================
// Initialisation programme
// ========================
void setup() {

  // Initialisation de la liaison série (pour communication : arduino -> PC)
  Serial.begin(9600);
  Serial.println(F("===================================================================="));
  Serial.println(F("Exemple 2 (tuto PCF8574) : lecture des ENTREES P7 à P0, en utilisant"));
  Serial.println(F("                           une librairie disponible sous Arduino IDE"));
  Serial.println(F("===================================================================="));
  Serial.println("");

  // Définition des E/S P7 à P0 du PCF8574 en ENTRÉE
  //      Nota : cela DOIT précéder l'initialisation du PCF8574 qui suit, utilisant la fonction begin (ceci est spécifique à cette librairie)
  pcf8574.pinMode(P0, INPUT);
  pcf8574.pinMode(P1, INPUT);
  pcf8574.pinMode(P2, INPUT);
  pcf8574.pinMode(P3, INPUT);
  pcf8574.pinMode(P4, INPUT);
  pcf8574.pinMode(P5, INPUT);
  pcf8574.pinMode(P6, INPUT);
  pcf8574.pinMode(P7, INPUT);

  // Initialisation du PCF8574
  Serial.print(F("Initialisation du pcf8574 : "));
  if (pcf8574.begin()){
    Serial.println(F("REUSSIE"));
    Serial.println("");
  } else {
    Serial.println(F("ECHEC"));
    Serial.println(F("Arrêt du programme."));
    while(1);
  }

}


// =================
// Boucle principale
// =================
void loop() {

  // Lecture des entrées
  uint8_t valP0 = pcf8574.digitalRead(P0);
  uint8_t valP1 = pcf8574.digitalRead(P1);
  uint8_t valP2 = pcf8574.digitalRead(P2);
  uint8_t valP3 = pcf8574.digitalRead(P3);
  uint8_t valP4 = pcf8574.digitalRead(P4);
  uint8_t valP5 = pcf8574.digitalRead(P5);
  uint8_t valP6 = pcf8574.digitalRead(P6);
  uint8_t valP7 = pcf8574.digitalRead(P7);

  // Affichage des valeurs sur le port série
  Serial.print(valP7);
  Serial.print(valP6);
  Serial.print(valP5);
  Serial.print(valP4);
  Serial.print(valP3);
  Serial.print(valP2);
  Serial.print(valP1);
  Serial.print(valP0);
  Serial.println("");         // Retour à la ligne

  // On attend un peu, puis on reboucle !
  delay(1000);
  
}

Vous noterez la simplicité d’écriture des lignes de code, comparé à l’exemple précédent. Car au final, on utilise les « nouvelles entrées » du PCF8574 à l’image de celles présentes sur nos Arduino (ou presque !). En effet :

  • la fonction PCF8574 « pinMode » permet de dire si va utiliser telle ou telle broche en entrée ou sortie
  • la fonction PCF8574 « digitalRead » permet de lire l’état d’une entrée en particulier

Si vous uploadé ce code dans votre Arduino, câblé comme présenté ci-dessus, vous devriez alors obtenir des infos périodiques sur l’état des entrées du PCF 8574, sur le moniteur série de l’IDE Arduino. D’ailleurs, voici ce que cela donne de mon côté :

Exemple mesure PCF8574 inputs avec codage arduino, lecture chaque second de l'état logique des entrées, et affichage des 0 et 1 sur moniteur série

Nota : ici, j’avais forcé les entrées P5 et P4 à la masse (via les microswitchs), tandis que les autres entrées (P7, P6, P3, P2, P1, et P0) étaient simplement reliées à +Vcc, via leurs résistances de pull-up respectives.

Comme toujours : en cas de problème d’adresse au niveau du PCF8574, un message d’erreur vous signalera tout problème (comme visible ci-dessous).

Exemple problème I2C sur adresse PCF 8574, détecté par programmation arduino, depuis IDE avec affichage sur moniteur série de l'échec de démarrage

Pour info, les composants utilisés ont été :

Code arduino #3 : faire clignoter une LED (blink) avec la librairie Wire

Maintenant que nous avons vu comment « transformer » les broches P0 à P7 en entrées, nous allons voir comment les faire passer en sortie. En effet, cet exemple-ci vous montre comment paramétrer une broche du PCF8574 en sortie, afin de pouvoir faire clignoter une LED (le fameux programme « blink », qu’on exécute de base avec un Arduino ou autre !).

Comme support exemple, je vous propose de réaliser le schéma suivant, qui met en œuvre un Arduino Nano, un PCF 8574, et une LED (branchée sur la broche P0) :

PCF8574 blink arduino pour faire clignoter une LED branchée sur sortie P0 à P7, avec résistance de limitation de courant, et schéma de raccordement

Le principe de fonctionnement est simple :

  • la LED s’allumera quand on fera passer la sortie P0 à l’état bas (puisqu’elle est branchée « à l’envers »)
  • la LED s’éteindra quand on fera passer la sortie P0 à l’état haut

Pour rappel, si j’ai fait ce choix de branchement, c’est parce qu’un PCF 8574 ne peut délivrer que peu de courant à l’état haut, tandis qu’il peut drainer beaucoup plus de courant à l’état bas. D’où le sens de raccordement « inverse ».

Au niveau du code, voici comment cela se traduit, en utilisant la librairie Wire, native dans Arduino IDE :

/*
   ______               _                  _///_ _           _                   _
  /   _  \             (_)                |  ___| |         | |                 (_)
  |  [_|  |__  ___  ___ _  ___  _ __      | |__ | | ___  ___| |_ _ __ ___  _ __  _  ___  _   _  ___
  |   ___/ _ \| __|| __| |/ _ \| '_ \_____|  __|| |/ _ \/  _|  _| '__/   \| '_ \| |/   \| | | |/ _ \
  |  |  | ( ) |__ ||__ | | ( ) | | | |____| |__ | |  __/| (_| |_| | | (_) | | | | | (_) | |_| |  __/
  \__|   \__,_|___||___|_|\___/|_| [_|    \____/|_|\___|\____\__\_|  \___/|_| |_|_|\__  |\__,_|\___|
                                                                                      | |
                                                                                      \_|
  Fichier :       prg3-BlinkSurLaSortieP0duPCF8574-AvecLibrairieWire.ino
  
  Description :   Programme permettant de faire clignoter une led (blink) toutes les secondes,
                  sur la sortie P0 d'un PCF 8574 (en utilisant la librairie Wire uniquement)
                  
  Auteur :        Jérôme TOMSKI (https://passionelectronique.fr/)
  Créé le :       26.06.2022

*/

#include <Wire.h>
#define adresseDeLaPucePCF8574 0x20           // Adresse I2C du module PCF8574
                                              //      (attention : cela varie selon la configuration des broches A2, A1, et A0 de cette puce)

// ========================
// Initialisation programme
// ========================
void setup() {

  // Initialise la liaison série (Arduino Nano -> PC)
  Serial.begin(9600);
  Serial.println(F("==================================================================="));
  Serial.println(F("Exemple 3 (tuto PCF8574) : blink (clignotement) de la SORTIE P0,   "));
  Serial.println(F("                           en utilisant seulement la librairie Wire"));
  Serial.println(F("==================================================================="));
  Serial.println("");

  // Initialise le contrôleur I2C arduino
  Wire.begin();

  // Teste la présence de la puce PCF 8574 (si elle est bien connectée, elle renverra la valeur "0" à l'appel de "endTransmission") 
  Wire.beginTransmission(adresseDeLaPucePCF8574);
  if(Wire.endTransmission() != 0) {
    Serial.print(F("Le module PCF8574 ne répond pas à l'adresse 0x"));
    Serial.println(adresseDeLaPucePCF8574, HEX);
    Serial.println(F("Arrêt du programme."));
    while(1);
  }
      
}


// =================
// Boucle principale
// =================
void loop() {

  // Allumage de la LED
  Serial.println(F("Allumage de la LED …"));
  Wire.beginTransmission(adresseDeLaPucePCF8574);
    // Fixation du niveau des pins P7, P6, P5, P4, P3, P2, P1 à un niveau quelconque (j'ai mis "1" ici, pour qu'elles soient toutes par défaut au niveau haut)
    // Fixation du niveau de la pin P0 à "0", pour avoir un niveau bas, pour commencer
  Wire.write(0b11111110);                             // Mise à 1 des pins P7 à P1 ; et mise à 0 de la pin P0 <==== la LED s'allume
  Wire.endTransmission();

  // Puis pause d'une demi seconde (500 ms)
  delay(500);

  // Extinction de la LED
  Serial.println(F("… et extinction !"));
  Wire.beginTransmission(adresseDeLaPucePCF8574);
    // Remodification de la pin P0, pour la passer à "1" cette fois-ci (on garde toutes les autres à 1 ici aussi, dans cet exemple)
  Wire.write(0b11111111);                             // Mise à 1 des pins P7 à P1 ; et mise à 1 de la pin P0 <==== la LED s'éteint
  Wire.endTransmission();
  
  // Et on reboucle à l'infini, en reprenant une pause d'une 1/2 seconde (500 ms) une seconde fois
  Serial.println("");
  delay(500);

}

Une fois uploadé dans votre Arduino, vous devriez voir la LED clignoter, une fois par seconde. À noter que si vous ouvrez parallèlement votre moniteur série, vous devriez voir s’afficher des messages, signifiant quand les consignes d’allumage et d’extinction sont envoyées à la LED, au travers du PCF8574. Voici d’ailleurs ce que cela donne, de mon côté :

Test blink PCF 8574 sur moniteur I2C Arduino, visionnage clignotement LED toutes les secondes, sur pin configurée en sortie logique, active à l'état bas

Avec au passage, une photo du montage que j’ai réalisé sur breadboard, pour faire ces essais :

Montage test PCF8574 clignotement led sur breadboard, pour vérifier fonctionnement programme Arduino et câblage sortie inversée

Au niveau des composants mis en œuvre dans cet exemple, figurent :

Code arduino #4 : réaliser un chenillard avec 2 x PCF8574 chaînés

Histoire de varier les plaisirs, je vous propose à présent de réaliser un chenillard à 16 leds, en utilisant 2 modules PCF8574. Ces seize leds seront en fait 2 bargraphes de 8 leds, pour éviter le nombre de fils à mettre en œuvre, lorsqu’on câble tout ça sur breadboard !

Du coup, nous allons utiliser ici :

  • 2 modules PCF8574, au lieu d’un seul
  • piloter 16 sorties, réparties sur 2 modules
  • et utiliser la librairie PCF8574.h, pour simplifier le codage arduino

Pour concevoir ce chenillard, voici le schéma électronique que je vous propose :

Chenillard arduino avec plusieurs modules PCF8574 branchés en série, afin de faire allumer les LED les unes à la suite des autres, avec schéma fils câblage

Pour info, les composants utilisés dans cet exemple-ci sont :

Comme toujours, chaque LED s’allumera lorsque sa sortie correspondante passera à 0V. Pour rappel, cela est, pour ainsi dire, imposé par le fait qu’un PCF 8574 ne peut délivrer que peu de courant à l’état haut, tandis qu’il peut recevoir « beaucoup » de courant, à l’état bas (d’où le sens de branchement de ces leds).

Côté programme arduino, voici ce qui va donner vie à notre chenillard :

/*
   ______               _                  _///_ _           _                   _
  /   _  \             (_)                |  ___| |         | |                 (_)
  |  [_|  |__  ___  ___ _  ___  _ __      | |__ | | ___  ___| |_ _ __ ___  _ __  _  ___  _   _  ___
  |   ___/ _ \| __|| __| |/ _ \| '_ \_____|  __|| |/ _ \/  _|  _| '__/   \| '_ \| |/   \| | | |/ _ \
  |  |  | ( ) |__ ||__ | | ( ) | | | |____| |__ | |  __/| (_| |_| | | (_) | | | | | (_) | |_| |  __/
  \__|   \__,_|___||___|_|\___/|_| [_|    \____/|_|\___|\____\__\_|  \___/|_| |_|_|\__  |\__,_|\___|
                                                                                      | |
                                                                                      \_|
  Fichier :       prg4-ChenillardAvecDoublePCF8574-AvecLibrairieIDEarduino.ino
  
  Description :   Programme permettant de faire un chenillard avec 2 bargraphes de 8 leds (donc 16 leds au total),
                  en utilisant 2 x PCF8574 et une librairie disponible dans le gestionnaire de bibliothèques arduino (celle de Renzo Mischianti)
                  
  Auteur :        Jérôme TOMSKI (https://passionelectronique.fr/)
  Créé le :       26.06.2022

*/

#include <PCF8574.h>
#define adresseDu1erModulePCF8574 0x20    // Adresse i2c du 1er module PCF8574 (0x20), en configurant les entrées de cette puce de la sorte : A2=0  A1=0  A0=0
#define adresseDu2ndModulePCF8574 0x21    // Adresse i2c du 2nd module PCF8574 (0x21), en configurant les entrées de cette puce de la sorte : A2=0  A1=0  A0=1

PCF8574 premierPCF8574(adresseDu1erModulePCF8574);
PCF8574 deuxiemePCF8574(adresseDu2ndModulePCF8574);

// ========================
// Initialisation programme
// ========================
void setup() {

  // Initialisation de la liaison série (communication arduino -> PC)
  Serial.begin(9600);
  Serial.println(F("======================================================================="));
  Serial.println(F("Exemple 4 (tuto PCF8574) : chenillard à 16 LEDS, illustrant le pilotage"));
  Serial.println(F("                           de 2 x PCF8574 branchés 'en série'          "));
  Serial.println(F("======================================================================="));
  Serial.println("");

  // Configuration des 8 broches P0..P7 en SORTIES, sur le premier PCF8574 (et mise à l'état haut, dans la foulée)
  premierPCF8574.pinMode(P0, OUTPUT, HIGH);
  premierPCF8574.pinMode(P1, OUTPUT, HIGH);
  premierPCF8574.pinMode(P2, OUTPUT, HIGH);
  premierPCF8574.pinMode(P3, OUTPUT, HIGH);
  premierPCF8574.pinMode(P4, OUTPUT, HIGH);
  premierPCF8574.pinMode(P5, OUTPUT, HIGH);
  premierPCF8574.pinMode(P6, OUTPUT, HIGH);
  premierPCF8574.pinMode(P7, OUTPUT, HIGH);

  // Configuration des 8 broches P0..P7 en SORTIES, sur le second PCF8574 (et mise à l'état haut, dans la foulée)
  deuxiemePCF8574.pinMode(P0, OUTPUT, HIGH);
  deuxiemePCF8574.pinMode(P1, OUTPUT, HIGH);
  deuxiemePCF8574.pinMode(P2, OUTPUT, HIGH);
  deuxiemePCF8574.pinMode(P3, OUTPUT, HIGH);
  deuxiemePCF8574.pinMode(P4, OUTPUT, HIGH);
  deuxiemePCF8574.pinMode(P5, OUTPUT, HIGH);
  deuxiemePCF8574.pinMode(P6, OUTPUT, HIGH);
  deuxiemePCF8574.pinMode(P7, OUTPUT, HIGH);

  // Initialisation du 1er PCF8574
  Serial.print(F("Initialisation du 1er PCF8574 à l'adresse [0x"));
  Serial.print(adresseDu1erModulePCF8574, HEX);
  Serial.print(F("] : "));
  if (premierPCF8574.begin()){
    Serial.println(F("réussie !"));
  } else {
    Serial.println(F("échec…"));
    Serial.println(F("Arrêt du programme."));
    while(1);
  }

  // Initialisation du 2nd PCF8574
  Serial.print(F("Initialisation du 2nd PCF8574 à l'adresse [0x"));
  Serial.print(adresseDu2ndModulePCF8574, HEX);
  Serial.print(F("] : "));
  if (deuxiemePCF8574.begin()){
    Serial.println(F("réussie !"));
  } else {
    Serial.println(F("échec…"));
    Serial.println(F("Arrêt du programme."));
    while(1);
  }

  // Fin des initialisations, passage à la boucle LOOP
  Serial.println("");

}


// =================
// Boucle principale
// =================
void loop() {

  // Définition de la vitesse du chenillard (on fera "avancer" la LED éclairée toutes les 100 ms, par défaut)
  int dureeDavancement = 100;     

  // Pas 1 sur 16
  deuxiemePCF8574.digitalWrite(P0, HIGH);   // Extinction de la LED #16     <--- ligne inutile au 1er tour, mais indispensable aux loop suivants
  premierPCF8574.digitalWrite(P7, LOW);     // Allumage de la LED #1
  delay(dureeDavancement);                  // Pause avant de passer à la suite

  // Pas 2 sur 16
  premierPCF8574.digitalWrite(P7, HIGH);    // Extinction de la LED #1
  premierPCF8574.digitalWrite(P6, LOW);     // Allumage de la LED #2
  delay(dureeDavancement);                  // Pause avant de passer à la suite
 
  // Pas 3 sur 16
  premierPCF8574.digitalWrite(P6, HIGH);    // Extinction de la LED #2
  premierPCF8574.digitalWrite(P5, LOW);     // Allumage de la LED #3
  delay(dureeDavancement);                  // Pause avant de passer à la suite

  // Pas 4 sur 16
  premierPCF8574.digitalWrite(P5, HIGH);    // Extinction de la LED #3
  premierPCF8574.digitalWrite(P4, LOW);     // Allumage de la LED #4
  delay(dureeDavancement);                  // Pause avant de passer à la suite
  
  // Pas 5 sur 16
  premierPCF8574.digitalWrite(P4, HIGH);    // Extinction de la LED #4
  premierPCF8574.digitalWrite(P3, LOW);     // Allumage de la LED #5
  delay(dureeDavancement);                  // Pause avant de passer à la suite
  
  // Pas 6 sur 16
  premierPCF8574.digitalWrite(P3, HIGH);    // Extinction de la LED #5
  premierPCF8574.digitalWrite(P2, LOW);     // Allumage de la LED #6
  delay(dureeDavancement);                  // Pause avant de passer à la suite

  // Pas 7 sur 16
  premierPCF8574.digitalWrite(P2, HIGH);    // Extinction de la LED #6
  premierPCF8574.digitalWrite(P1, LOW);     // Allumage de la LED #7
  delay(dureeDavancement);                  // Pause avant de passer à la suite

  // Pas 8 sur 16
  premierPCF8574.digitalWrite(P1, HIGH);    // Extinction de la LED #7
  premierPCF8574.digitalWrite(P0, LOW);     // Allumage de la LED #8
  delay(dureeDavancement);                  // Pause avant de passer à la suite

  // Pas 9 sur 16
  premierPCF8574.digitalWrite(P0, HIGH);    // Extinction de la LED #8
  deuxiemePCF8574.digitalWrite(P7, LOW);    // Allumage de la LED #9
  delay(dureeDavancement);                  // Pause avant de passer à la suite

  // Pas 10 sur 16
  deuxiemePCF8574.digitalWrite(P7, HIGH);   // Extinction de la LED #9
  deuxiemePCF8574.digitalWrite(P6, LOW);    // Allumage de la LED #10
  delay(dureeDavancement);                  // Pause avant de passer à la suite

  // Pas 11 sur 16
  deuxiemePCF8574.digitalWrite(P6, HIGH);   // Extinction de la LED #10
  deuxiemePCF8574.digitalWrite(P5, LOW);    // Allumage de la LED #11
  delay(dureeDavancement);                  // Pause avant de passer à la suite
  
  // Pas 12 sur 16
  deuxiemePCF8574.digitalWrite(P5, HIGH);   // Extinction de la LED #11
  deuxiemePCF8574.digitalWrite(P4, LOW);    // Allumage de la LED #12
  delay(dureeDavancement);                  // Pause avant de passer à la suite

  // Pas 13 sur 16
  deuxiemePCF8574.digitalWrite(P4, HIGH);   // Extinction de la LED #12
  deuxiemePCF8574.digitalWrite(P3, LOW);    // Allumage de la LED #13
  delay(dureeDavancement);                  // Pause avant de passer à la suite

  // Pas 14 sur 16
  deuxiemePCF8574.digitalWrite(P3, HIGH);   // Extinction de la LED #13
  deuxiemePCF8574.digitalWrite(P2, LOW);    // Allumage de la LED #14
  delay(dureeDavancement);                  // Pause avant de passer à la suite

  // Pas 15 sur 16
  deuxiemePCF8574.digitalWrite(P2, HIGH);   // Extinction de la LED #14
  deuxiemePCF8574.digitalWrite(P1, LOW);    // Allumage de la LED #15
  delay(dureeDavancement);                  // Pause avant de passer à la suite
  
  // Pas 16 sur 16
  deuxiemePCF8574.digitalWrite(P1, HIGH);   // Extinction de la LED #15
  deuxiemePCF8574.digitalWrite(P0, LOW);    // Allumage de la LED #16
  delay(dureeDavancement);                  // Pause avant de passer à la suite
  
  
  // Puis on reboucle !
  
}

Comme vous le constaterez certainement, l’utilisation de la librairie « PCF8574.h » simplifie grandement le codage (comparé à la librairie Wire, j’entends). En effet, les instructions sont bien claires et explicites, malgré le nombre de lignes à écrire.

Comme toujours, le moniteur série Arduino donne des informations sur l’initialisation des modules PCF 8574 (réussite ou échec de communication i2c). D’ailleurs, voici un exemple de retour série, en cas d’erreur d’adressage i2c (exemple avec un PCF8574 ayant bien 0x20 comme adresse, et un second n’ayant pas l’adresse 0x21) :

Détecteur problème I2C d'un PCF 8574 depuis programme exemple arduino, avec affichage série des erreurs et informations sur valeurs saisies sur bus

Sinon, si tout va bien, vous devriez voir une LED s’allumer à la fois, partant de la gauche pour aller vers la droite, et rebouclant ainsi à l’infini !

Bargraphe PCF8574 piloté par Arduino, avec 16 sorties supplémentaires branchés sur LED, afin de réaliser un chenillard lumineux, contrôlé en i2c

Code arduino #5 : prendre en compte les interruptions émanant d’un PCF 8574 (librairie Wire)

Une chose que je n’avais pas encore abordé en pratique, est le fait que le PCF8574 nous met à disposition une sortie d’interruption, noté INT. Celle-ci nous signale tout changement d’état au niveau des broches P0 à P7, lorsque celles-ci sont configurées en ENTRÉE.

Cette broche INT est active à l’état bas. C’est à dire qu’elle sera :

  • mise à 0 volt un instant, pour signaler un changement d’état au niveau des entrées
  • mise à +Vcc le reste du temps, pour signifier qu’il y a eu aucun changement depuis

À noter que le +Vcc sur la sortie /INT n’est pas fourni par le PCF 8574 en lui-même. En effet, en pratique, il faudra mettre en place une résistance de pull-up, pour formaliser cet état (étant donné que la sortie INT est de type « à drain ouvert »).

Pour vous montrer comment exploiter cette ligne d’interruption, nommée INT, voici le montage que je vous propose d’étudier ensemble :

Schéma capture interruption PCF8574 avec Arduino, pull-up interne utilisée sur Nano, avec test exemple de détection de changement des entrées surveillées

À peu de choses près, il s’agit ni plus ni moins que de notre tout premier montage (cf. exemple #1), auquel nous avons rajouté un fil, allant de la sortie /INT du PCF8574, à l’entrée D2 de notre Arduino.

Nota : la résistance de pull-up, indispensable au bon fonctionnement de la ligne INT, est absente sur ce schéma. Mais ce n’est pas un oubli. Car nous allons ici simplement activer la résistance pull-up interne de l’Arduino sur la broche D2, ce qui nous permettra de nous passer d’un composant externe supplémentaire.

Côté programme, voici des lignes de codes qui vont vous montrer comment exploiter les signaux d’interruptions, issues du PCF 8574 (et utilisant simplement la bibliothèque Wire, native sous l’IDE Arduino) :

/*
   ______               _                  _///_ _           _                   _
  /   _  \             (_)                |  ___| |         | |                 (_)
  |  [_|  |__  ___  ___ _  ___  _ __      | |__ | | ___  ___| |_ _ __ ___  _ __  _  ___  _   _  ___
  |   ___/ _ \| __|| __| |/ _ \| '_ \_____|  __|| |/ _ \/  _|  _| '__/   \| '_ \| |/   \| | | |/ _ \
  |  |  | ( ) |__ ||__ | | ( ) | | | |____| |__ | |  __/| (_| |_| | | (_) | | | | | (_) | |_| |  __/
  \__|   \__,_|___||___|_|\___/|_| [_|    \____/|_|\___|\____\__\_|  \___/|_| |_|_|\__  |\__,_|\___|
                                                                                      | |
                                                                                      \_|
  Fichier :       prg5-InterruptionDepuisPCF8574-AvecLibrairieWire.ino
  
  Description :   Programme permettant de faire clignoter une led (blink) toutes les secondes,
                  sur la sortie P0 d'un PCF 8574 (en utilisant la librairie Wire uniquement)
                  
  Auteur :        Jérôme TOMSKI (https://passionelectronique.fr/)
  Créé le :       27.06.2022

*/

#include <Wire.h>

#define adresseDeLaPucePCF8574 0x20                   // Adresse I2C du module PCF8574 (défini par le niveau de ses broches d'adresse A0, A1, et A2)
#define brocheArduinoDeDeclenchementInterruption  2   // La broche D2 permettra au PCF8574 "d'interrompre" l'arduino, à tout moment
                                                                // Nota 1 : l'interruption est active à l'état bas
                                                                // Nota 2 : une résistance de pull-up est nécessaire ici (on activera celle interne à l'arduino, sur la pin D2)

volatile bool interruptionDeclenchee = false;         // Variable qui mémorisera le fait qu'une interruption s'est déclenché
                                                                // Remarque : celle-ci est de type volatile, pour être disponible DANS et HORS de la routine d'interruption

// ========================
// Initialisation programme
// ========================
void setup() {

  // Initialisation de la liaison série (Arduino Nano -> PC)
  Serial.begin(9600);
  Serial.println(F("==============================================================="));
  Serial.println(F("Exemple 5 (tuto PCF8574) : interruption générée par un PCF8574 "));
  Serial.println(F("                           (utilisation de librairie Wire, ici)"));
  Serial.println(F("==============================================================="));
  Serial.println("");

  // Initialisation du contrôleur i2c Arduino
  Wire.begin();

  // Vérification de la présence du PCF 8574 (si il est bien connecté, il renverra la valeur "0" à l'appel de "endTransmission") 
  Wire.beginTransmission(adresseDeLaPucePCF8574);
  if(Wire.endTransmission() != 0) {
    Serial.print(F("Le PCF8574 ne répond pas à l'adresse 0x"));
    Serial.println(adresseDeLaPucePCF8574, HEX);
    Serial.println(F("Arrêt du programme."));
    while(1);
  }

  // On met toutes les broches P0 à P7 à l'état haut, pour que celles-ci puissent fonctionner en entrée
  Wire.beginTransmission(adresseDeLaPucePCF8574);
  Wire.write(0b11111111);     // Chaque "1" représente respectivement P7, P6, P5, P4, P3, P2, P1, et P0
  Wire.endTransmission();
  delay(500);                 // Petite pause avant d'activer les interruptions

  // Activation de la pull-up, sur l'entrée d'interruption arduino choisie
  pinMode(brocheArduinoDeDeclenchementInterruption, INPUT_PULLUP);

  // Définition de cette pin comme "entrée d'interruption programme" (activation à chaque "FALLING", donc sur front descendant du signal)
  attachInterrupt(digitalPinToInterrupt(brocheArduinoDeDeclenchementInterruption), ROUTINE_D_INTERRUPTION, FALLING);

}

// ======================
// Routine d'interruption
// ======================
void ROUTINE_D_INTERRUPTION() {
  interruptionDeclenchee = true;
  Serial.println("Routine d'interruption exécutée");

  // À noter que je n'ai pas mis ici de code "anti-rebond", pour ne pas alourdir le programme
}

// =================
// Boucle principale
// =================
void loop() {

  // On ne fait rien ici, sauf lorsqu'une interruption a été déclenchée (ce qu'on sait quand la variable booléenne ci-dessus est à VRAIE)
  if(interruptionDeclenchee) {
    Wire.requestFrom(adresseDeLaPucePCF8574, 1);    // On interroge le PCF8574, en lui demandant de nous retourner 1 octet (qui contiendra l'état des broches P0 à P7)

    if(Wire.available()) {
      byte reponseDuPCF8574 = Wire.read();
      Serial.print(F("Réponse du PCF8574 = "));
      Serial.println(reponseDuPCF8574, BIN);

      // On affiche quelle broche est à l'origine de l'interruption (remarque : ne prend pas en compte les appuis simultanés)
      if(reponseDuPCF8574 == 0b01111111)  Serial.println(F("  ==> Interruption depuis la broche P7"));
      if(reponseDuPCF8574 == 0b10111111)  Serial.println(F("  ==> Interruption depuis la broche P6"));
      if(reponseDuPCF8574 == 0b11011111)  Serial.println(F("  ==> Interruption depuis la broche P5"));
      if(reponseDuPCF8574 == 0b11101111)  Serial.println(F("  ==> Interruption depuis la broche P4"));
      if(reponseDuPCF8574 == 0b11110111)  Serial.println(F("  ==> Interruption depuis la broche P3"));
      if(reponseDuPCF8574 == 0b11111011)  Serial.println(F("  ==> Interruption depuis la broche P2"));
      if(reponseDuPCF8574 == 0b11111101)  Serial.println(F("  ==> Interruption depuis la broche P1"));
      if(reponseDuPCF8574 == 0b11111110)  Serial.println(F("  ==> Interruption depuis la broche P0"));
      if(reponseDuPCF8574 == 0b11111111)  Serial.println(F("  ==> Toutes les entrées sont 'relâchées'"));

      Serial.println("");
    }

    // Et on reset l'indicateur de détection d'interruption, pour capter la prochaine
    interruptionDeclenchee = false;
  }

}

Vous remarquerez plusieurs choses dans ce code :

  • les broches P7 à P0 ont été mises à l’état haut, pour s’en servir comme « entrée » (pour rappel, c’est ainsi qu’il faut procéder, avec ces entrées/sorties « quasi-bidirectionnelles »)
  • la résistance pull-up, interne à l’arduino, a été activée sur l’entrée D2 (qui recevra le signal /INT issu du PCF8574)
  • une fonction d’interruption arduino, rattachée à cette entrée D2, s’activera sur chaque front descendant détecté

Côté fonctionnel, ce programme passe son temps à surveiller si une interruption a été déclenchée ou non (en checkant la variable « interruptionDeclenchee »), et affiche l’état des entrées le cas échéant. À noter que cette variable « interruptionDeclenchee » est de type « volatile », afin qu’elle soit accessible aussi bien dans le programme principal, que dans la routine d’interruption.

Une fois ce programme uploadé dans votre arduino, vous devriez voir des infos s’afficher sur le moniteur série. Voici d’ailleurs ce que j’ai obtenu de mon côté, pendant mes essais :

Liste interruptions générées par PCF8574 dans moniteur série Arduino, à l'exécution d'un programme de test de surveillance des entrées

Remarques :

  • ce programme ne fonctionne bien que si une seule des entrées n’est active à la fois (pour ne pas compliquer le code, mais il suffirait de l’adapter au besoin)
  • ce programme n’a aucun dispositif anti-rebond ici, ce qui peut faire que certaines interruptions soient déclenchées plusieurs fois, pour un seul et même basculement d’interrupteur (au niveau des microswitchs, j’entends)
  • le PCF8574 déclenche une interruption au démarrage (lorsqu’on configure ses broches en « entrées »), c’est pourquoi j’ai rajouté une tempo d’une demi-seconde dans la fonction setup, pour la filtrer

Code arduino #6 : afficher l’état des entrées/sorties à chaque interruption (librairie pcf8574.h)

Un dernier exemple pour la route, pour ceux qui préféreraient utiliser la librairie PCF8574.h, plutôt que la librairie Wire, pour gérer les interruptions. Pour ce faire, nous allons reprendre le montage précédent, qui ressemble à ceci, une fois câblé sur breadboard :

Raccordement PCF8574 ARDUINO, avec fil de câblage d'interruption, et système d'indication périodique d'état des entrées toutes les secondes

Au niveau du codage, cela devient :

/*
   ______               _                  _///_ _           _                   _
  /   _  \             (_)                |  ___| |         | |                 (_)
  |  [_|  |__  ___  ___ _  ___  _ __      | |__ | | ___  ___| |_ _ __ ___  _ __  _  ___  _   _  ___
  |   ___/ _ \| __|| __| |/ _ \| '_ \_____|  __|| |/ _ \/  _|  _| '__/   \| '_ \| |/   \| | | |/ _ \
  |  |  | ( ) |__ ||__ | | ( ) | | | |____| |__ | |  __/| (_| |_| | | (_) | | | | | (_) | |_| |  __/
  \__|   \__,_|___||___|_|\___/|_| [_|    \____/|_|\___|\____\__\_|  \___/|_| |_|_|\__  |\__,_|\___|
                                                                                      | |
                                                                                      \_|
  Fichier :       prg6-InterruptionDepuisPCF8574-AvecLibrairieIDEarduino.ino
  
  Description :   Programme permettant à un arduino de capter les interruptions envoyées depuis le PCF8574, en utilisant
                  la librairie PCF8574 (celle de Renzo Mischianti), disponible dans le gestionnaire de bibliothèques arduino
                  
  Auteur :        Jérôme TOMSKI (https://passionelectronique.fr/)
  Créé le :       26.06.2022

*/

#include <PCF8574.h>
#define adresseDuModulePCF8574                          0x20    // Adresse i2c du module PCF8574
#define brocheArduinoRecevantLesDemandesDinterruption      2    // La broche D2 de notre Arduino recevra les interruptions générées par le PCF8574

void routineDinterruption();    // Fonction exécutée à chaque interruption (sera détaillée plus loin ; ici, il ne s'agit juste que de sa déclaration)

PCF8574 modulePCF8574(adresseDuModulePCF8574, brocheArduinoRecevantLesDemandesDinterruption, routineDinterruption);

volatile bool interruptionAgerer = false;

// ========================
// Initialisation programme
// ========================
void setup() {

  // Initialisation de la liaison série ( arduino -> PC)
  Serial.begin(9600);
  Serial.println(F("================================================================================="));
  Serial.println(F("Exemple 6 (tuto PCF8574) : gestion des interruptions issues d'un PCF8574, depuis "));
  Serial.println(F("                           un Arduino Nano, en utilisant la librairie PCF8574.h  "));
  Serial.println(F("================================================================================="));
  Serial.println("");

  // Configuration des 8 broches P0..P7 en ENTRÉES (en pratique, ces broches sont simplement mises au niveau haut)
  modulePCF8574.pinMode(P0, INPUT);
  modulePCF8574.pinMode(P1, INPUT);
  modulePCF8574.pinMode(P2, INPUT);
  modulePCF8574.pinMode(P3, INPUT);
  modulePCF8574.pinMode(P4, INPUT);
  modulePCF8574.pinMode(P5, INPUT);
  modulePCF8574.pinMode(P6, INPUT);
  modulePCF8574.pinMode(P7, INPUT);

  // Initialisation du PCF8574
  Serial.print(F("Initialisation du PCF8574 à l'adresse [0x"));
  Serial.print(adresseDuModulePCF8574, HEX);
  Serial.print(F("] : "));
  if (modulePCF8574.begin()){
    Serial.println(F("réussie !"));
  } else {
    Serial.println(F("échec…"));
    Serial.println(F("Arrêt du programme."));
    while(1);
  }

  // Fin des initialisations, passage à la boucle LOOP
  delay(500);
  Serial.println("");

}


// =================
// Boucle principale
// =================
void loop() {

  if(interruptionAgerer) {
    // Lecture de toutes les entrées du PCF8574
    PCF8574::DigitalInput entreeDuPCF8574 = modulePCF8574.digitalReadAll();

    // Affichage de l'état de toutes les entrées
    Serial.print(F("Valeurs P7 à P0 = "));
    Serial.print(entreeDuPCF8574.p7); Serial.print(" ");
    Serial.print(entreeDuPCF8574.p6); Serial.print(" ");
    Serial.print(entreeDuPCF8574.p5); Serial.print(" ");
    Serial.print(entreeDuPCF8574.p4); Serial.print(" ");
    Serial.print(entreeDuPCF8574.p3); Serial.print(" ");
    Serial.print(entreeDuPCF8574.p2); Serial.print(" ");
    Serial.print(entreeDuPCF8574.p1); Serial.print(" ");
    Serial.print(entreeDuPCF8574.p0); Serial.print(" ");
    Serial.println("");

    // Et on réinitialise la mémorisation du drapeau d'interruption
    delay(100);     // Pour limiter les "rebonds" éventuellement présents en entrée
    interruptionAgerer = false;
  }
   
}

// =======================================
// Fonction appellée à chaque interruption
// =======================================
void routineDinterruption() {
  interruptionAgerer = true;
}

Une fois téléchargé dans votre Arduino, vous devriez voir des informations s’afficher sur le moniteur série. Voici ce que j’obtiens de mon côté :

Résultat interruption PCF 8574 sur moniteur série Arduino IDE, suivant état logique des entrées P7 à P0, exemple de code de programmation de test I2C

À noter que les lignes « Valeurs P7 à P0 » ne s’affichent que lorsqu’une interruption est générée, c’est à dire uniquement lorsqu’une entrée change d’état (passe de 0 à 1, ou l’inverse).

[AJOUT] Le PCF8574A : ou comment disposer d’autres adresses I2C, pour doubler son nombre d’E/S

Dans ce tuto, je vous ai parlé uniquement que du PCF8574. Mais il faut savoir qu’il existe une « variante » de cette puce, portant le nom de PCF8574A (donc avec une lettre « A » en plus, en fin de nom).

En pratique, le fonctionnement de ces 2 circuits intégrés est identique. Ils sont d’ailleurs fabriqués par le même fabricant (Texas Instruments). Par contre, une chose les différencie : il s’agit de leur adresse, sur le bus I2C. Et c’est là, que tout devient intéressant. Car :

  • le PCF8574 « normal » peut être branché jusqu’à 8 fois en « parallèle », afin d’obtenir 8×8, soit 64 entrées/sorties. Le concernant, les adresses I2C à 7-bits possibles pour ce PCF sont : 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, ou 0x27 (en écriture hexadécimale).
  • le PCF8574A, quant à lui, est configurable sur les adresses suivantes (7-bits, i2c) : 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, et 0x3F.

Quel intérêt, me direz-vous ? Eh bien, cela permet de pouvoir brancher non pas 8 x PCF8574 seulement sur un bus I2C, mais 8 x PCF8574 + 8 x PCF8574A. Ainsi, comme chaque PCF peut ajouter 8 entrées/sorties supplémentaires, c’est au final 64 E/S sur les PCF 8574 et 64 E/S sur les PCF 8574A, ce qui fait un total de 128 E/S ! Autant vous dire que ça en fait un paquet, comme on dit 😉

En résumé, on peut obtenir 128 entrées/sorties additionnelles avec 2 fils de commande seulement (SDA et SCL, du bus I2C). Le tout étant réparti sur 16 modules (8 « normaux » et 8 « version A »), soit 16 adresses i2c différentes sur le bus.

Du reste, pour ceux qui souhaitent approfondir tout cela, vous retrouverez ici :

Nota : pour rappel, dans les datasheet, les adresses I2C sont notées sur 8-bits. Cela donne des valeurs différentes de ce qu’on doit entrer dans nos programmes arduino, car ces dernières sont codées sur 7-bits. Pour l’explication « détaillée », je vous renvoie au paragraphe 4, plus haut, nommé « Choix de l’adresse I2C ».

[AJOUT] Le PCF8575 : une version possédant 2 fois plus d’entrées/sorties (16 E/S au lieu de 8 !)

Une autre manière de doubler le nombre d’entrées/sorties d’un PCF8574, qui en a « seulement » 8, est de passer sur un PCF8575. En effet, cette « variante » du PCF 8574 nous permet d’avoir 16 E/S, au lieu de 8, et ce, sur une seule et même puce. Et comme on peut là aussi en câbler 8 en parallèle, cela nous donne 16×8, soit 128 entrées/sorties supplémentaires.

Au niveau des adresses I2C, ce sont les mêmes que pour le 8574, à savoir : 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, ou 0x27 (en écriture hexadécimale).

Si cela vous intéresse, vous trouverez ici le datasheet du PCF 8575, mis à disposition par le fabricant (Texas Instruments). Perso, je vais l’intégrer à l’une de mes prochaines réalisations, donc vous serez peut-être amené à le voir en action 😉

Conclusion

Voilà ! Vous en savez à présent suffisamment pour faire vos premiers pas avec le PCF8574, ou ses « variantes». Ainsi, vous pourrez par exemple ajouter des entrées/sorties supplémentaires à votre Arduino, ou tout autre microcontrôleur d’ailleurs, du moment où vous disposez d’un bus I2C !

Voilà ! Il est l’heure pour moi de vous laisser, et de vous dire à bientôt, pour un prochain tuto 😉

Jérôme.

À découvrir aussi : comment rajouter un convertisseur numérique analogique (DAC) à son Arduino ?

Ce contenu vous plaît ? Alors abonnez-vous à la Newsletter pour ne rien louper !

(*) Mis à jour le 17/10/2022

7 commentaires sur “Tutorial PCF8574 : comment ajouter des entrées / sorties à son arduino ? (avec exemples de code)”

  1. Beau tuto (comme les précédents).

    Je connaissais le 8574 mais pas la version A. Sur un Arduino Mega 2560, j’ai branché sur le port i2c 2×8574 et 2xLCD 4×40. Le câblage est vraiment plus simple. J’ai soudé les modules 8574 sur des cartes 8 relais, avec une alimentation directe. Prochain challenge, remplacer mes deux afficheurs 4×40 par un TFT 800×400 …

    Ah, une chose ici, les sketches sont souvent tronqués à droite, donc incomplets dans les commentaires.

    Beau travail, Jérome, j’ai hâte de découvrir le prochain !
    Loic

    1. Salut Loic !

      Beau challenge en perspective, c’est cool ! Pour ma part, j’ai commencé à écrire un tuto sur comment piloter un écran LCD 1602 (2 lignes 16 caractères), aussi bien en parallèle, qu’en i2c. Mais ça, ce ne sera pas avant la rentrée …

      Concernant les sketches, ils sont tous complets de mon côté, aussi bien sur PC que sur mobile (j’ai un Samsung A40, fonctionnant sous Android donc). Sur PC, il y une barre de scroll en bas des blocs de code (en gris clair, pas très visible), tandis que sur mobile, on peut slider d’un simple bout de doigt, de droite à gauche et vice-versa. Sinon, en cas de problème, tu as toujours la possibilité de copier le code en entier (via le petit icône dédié), et comme ça, en le collant dans un fichier texte ou autre, tu auras tout le code au complet, commentaires compris 😉

      Voilà ! Bon courage à toi !
      Jérôme.

  2. Bonjour Jérome et Bravo !

    Toutes mes félicitations pour ce magnifique travail très détaillé, complet, et bien présenté !
    J’ai programmé ce que tu donnes et cela marche très bien !
    Par contre pour le faire « à ma sauce », je rencontre tout de même un problème qui me surprends.

    Mon objectif est de commander simultanément 2 moteurs pas à pas (4 bits pour chaque bobinage) via un byte représentant l’état des phases des 2 moteurs. L’idée est de suivre un tableau des phases dans un sens ou dans un autre, plus facile à gérer que 256 valeurs fixes ! (Et plus élégant!)

    Les écritures dans le PCF se font « d’un coup », les 8 bits changent en même temps :

    • Wire.write(0babcdABCD); // phases du moteur 1 minuscules / du moteur 2 en Majuscule
    • byte DataPourPCF8574; Wire.write(DataPourPCF8574);

    Pour gérer précisément les accélérations et vitesses des moteurs, j’utilise habituellement le TIMER1.
    La routine qui calcule et envoie au PCF l’octet est appelé par l’interruption du Timer1 : « Timer1.attachInterrupt(routine); », et la durée avec « Timer1.initialize( durée); ».

    Le problème, si cette routine envoie au PCF « Wire.write(DataPourPCF8574); », ca plante, et la carte uno part en reset.
    Par contre si cette même routine envoie sur des pins standards de la UNO, comme je fais d’habitude, aucun problème, c’est un fonctionnement parfait ! La seule différence, c’est là on envoie l’octet de data !

    Aurait-tu une idée de la raison de cette « incompatibilité » et du « plantage » ???

    Cordialement
    André

    1. Salut André !

      Je crois savoir d’où viens ton soucis 😉

      En fait, si j’ai bien compris, tu as mis une commande « Wire.write(données) » dans ta routine d’interruption, et non dans la fonction loop(). Si c’est bien ce que tu as fait, ça pourrait expliquer l’émergence d’un problème.

      En effet, sauf erreur de ma part, on ne peut pas se servir de la fonction Wire.write dans une routine d’interruption, car cette fonction se sert également d’une interruption pour fonctionner. En fait, ce serait comme vouloir « faire une interruption à l’intérieur d’une autre interruption » (ce qui n’est théoriquement pas faisable car, sauf erreur de ma part là encore, les interruptions sont désactivées lorsqu’une routine d’interruption est en cours d’exécution).

      Du coup, je pense qu’il suffirait de réécrire le code différemment, pour contourner le problème (si possible).

      En espérant que cela puisse t’aider dans la résolution de ton soucis !

      Bien à toi,
      Jérôme.

  3. Bonjour Jérôme

    Oui tu as bien compris ce que je fais. Et ta réponse est très claire. Je n’avais pas pensé à cet aspect.
    Merci beaucoup pour ton éclairage qui va m’aider bien sur. Il confirme la solution que j’envisageais.
    Mais cette fois en sachant pourquoi je vais le faire comme cela. C’est très satisfaisant.

    Bravo encore à toi

    André

  4. Bonjour Jérôme,

    Comme d’habitude, toujours très bien exposé avec des illustrations, des exemples et des photos claires.

    Bravo et encore merci pour ce partage.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Symbole danger point d'exclamation site PSE, triangle jaune avec contour noir, texte noir alerte au milieu Afin de filtrer au maximum les messages de type "spam" ou "inappropriés", chaque commentaire est soumis à modération, et validé manuellement. Du coup, il se peut que certains commentaires ne soient pas publiés, ou sinon, avec un peu de retard.