Besoin de brancher plusieurs périphériques I²C identiques, sur un seul et même bus i2c ? Alors le multiplexeur I2C modèle TCA9548 est ce qu’il vous faut ! Ainsi, par exemple, vous pourrez raccorder plusieurs écran OLED avec la même adresse sur votre bus i²c, sans vous soucier d’éventuels conflits d’adresses.
Dans cet article, je vous propose de voir comment fonctionne le multiplexeur i2c TCA9548A, comment le câbler à un Arduino, et comment le piloter via un exemple de code arduino. Ça vous dit ? Alors en avant !
Remarque : cet article n’est qu’une introduction aux multiplexeurs I²C, mettant en avant le TCA 9548A. Ici, je me focalise sur « l’essentiel », sans trop rentrer dans les détails, afin que tous ceux qui débutent en électronique puissent bien suivre ! Et comme toujours, dans le but que tout ce contenu puisse vous servir, dans vos futurs projets 🙂
Module | Description | Lien |
---|---|---|
Module TCA9548A monté sur PCB (multiplexeur i2c à 8 voies) |
Qu’est-ce qu’un multiplexeur (classique ou I²C), comment ça fonctionne, et à quoi ça sert ?
Tout d’abord, en électronique, on appelle multiplexeur un « système d’aiguillage électronique », permettant de mettre en relation une broche d’entrée unique, avec une des ‘n’ sorties possibles. Par « abus de langage », il est parfois appelé aiguilleur, sélecteur, ou routeur, selon les usages.
Basiquement, un multiplexeur agi comme un sélecteur mécanique, et peut être représenté de la sorte :
C’est d’ailleurs ce qu’on voit au niveau des aiguillages de trains, qui permettent de connecter 1 voie ferrée « d’entrée » à une des 2 autres voies « de sortie » possibles ; en sachant qu’une fois l’aiguillage verrouillé dans une position donnée, les trains peuvent y circuler dans un sens, comme dans l’autre. Eh bien en électronique c’est la même chose ! Sauf qu’il n’y a pas d’élément mécanique pour faire l’aiguillage (puisque qu’il se fait de manière électronique), et que nous ne sommes pas limités à 2 sorties !
Maintenant que nous avons vu ce qu’est un multiplexeur, voyons ce qu’est un multiplexeur I2C ! En fait, un multiplexeur I²C est tout simplement un multiplexeur « amélioré », permettant de jumeler 1 bus i2c d’entrée, avec 1 parmi ‘n’ bus I2C disponibles en sortie. Ainsi, un pont est établi entre ces deux bus là, spécifiquement, en les isolant de tous les autres.
Toujours pas clair ? Alors voici un exemple de représentation visuelle et schématique d’un multiplexeur I2C (le nombre de voies pouvant bien évidemment varier, selon les composants électroniques) :
Nota : vous verrez souvent écrit qu’un multiplexeur permet de connecter 1 entrée donnée (unique) à 1 des sorties possibles. Or les termes « entrée » et « sorties » peuvent parfois prêter à confusion. Car en effet, comme vous pouvez le constater ci-dessus, certains signaux traversant un multiplexeur I²C peuvent aller dans les 2 sens (de l’entrée vers la sortie sélectionnée, ou de la sortie sélectionnée vers l’entrée). Ne prenez donc pas les mots « entrée » ou « sortie » au pied de la lettre, stricto sensu ! Car certains « ponts » établis dans un multiplexeur peuvent être unidirectionnels ou bidirectionnels, selon le composant utilisé !
Maintenant, dans quel cas avons-nous besoin d’un multiplexeur I2C ?
Eh bien en fait, le plus souvent, un multiplexeur i2c est mis en œuvre lorsqu’on a besoin de communiquer avec plusieurs périphériques I2C identiques, de manière individuelle, alors qu’ils ont la même adresse physique. Car sans multiplexeur, tous les périphériques en double, triple, ou ‘n’ exemplaires, seraient pilotés en même temps, sans pouvoir être distinguer les uns des autres. Or si on souhaite s’adresser à eux individuellement, il devient alors nécessaire de les isoler les uns des autres, sur des « sous-bus I²C » différents. Et c’est justement ce que fait un multiplexeur I2C !
Pour que ce soit plus parlant, voici un exemple pratique : si vous utilisez un Arduino Uno ou Nano, vous savez que ces cartes ne mettent à disposition qu’un seul bus I2C physique (hors émulation logicielle, j’entends). Ce bus natif I²C est accessible via les broches A4 (SDA) et A5 (SCL) de ces cartes. Par ailleurs, comme vous le savez certainement, une adresse I2C est codée sur 7 bits, ce qui fait qu’on ne peut techniquement s’adresser qu’à 127 périphériques i2c maximum, théoriquement. Avec, bien entendu, tout un tas d’adresses réservées et/ou imposées aux fabricants, pour l’adressage de leurs périphériques I²C. Du coup, si vous souhaitez par exemple vous adresser à un écran OLED i2c parmi plusieurs identiques, une solution simple est de mettre en œuvre un multiplexeur I²C entre l’arduino et ces écrans, afin de pouvoir les commander individuellement !
Maintenant que nous avons vu ce qu’est un multiplexeur i²c et à quoi il sert, voyons ensemble la puce TCA9548, qui est un multiplexeur I2C de 1 ↔ 8 voies/bus possibles … avec quelques particularités en plus 🙂
Module | Description | Lien |
---|---|---|
Module TCA9548A monté sur PCB (multiplexeur i2c à 8 voies) |
Le multiplexeur i2c TCA9548A (8 voies) : brochage (pinout), fonctionnement basique, pilotage, et caractéristiques
TCA9548A pinout : brochage de la puce, et de la version montée sur PCB
Physiquement, le multiplexeur i2C TCA9548A se présente tout simplement sous la forme d’une puce électronique (ou d’une mini plaquette PCB, sur laquelle il est soudé). Ici, je vais vous présenter le modèle fabriqué par Texas Instrument (au besoin, voici le datasheet de multiplexeur TCA9548A à 8 voies pour bus I²C, au format PDF) :
Au niveau du brochage, on retrouve :
- des broches d’alimentation : Vcc (aussi appelé Vin) et Gnd
- des broches d’entrée I2C : SDA et SCL
- des broches de sorties I2C :
- SD0/SC0 pour les broches SDA et SCL du port de sortie i2c #0
- SD1/SC1 pour les broches SDA et SCL du port de sortie i2c #1
- SD2/SC2 pour les broches SDA et SCL du port de sortie i2c #2
- SD3/SC3 pour les broches SDA et SCL du port de sortie i2c #3
- SD4/SC4 pour les broches SDA et SCL du port de sortie i2c #4
- SD5/SC5 pour les broches SDA et SCL du port de sortie i2c #5
- SD6/SC6 pour les broches SDA et SCL du port de sortie i2c #6
- SD7/SC7 pour les broches SDA et SCL du port de sortie i2c #7
- une broche de commande notée /RESET, permettant de réinitialiser la puce (l’état initial du TCA 9548A étant d’avoir toutes les broches de sorties « déconnectées »)
- et des broches de sélection d’adresse (A0, A1, et A2), désignant l’adresse I2C de la puce, en elle-même
Lorsque cette puce est montée sur la plaquette PCB, on retrouve généralement en plus les composants annexes suivants :
- 3 résistances pull-up (typiquement 10 kohms), individuellement raccordées aux broches SDA, SCL, et /RESET
- 3 résistances pull-down (typiquement 10 kohms), individuellement raccordées aux broches A0, A1, et A2
- et 1 condensateur de filtrage/découplage (typiquement de 10 µF)
Les valeurs des résistances et capacité pouvant varier d’un fournisseur l’autre, comme toujours !
Fonctionnement basique du TCA9548A (au niveau de la transmission des signaux)
Au niveau fonctionnement du TCA9548 en lui-même, il est assez simple, enfin …une fois qu’on a bien compris ! Pour faire simple, je vais vous expliquer comment il s’utilise en pratique, et ainsi, vous comprendrez son fonctionnement.
Alors, en pratique, il suffit de suivre les 2 étapes suivantes, pour utiliser un TCA9548 :
- premièrement, il faut dire laquelle des sorties I2C devra être reliée avec l’entrée I2C (subtilité ici : on peut choisir 0, 1, ou plusieurs sorties parmi les 8 possibles, à connecter avec l’entrée unique)
- deuxièmement, on envoie les signaux sur l’entrée I2C, afin qu’ils soient acheminés là où on le désire (si vous avez bien compris le point précédent, les signaux d’entrée se retrouveront alors soit sur aucune sortie, soit sur une seule sortie I2C, soit sur plusieurs sorties I2C simultanément, parmi les huit sorties possibles sur le TCA)
Du coup, par exemple, si vous souhaitez envoyer des données en I²C à un périphérique i2c relié sur le port #2 d’un TCA 9548A, il faudra d’abord établir le pont entre l’entrée et le port de sortie #2, et ensuite, envoyer les signaux sur l’entrée SDA/SCL du TCA, afin que ces signaux se retrouvent sur les sorties SD2/SC2 du TCA (qui correspondent aux lignes SDA/SCL du port #2).
Autre exemple : si vous souhaitez envoyer simultanément des données I2C sur les ports de sortie #3 et #7 d’un TCA9548 A, il faudra alors tout d’abord établir un pont entre l’entrée du TCA et ces deux sorties spécifiques là, puis ensuite envoyer des données sur SCL/SDA du TCA, afin que celles-ci se retrouvent sur les lignes SC3/SD3 et SC7/SD7 (SC3 et SC7 étant les sorties d’horloge SCL des ports #3 et #7, et SD3 et SD7 les lignes de données SDA des ports #3 et #7).
Cela étant dit, à présent, il faut savoir que le TCA9548A est un périphérique I2C avant tout (avant d’être un multiplexeur I2C), et que par conséquent, il possède lui aussi une adresse i2c qui lui est propre. En clair, lorsqu’on envoie un message I²C sur les entrées SDA/SCL d’un TCA 9548A :
- si l’adresse contenue dans le message I2C est celle du TCA9548 A, alors le TCA saura qu’on s’adresse à lui directement (pour lui dire de connecter telle ou telle de ses sorties avec son entrée, basiquement)
- si l’adresse contenue dans le message I2C est différente de celle du TCA, alors il saura que le message reçu sur ses entrées est à transmettre en sortie (sur la ou les sorties sélectionnées, le cas échéant)
En espérant que mes explications soient suffisamment claires, sinon tout prendra sens, au niveau des exemples de code arduino, plus bas 😉
Module | Description | Lien |
---|---|---|
Module TCA9548A monté sur PCB (multiplexeur i2c à 8 voies) |
Comment piloter le TCA 9548 A, pour connecter l’entrée unique avec telle ou telle sortie ?
Comme évoqué précédemment, le TCA9548A permet de mettre en relation 1 bus d’entrée I2C avec 0, 1 ou plusieurs sorties I2C. Et pour rappel, ses lignes d’entrée SDA/SCL servent à la fois :
- pour dire au TCA 9548A de connecter telle ou telles sorties avec l’entrée (ou aucune, si souhaité)
- pour la transmission/réception de données avec la ou les sorties souhaitées (ou aucune, si souhaité)
Et comme un message I2C contient toujours l’adresse de son destinataire, il suffit d’envoyer des données avec l’adresse du TCA pour s’adresser à lui, ou envoyer des données avec n’importe quelle autre adresse, pour que le TCA transfère ces données sur 0, 1, ou plusieurs de ses sorties.
Techniquement, sur le bus I²C, il y a envoi de 2 octets à la suite, à minima (le 1er octet contenant l’adresse du destinataire du message, et le ou les suivants étant les données à proprement parler).
Techniquement, côté code arduino cette fois-ci, nous utiliserons la bibliothèque native « Wire.h », pour l’envoi de ces octets. Pour ce faire, nous utiliserons les fonctions :
- Wire.beginTransmission(adresse_du_TCA), qui permettra d’envoyer un premier octet sur le bus I2C, contenant l’adresse de notre puce TCA9548 ou de tout autre périphérique I2C ciblé ; ainsi, le TCA saura que l’octet suivant lui est adressé ou qu’il devra tout simplement le transmettre sur sa ou ses sorties actives
- et Wire.write(mot_de_selection), qui permettra d’envoyer un second octet sur le bus I2C, contenant les données à proprement parler ; ces données peuvent par exemple être les 8 bits qui détermineront l’état des 8 sorties du TCA (1 = connecté à l’entrée, 0 = déconnecté ; le bit de poids fort correspondant aux sorties i2c du port #7 du TCA, et le poids faible, au bus de sortie i2c #0)
Avec comme toujours, pour « conclure » la transmission I2C, une commande Wire.endTransmission() pour spécifier au TCA ou autre cible I2C qu’il n’y aura plus d’autres octets à venir, dans l’immédiat.
Ainsi, en pratique, si on envoie par exemple la commande Wire.beginTransmission(0x70) et Wire.write(0b1100 1010), et qu’un TCA9548 est bien configurer pour fonctionner sur l’adresse 0x70, alors ce dernier comprendra qu’il devra dorénavant transmettre tous les messages suivants (qui ne contiendraient pas l’adresse 0x70) vers ses ports de sorties i2c #7, #6, #3, et #1, en désactivant au passage les ports de sorties 5/4/2/0 (7/6/3/1 correspondant aux bits « 1 » du wire.write et 5/4/2/0 aux bits « 0 »).
Bien sûr, un nouveau message comportant l’adresse 0x70 permettrait à tout moment de rechanger l’état du (ou des) pont(s) actifs/inactifs !
Nota : si tout ceci n’est pas très clair, ne vous inquiétez pas ! Car tout prendra sens, lorsque vous verrez le code arduino. Enfin … j’espère 😉
Caractéristiques techniques du TCA 9548A (tension d’alimentation, fréquence d’utilisation, …)
Au niveau de l’alimentation électrique, une puce TCA9548A nécessite entre 1,65V à 5,5V, si la température ambiante se situe entre -40°C à +85°C (ou entre 1,65V et 3,6V, si la température ambiante est comprise entre +85°C et +125°C). Du coup, la plupart du temps, on peut dire qu’une tension d’alim de 1,8V 3,3V ou 5V lui convient parfaitement !
Au niveau I²C, le TCA 9548A supporte une horloge allant jusqu’à 400 kHz (ce qu’on appelle le « Fast Mode »). Mais rien ne vous empêche de dialoguer moins vite avec lui, en utilisant le « Standard Mode », c’est à dire à 100 kHz (fréquence d’horloge SCL).
À noter que lorsque la puce TCA9548 A « démarre », toutes les sorties I2C sont déconnectées (on peut d’ailleurs obtenir le même résultat en connectant l’entrée /RESET de la puce à la masse, lorsque souhaité !).
Différentes adresses i2c d’un TCA9548 (de 0x70 à 0x77)
Comme vu précédemment, le TCA9548 A est à la fois un périphérique I2C (car il se pilote en i2c, pour paramétrer ses pontages entrée/sorties) et un aiguilleur de signaux I2C, à destination d’autres périphériques I²C, branchés au niveau de ses sorties.
Étant donc à la base un périphérique i2c, il dispose naturellement d’une (ou plusieurs) adresse(s) I2C, mise à disposition par le fabricant. Dans le cas du TCA 9548 A, les adresses I²C possibles pour le piloter sont 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, ou 0x77. Et il nous revient de choisir physiquement l’une de ces adresses, afin de le « fixer » sur le réseau. Pour ce faire, il suffit de relier les entrées A0, A1, et A2 de la puce TCA 9548A au Vcc (état haut = 1) ou à Gnd (état bas = 0), selon l’adresse qu’on désire, comme le montre le tableau suivant :
Pour rappel, si vous utilisez un TCA9548 A monté sur PCB, il y a normalement des résistances pull-down en place sur les lignes d’entrée I2C. Si tel est le cas, l’adresse I2C par défaut de votre carte/module TCA9548A sera donc 0x70 (du fait que A0, A1, et A2 soient ramenés à l’état bas, via ces résistances).
Module | Description | Lien |
---|---|---|
Module TCA9548A monté sur PCB (multiplexeur i2c à 8 voies) |
Comment câbler son TCA9548A sur un Arduino Uno ?
En fait, relier un module TCA9548A à une carte Arduino Uno est super simple, car seuls 4 fils suffisent, pour ce faire :
Pour être plus précis, au niveau des connectiques, vous aurez besoin de :
- 2 fils pour connecter l’alimentation (+5V/GND de l’Arduino Uno vers les broches VIN/GND de la carte TCA 9548A)
- et 2 fils de communication I²C (A4/A5 de l’Arduino Uno vers les broches SDA/SCL du module TCA)
Pour rappel, comme évoqué précédemment, les lignes A0/A1/A2 du module TCA9548 A sont dotées de résistances pull-down. Ainsi, en l’absence de raccordement de ces broches, celles-ci sont ramenées à la masse. Or, comme vu au paragraphe précédent, si A0=0, A1=0, et A2=0, alors l’adresse du TCA 9548 A sera 0x70, sur le bus i2c. Bien sûr, si vous souhaitez une autre adresse que 0x70 pour votre puce TCA, il vous faudra alors physiquement raccorder les broches A0/A1/A2 aux potentiels que vous souhaitez (+Vcc ou Gnd), afin d’obtenir l’adresse I2C que vous désirez.
Remarque : les entrées SDA et SCL ont des résistances pull-up intégrées dans le module TCA 5948A (valeur = 10 Kohms). Il n’y a donc pas besoin d’en rajouter, entre l’arduino et le TCA 🙂
Nota : ici, la broche RST (aussi nommée /RESET) est déconnectée, ce qui fait que le module sera toujours actif ; car, pour rappel, une résistance pull-up ramène cette ligne à l’état haut, en l’absence de branchement dessus. Bien évidemment, vous pouvez parfaitement relier cette broche à votre arduino, pour contrôler ou forcer la réinitialisation de votre module TCA9548A à tout moment, quand vous le souhaitez !
À présent, sur la base de ce montage, libre à vous d’ajouter vos périphériques I²C sur les sorties du module TCA, en respectant bien la distinction des lignes d’horloge SCL et lignes de données SDA. Les dénominations de ces lignes sont d’ailleurs les suivantes :
- SD0/SC0 sont les sorties SDA et SCL du 1er port I2C de la carte (index #0)
- SD1/SC1 sont les sorties SDA et SCL du 2ème port I2C de la carte (index #1)
- SD2/SC2 sont les sorties SDA et SCL du 3ème port I2C de la carte (index #2)
- SD3/SC3 sont les sorties SDA et SCL du 4ème port I2C de la carte (index #3)
- SD4/SC4 sont les sorties SDA et SCL du 5ème port I2C de la carte (index #4)
- SD5/SC5 sont les sorties SDA et SCL du 6ème port I2C de la carte (index #5)
- SD6/SC6 sont les sorties SDA et SCL du 7ème port I2C de la carte (index #6)
- SD7/SC7 sont les sorties SDA et SCL du 8ème port I2C de la carte (index #7)
En sachant qu’au niveau du branchement de vos périphériques i2c en eux-mêmes, vous n’êtes pas limités à 1 périphérique I2C par sortie, au niveau du TCA. En effet, vous pouvez :
- soit laisser une sortie du TCA non raccordée
- soit brancher 1 périphérique I2C sur telle ou telle sortie du module TCA
- soit brancher plusieurs périphériques I2C par sortie, du moment où chacun d’eux à une adresse I²C différente (si l’on souhaite qu’ils soient tous accessibles individuellement, j’entends)
- soit un mix des deux façons précédentes
En clair, voici une représentation visuelle de comment vous pouvez brancher vos « esclaves i2c » en sortie du module TCA9548A :
Maintenant que nous avons vu la partie matérielle, passons à la partie logicielle 🙂
Code exemple #1 : un scanner i2c pour multiplexeur TCA 9548
Avant d’attaquer ce 1er exemple, un petit rappel pour bien comprendre la suite : le TCA9548A possède 8 voies I²C, et sur chacune de ces voies, on peut raccorder 0, 1, ou plusieurs périphériques i2c dessus. On peut donc connecter beaucoup d’esclaves I2C sur un TCA 9548, comme vous vous en doutez !
Aussi, pour savoir si tous les périphériques I2C sont bien connectés sur le TCA et vérifier leur adresse sur le réseau, rien de tel qu’un scanner i2c, pour tout analyser ! Et plus précisément, rien de tel qu’un « scanner I²C multi-voies », pour scanner toutes les adresse i2c (127 au maximum) de toutes les voies du TCA (8 voies). Ainsi, cela nous permettra de visualiser l’adresse de tous les esclaves I2C, raccordés sur chacune des voies du TCA9548 A, et ainsi, vérifier/tester que ces périphériques fonctionnent bien (du moins, basiquement !). Et ça, c’est le programme arduino que nous allons voir ici !
Mais avant tout, nous avons besoin d’un montage de base pour effectuer nos tests. Pour ce faire, je vous propose donc de partir sur le câblage suivant, afin de pouvoir tester ce programme de scan d’adresses I2C multivoies :
Ici, j’ai fait le choix d’utiliser un Arduino Nano (pour pouvoir tout câbler sur breadboard), et de raccorder 4 écrans OLED i2c sur le multiplexeur TCA 9548 (à raison d’un écran oled par sortie du multiplexeur).
Nota : vous remarquerez qu’il n’y a aucune résistance pull-up sur les lignes SDA et SCL, que ce soit du côté arduino ou du côté des afficheurs OLED i2c utilisés ici. Pourtant, celles-ci sont bien présentes, car indispensables ! En fait, elles se situent sur le module TCA9548 A (pour la partie Arduino ↔ module TCA 9548A) et au dos de chacun des afficheurs (pour chaque partie TCA9548 port n°X ↔ écran OLED n°X).
Voici ce que ça donne en images, une fois câblé sur breadboard :
Le but du scanner (programme arduino) sera donc ici de tester si ces 4 écrans oled répondent bien présent, via le scan de toutes les adresses de toutes les voies I²C du TCA9548A. Ce qui nous permettra au passage de récupérer/vérifier l’adresse I2C de ces périphériques, afin de pouvoir les utiliser plus tard, dans un autre programme !
Module | Description | Lien |
---|---|---|
Module TCA9548A monté sur PCB (multiplexeur i2c à 8 voies) |
Mais pour l’heure, restons sur ce scanner I2C multivoies, et voyons sans plus attendre son code de programmation :
/*
______ _ _///_ _ _ _
/ _ \ (_) | ___| | | | (_)
| [_| |__ ___ ___ _ ___ _ __ | |__ | | ___ ___| |_ _ __ ___ _ __ _ ___ _ _ ___
| ___/ _ \| __|| __| |/ _ \| '_ \_____| __|| |/ _ \/ _| _| '__/ \| '_ \| |/ \| | | |/ _ \
| | | ( ) |__ ||__ | | ( ) | | | |____| |__ | | __/| (_| |_| | | (_) | | | | | (_) | |_| | __/
\__| \__,_|___||___|_|\___/|_| [_| \____/|_|\___|\____\__\_| \___/|_| |_|_|\__ |\__,_|\___|
| |
\_|
Fichier : prgArduino1-scanner-I2C-avec-TCA9548-et-4-oled.ino
Description : Programme permettant de scanner les 8 ports (8 voies ou 8 sorties, si vous préférez)
d'un multiplexeur I2C modèle TCA9548A, afin de lire les périphériques branchés dessus
Licence : BY-NC-ND 4.0 CC (https://creativecommons.org/licenses/by-nc-nd/4.0/deed.fr)
Remarques : - pour la démo de ce scanner, 4 écrans OLED à base de SSD1306 seront branchés sur les
voies 0 à 3 du TCA 9548 A
- le code est volontairement "lourd" et détaillé, afin de faciliter la compréhension
au maximum
Auteur : Jérôme TOMSKI (https://passionelectronique.fr/)
Créé le : 31.07.2024
*/
// Inclusion des librairies dont nous aurons besoin ici
#include <Wire.h> // La librairie Wire nous servira à piloter le TCA9548
// Définition de constantes
#define adresseI2CduTCA9548 0x70 // C'est l'adresse I²C par défaut, du module TCA 9548A (qui peut physiquement être réglée de 0x70 à 0x77)
// =======================================================================================
// Fonction "changer_aiguillage_sur_TCA9548"
// Remarque : le TCA 9548 fonctionne comme un aiguillage de chemin de fer ; il permet de
// connecter l'entrée du TCA à l'une des 8 sorties (voies) possibles (de 0 à 7)
// =======================================================================================
void changer_aiguillage_sur_TCA9548(int numero_de_voie_a_selectionner) {
// Nota 1 : sur un TCA9548, on peut choisir 1 des 8 voies mises à disposition (voies 0 à 7)
// Nota 2 : une fois la nouvelle voie (sortie) sélectionnée, le TCA 9548 est comme qui dirait "transparent" ;
// c'est à dire quelles que soient les adresses et données envoyées sur le port I2C (à part l'adresse du TCA),
// celles-ci se retrouveront aiguillées vers la sortie choisie (comme si le TCA n'existait pas, entre les deux)
// On quitte la fonction si le numéro de voie n'est pas correct
if(numero_de_voie_a_selectionner < 0 || numero_de_voie_a_selectionner > 7)
return;
// Si le numéro de voie est correct, alors on change "l'aiguillage interne du TCA9548" pour connecter cette sortie à l'entrée
Wire.beginTransmission(adresseI2CduTCA9548);
Wire.write(1 << numero_de_voie_a_selectionner);
Wire.endTransmission();
}
// ========================
// Initialisation programme
// ========================
void setup() {
// *****************************************************************************************
// Initialisation de la liaison série Arduino Nano ↔ PC, pour faire du débuggage, au besoin
// *****************************************************************************************
while(!Serial);
Serial.begin(9600);
Serial.println(F("==============================================================="));
Serial.println(F("Programme #1 : scanner I2C pour multiplexeur TCA9548A (4 écrans"));
Serial.println(F(" OLED sont branchés dessus, pour la démo)"));
Serial.println(F("==============================================================="));
Serial.println();
delay(500);
// ***************************************************************************
// Boucle de parcours des 8 voies (allant de 0 à 7) du multiplexeur TCA 9548 A
// ***************************************************************************
Wire.begin();
for(int numero_de_voie_multiplexeur_a_scanner = 0 ; numero_de_voie_multiplexeur_a_scanner <= 7 ; numero_de_voie_multiplexeur_a_scanner++) {
// Sélection de la voie qui nous intéresse
// ---------------------------------------
changer_aiguillage_sur_TCA9548(numero_de_voie_multiplexeur_a_scanner);
Serial.print(F("Scan du port #")); Serial.print(numero_de_voie_multiplexeur_a_scanner);
Serial.println(F(" du multiplexeur"));
// Scan des 128 adresses i2c possibles (allant de 0 à 127)
// -------------------------------------------------------
for (int adresse_i2c_a_scanner = 0 ; adresse_i2c_a_scanner <=127 ; adresse_i2c_a_scanner++) {
// On saute l'adresse du multiplexeur, lorsqu'on arrive dessus
if (adresse_i2c_a_scanner == adresseI2CduTCA9548)
continue;
// Test de l'adresse i2c scannée
Wire.beginTransmission(adresse_i2c_a_scanner);
if (!Wire.endTransmission()) {
Serial.print(" → Périphérique I2C trouvé à l'adresse 0x");
Serial.println(adresse_i2c_a_scanner, HEX);
}
}
}
// ***********
// Fin du scan
// ***********
Serial.println();
Serial.println(F("Scan terminé !"));
}
// =================
// Boucle principale
// =================
void loop() {
// Pas de code ici, car tout se passe dans la fonction "setup" !
}
Une fois ce programme uploadé dans la carte arduino, il suffit d’ouvrir le moniteur série de l’IDE Arduino pour voir ce qui s’affiche. De mon côté, voici ce que j’ai obtenu :
On retrouve bien les 4 écrans OLED I²C que j’ai raccordé sur le multiplexeur TCA9548A, en notant au passage qu’ils ont tous la même adresse I2C « 0x3C » (ce qui pour rappel ne posera aucun problème, car le fait qu’ils soient chacun sur une voie différente permettra d’éviter tout conflit, bien qu’ils aient tous la même adresse i2c ! C’est d’ailleurs tout l’intérêt d’un multiplexeur, sans quoi on ne pourra les piloter individuellement).
Remarque : vous noterez qu’on utilise aucune librairie spécifique ici, dans le code arduino, pour piloter ce multiplexeur i2c TCA9548A. En fait, on fait seulement appel à la librairie de base « Wire », nativement présente dans l’IDE Arduino, et rien d’autre !
À présent, envoyons des éléments à afficher sur ces écrans oled, afin de voir si l’aiguillage i2c fonctionne bien 😉
Code exemple #2 : pilotage de 4 écrans OLED i2c ayant la même adresse (avec 1 seul port I²C Arduino et 1 multiplexeur TCA 9548)
Ici, c’est typiquement le genre d’exemple qui illustre bien l’usage d’un multiplexeur I2C ! Car nous allons individuellement piloter chacun des quatre afficheurs I²C vus dans l’exemple précédent (écrans oled i2c de 0,96″, à contrôleur SSD1306), alors qu’ils ont pourtant tous la même adresse (0x3C). Et ce, à partir d’un seul bus I2C, côté pilotage arduino (SDA/SCL de la carte), bien évidemment !
Pour rappel, si on avait mis ces 4 écrans oled sur un seul et même bus I2C (sans multiplexeur, j’entends), ils auraient tous été pilotés simultanément, en parallèle ; ils afficheraient donc tous la même chose, sans possibilité de pouvoir afficher des choses différentes de l’un à l’autre. Du coup, pour pouvoir les piloter séparément, rien de tel qu’un multiplexeur I²C, comme le TCA 9548A 🙂
Pour vous illustrer cela, je vous propose de reprendre le montage de l’exemple précédent (« scanner multivoies i2c », utilisant un TCA9548 A). Pour vous resituer le montage, voici ce qu’il donnait, au niveau câblage :
Maintenant que nous avons vu la partie matérielle, voyons ce que fera ce 2ème programme exemple. En fait, ici, nous allons afficher des infos différentes et identiques, sur chacun des afficheurs. Pour être plus clair, nous allons faire apparaître, sur chacun d’eux :
- le numéro de chaque afficheur, en haut de chaque écran oled (« 1er afficheur » sur le 1er écran OLED, etc)
- et une valeur (compteur) allant de 1 (à la mise sous tension) jusqu’à l’infini, afin de dynamiquement rafraîchir chaque écran oled, chaque seconde
Module | Description | Lien |
---|---|---|
Module TCA9548A monté sur PCB (multiplexeur i2c à 8 voies) |
En vidéo, voici ce que cela va donner, pour être plus explicite (qui utilise au passage l’alim USB v2 faite-maison, à base d’accus li-ion 18650, que je vous avais présenté il y a peu) :
Et pour arriver à ce résultat, voici le code arduino utilisé :
/*
______ _ _///_ _ _ _
/ _ \ (_) | ___| | | | (_)
| [_| |__ ___ ___ _ ___ _ __ | |__ | | ___ ___| |_ _ __ ___ _ __ _ ___ _ _ ___
| ___/ _ \| __|| __| |/ _ \| '_ \_____| __|| |/ _ \/ _| _| '__/ \| '_ \| |/ \| | | |/ _ \
| | | ( ) |__ ||__ | | ( ) | | | |____| |__ | | __/| (_| |_| | | (_) | | | | | (_) | |_| | __/
\__| \__,_|___||___|_|\___/|_| [_| \____/|_|\___|\____\__\_| \___/|_| |_|_|\__ |\__,_|\___|
| |
\_|
Fichier : prgArduino2-TCA9548A-et-4-oled-I2C.ino
Description : Programme permettant de piloter 4 écrans OLED i2c (SSD1306) ayant la même adresse,
via un multiplexeur I2C modèle TCA 9548 A, branché sur un Arduino Nano
Licence : BY-NC-ND 4.0 CC (https://creativecommons.org/licenses/by-nc-nd/4.0/deed.fr)
Remarques : - les écrans OLED utilisés ici sont des modèles à base de SSD1306,
faisant 128 x 64 pixels (0,96 pouces de diagonale)
- le code est volontairement "alourdi" et non optimisé, afin de faciliter
au maximum la compréhension (avec autant de commentaires que possible)
Auteur : Jérôme TOMSKI (https://passionelectronique.fr/)
Créé le : 31.07.2024
*/
// Inclusion des librairies dont nous aurons besoin ici
#include <Wire.h> // La librairie Wire nous servira à piloter le TCA9548
#include <Adafruit_SSD1306.h> // La librairie SSD1306 d'Adafruit nous permettra de piloter nos écrans OLED (à base de SSD1306)
// Définition de constantes
#define adresseI2CduTCA9548 0x70 // C'est l'adresse I²C par défaut, du module TCA 9548A (qui peut physiquement être réglée de 0x70 à 0x77)
#define nombreDePixelsEnLargeur 128 // Taille de l'écran OLED, au niveau de sa largeur (en pixels)
#define nombreDePixelsEnHauteur 64 // Taille de l'écran OLED, au niveau de sa hauteur (en pixels)
#define brocheResetOLED -1 // Valeur signifiant qu'il n'y a pas de pin spécifique pour les RESET des écrans OLEDS
#define adresseI2CdeLecranOLED 0x3C // C'est l'adresse I²C par défaut des écrans oleds à base de SSD1306
// (cette adresse peut être physiquement réglée sur 0x3C ou 0x3D, à même l'écran)
// Instanciation de la librairie oled
Adafruit_SSD1306 ecran_oled(nombreDePixelsEnLargeur, nombreDePixelsEnHauteur, &Wire, brocheResetOLED);
// =======================================================================================
// Fonction "changer_aiguillage_sur_TCA9548"
// Remarque : le TCA 9548 fonctionne comme un aiguillage de chemin de fer ; il permet de
// connecter l'entrée du TCA à l'une des 8 sorties (voies) possibles (de 0 à 7)
// =======================================================================================
void changer_aiguillage_sur_TCA9548(int numero_de_voie_a_selectionner) {
// Nota 1 : sur un TCA9548, on peut choisir 1 des 8 voies mises à disposition (voies 0 à 7)
// Nota 2 : une fois la nouvelle voie (sortie) sélectionnée, le TCA 9548 est comme qui dirait "transparent" ;
// c'est à dire quelles que soient les adresses et données envoyées sur le port I2C (à part l'adresse du TCA),
// celles-ci se retrouveront aiguillées vers la sortie choisie (comme si le TCA n'existait pas, entre les deux)
// On quitte la fonction si le numéro de voie n'est pas correct
if(numero_de_voie_a_selectionner < 0 || numero_de_voie_a_selectionner > 7)
return;
// Si le numéro de voie est correct, alors on change "l'aiguillage interne du TCA9548" pour connecter cette sortie à l'entrée
Wire.beginTransmission(adresseI2CduTCA9548);
Wire.write(1 << numero_de_voie_a_selectionner);
Wire.endTransmission();
}
// ========================
// Initialisation programme
// ========================
void setup() {
// *****************************************************************************************
// Initialisation de la liaison série Arduino Nano ↔ PC, pour faire du débuggage, au besoin
// *****************************************************************************************
while(!Serial);
Serial.begin(9600);
Serial.println(F("==================================================================================="));
Serial.println(F("Programme #2 : pilotage de 4 écrans OLED via Arduino Nano + multiplexeur TCA 9548A"));
Serial.println(F("=================================================================================="));
Serial.println();
delay(500);
// ****************************************************************
// Préparation de la connexion Arduino Nano ↔ multiplexeur TCA9548
// ****************************************************************
Wire.begin();
delay(500);
// ******************************************************************************
// Initialisation du 1er écran OLED, branché sur le port (la voie) 0 du TCA9548A)
// ******************************************************************************
changer_aiguillage_sur_TCA9548(0); // Sélection de la sortie I²C numéro 0, sur le TCA9548
delay(100); // Petit délai de stabilisation
if(!ecran_oled.begin(SSD1306_SWITCHCAPVCC, adresseI2CdeLecranOLED)) {
Serial.println("Connexion impossible au 1er écran OLED");
Serial.println("Arrêt du programme.");
while(1);
}
ecran_oled.clearDisplay(); // Effacement du buffer de l'écran
// *******************************************************************************
// Initialisation du 2ème écran OLED, branché sur le port (la voie) 1 du TCA9548A)
// *******************************************************************************
changer_aiguillage_sur_TCA9548(1); // Sélection de la sortie I²C numéro 1, sur le TCA9548
delay(100); // Petit délai de stabilisation
if(!ecran_oled.begin(SSD1306_SWITCHCAPVCC, adresseI2CdeLecranOLED)) {
Serial.println("Connexion impossible au 2ème écran OLED");
Serial.println("Arrêt du programme.");
while(1);
}
ecran_oled.clearDisplay(); // Effacement du buffer de l'écran
// *******************************************************************************
// Initialisation du 3ème écran OLED, branché sur le port (la voie) 2 du TCA9548A)
// *******************************************************************************
changer_aiguillage_sur_TCA9548(2); // Sélection de la sortie I²C numéro 2, sur le TCA9548
delay(100); // Petit délai de stabilisation
if(!ecran_oled.begin(SSD1306_SWITCHCAPVCC, adresseI2CdeLecranOLED)) {
Serial.println("Connexion impossible au 3ème écran OLED");
Serial.println("Arrêt du programme.");
while(1);
}
ecran_oled.clearDisplay(); // Effacement du buffer de l'écran
// *******************************************************************************
// Initialisation du 4ème écran OLED, branché sur le port (la voie) 3 du TCA9548A)
// *******************************************************************************
changer_aiguillage_sur_TCA9548(3); // Sélection de la sortie I²C numéro 3, sur le TCA9548
delay(100); // Petit délai de stabilisation
if(!ecran_oled.begin(SSD1306_SWITCHCAPVCC, adresseI2CdeLecranOLED)) {
Serial.println("Connexion impossible au 4ème écran OLED");
Serial.println("Arrêt du programme.");
while(1);
}
ecran_oled.clearDisplay(); // Effacement du buffer de l'écran
// ************************************************
// Petite pause, avant de passer à la boucle "loop"
// ************************************************
Serial.println(F("Initialisation : OK !"));
Serial.println();
delay(1000);
}
// =================
// Boucle principale
// =================
void loop() {
// Création d'un compteur, s'incrémentant toutes les secondes environ
// (celui-ci sera initialisé à la valeur 1, lors du tout premier passage dans
// cette fonction loop ; cela est permis avec les variables de type "static")
static int valeur_compteur = 1;
// Écriture sur l'écran OLED numéro 1 (donc à travers la voie "0" du TCA9548)
changer_aiguillage_sur_TCA9548(0);
ecran_oled.clearDisplay();
ecran_oled.setTextColor(WHITE);
ecran_oled.setTextSize(1);
ecran_oled.setCursor(0, 0);
ecran_oled.print("1er afficheur");
ecran_oled.setTextSize(2);
ecran_oled.setCursor(0, 30);
ecran_oled.print("Valeur=");
ecran_oled.print(valeur_compteur);
ecran_oled.display();
// Écriture sur l'écran OLED numéro 2 (donc à travers la voie "1" du TCA9548)
changer_aiguillage_sur_TCA9548(1);
ecran_oled.clearDisplay();
ecran_oled.setTextColor(WHITE);
ecran_oled.setTextSize(1);
ecran_oled.setCursor(0, 0);
ecran_oled.print("2eme afficheur");
ecran_oled.setTextSize(2);
ecran_oled.setCursor(0, 30);
ecran_oled.print("Valeur=");
ecran_oled.print(valeur_compteur);
ecran_oled.display();
// Écriture sur l'écran OLED numéro 3 (donc à travers la voie "2" du TCA9548)
changer_aiguillage_sur_TCA9548(2);
ecran_oled.clearDisplay();
ecran_oled.setTextColor(WHITE);
ecran_oled.setTextSize(1);
ecran_oled.setCursor(0, 0);
ecran_oled.print("3eme afficheur");
ecran_oled.setTextSize(2);
ecran_oled.setCursor(0, 30);
ecran_oled.print("Valeur=");
ecran_oled.print(valeur_compteur);
ecran_oled.display();
// Écriture sur l'écran OLED numéro 4 (donc à travers la voie "3" du TCA9548)
changer_aiguillage_sur_TCA9548(3);
ecran_oled.clearDisplay();
ecran_oled.setTextColor(WHITE);
ecran_oled.setTextSize(1);
ecran_oled.setCursor(0, 0);
ecran_oled.print("4eme afficheur");
ecran_oled.setTextSize(2);
ecran_oled.setCursor(0, 30);
ecran_oled.print("Valeur=");
ecran_oled.print(valeur_compteur);
ecran_oled.display();
// On augmente le compteur d'un, on attend une seconde, et on reboucle (à l'infini !)
valeur_compteur++;
delay(1000);
}
Au passage, une fois ce code uploadé dans votre Arduino Nano, vous avez la possibilité de jeter un coup d’œil au moniteur série de l’IDE arduino, afin de vous assurer que toutes les initialisations se soient bien passées. Si tel est le cas, vous devriez obtenir un écran ressemblant à cela :
Côté montage « en action », voici quelques photos prises au moment des essais (l’alimentation du montage étant assurée par l’alim USB v2 sans-fil fait-maison, à base d’accus lithium-ion 18650, que je vous avais présenté dernièrement) :
Cela illustre bien le fait qu’il est donc possible, avec un multiplexeur I2C, d’individuellement piloter plusieurs périphériques ayant pourtant la même adresse I²C, et ce, à partir d’un seul et unique bus i2c côté microcontrôleur ! Sympa, non ?
Remarque : différence entre TCA9548 vs PCA9548 (ou Tca9548a vs Pca9548a)
En pratique, vous rencontrerez peut-être souvent le modèle PCA9548 (ou PCA9548A) au lieu du TCA9548 (ou TCA9548A).
En fait, pour faire simple, il s’agit des mêmes composants ! Ou presque … 😉
En effet, au final, le TCA9548A est plus ou moins une version améliorée du PCA9548A (avec une plage de tension d’alimentation étendue, et des améliorations au niveau performances). En clair, ils sont équivalents (niveau brochage et fonctionnalités), même s’ils ne sont pas exactement les mêmes en interne !
Module | Description | Lien |
---|---|---|
Module TCA9548A monté sur PCB (multiplexeur i2c à 8 voies) |
TCA9548 arduino : conclusion !
Voilà ! Vous arrivez au terme de cet article sur le multiplexeur i2c TCA9548A, très utile donc si vous faites appel à bon nombre de périphériques I2C ayant la même adresse physique ! De quoi enrichir grandement ses projets, si besoin 😉
Il est temps pour moi de vous laisser et de vous dire à très vite, avec de nombreuses réalisations à vous partager prochainement !
À bientôt,
Jérôme.
À découvrir aussi : le module PCF 8574 pour ajouter tout un tas d’entrées/sorties à son Arduino !
(*) Mis à jour le 09/11/2024
Bonjour,
Sujet très intéressant qui permet de solutionner le manque de périphériques possibles sur des petits microcontôleurs pour pas cher.
Super !
Bonjour et merci pour les explications très détaillées, la vidéo est très convaincante !
Super. Les explications sont claires et précises.
Merci
Bonjour. Fantastique article. Je pourrais m’en servir un jour pour multiplier les afficheurs dans les gares de mon train miniature.
Bonjour
Je ne connaissais pas ce composant.
C’est parfait pour récupérer sur un seul arduino les températures de 8 capteurs AHT21. Ils sont en en I2C, adresse 0x38, mais cette adresse n’étant pas modifiable, je ne pouvais en connecter qu’un seul. Ce composant apporte la solution.
Merci 🙂
C’est moi qui vous remercie pour tous vos retours, ça fait plaisir !
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. Par ailleurs, j'ai malheureusement plus de messages à traiter que de temps pour y répondre ; c'est pourquoi je ne pourrais pas répondre à tout le monde. Désolé …