TCA9548A : multiplexer le bus I2C
Comme vous le savez probablement le bus I2C permet de dialoguer avec des composants à l'aide de seulement deux fils et on peut théoriquement en brancher un bon nombre :
Sur ce schéma que j'ai déjà publié sur ce blog je compare 7 capteurs météo. Le composant avec lequel on désire dialoguer est sélectionné par le logiciel.
Les composants I2C possèdent souvent une ou plusieurs broches de sélection d'adresse. Par exemple le capteur de température et humidité HDC2080 possède une broche ADD que l'on peut relier au 3.3V pour changer son adresse I2C (0x41 au lieu de 0x40 si elle est reliée à GND).
Mais certains composants ne disposent que d'une seule adresse (HTU21D, SI7021, afficheurs OLED I2C, etc.).
Le cas doit se produire plutôt rarement, mais que faire lorsque l'on est dans l'obligation d'utiliser deux composants I2C ayant la même adresse ?
Un autre cas peut se produire : certains composants mal conçus cohabitent difficilement avec d'autres sur le bus.
Le TCA9548 permet de multiplexer 8 bus I2C. Il a les caractéristiques suivantes :
- 8 bus esclaves
- alimentation 1.65V - 5.5V
- 3 broches de sélection d'adresse
C'est un circuit CMS 24 pins, mais il est facile de trouver des modules "breakboard" équipés de ce circuit (voir image ci-dessus).
1. Le schéma
Sur ce schéma le TCA9548 est alimenté sous 5V (une alimentation sous 3.3V serait parfaitement possible) et il contrôle deux modules I2C également alimentés sous 5V.
Les deux modules I2C sont branchés sur les ports I2C 2 et 3 du TCA9548.
Les broches d'adresse A0, A1 et A2 sont reliées à GND. L'adresse I2C du TCA9548 sera donc 0x70. D'autres choix sont possibles, entre 0x70 et 0x77.
2. La librairie
Il existe quelques librairies. Celle que je vais utiliser est la suivante :
https://github.com/sparkfun/SparkFun_I2C_Mux_Arduino_Library
Elle est installable depuis l'IDE ARDUINO.
3. Le code
3.1. Capteurs SHT31D
J'ai câblé un petit montage avec une carte ARDUINO NANO, le TCA9548 et 2 capteurs SHT31D A et B. L'alimentation des 3 modules est en 3.3V. Cela fonctionnerait de la même façon sous 5V, le SHT31D supportant de 2.4V à 5.5V.
La librairie Adafruit_SHT31 est nécessaire (installable depuis l'IDE).
Voici le code :
#include <Wire.h>
#include <SparkFun_I2C_Mux_Arduino_Library.h>
#include <Adafruit_SHT31.h>
QWIICMUX myMux;
Adafruit_SHT31 sht31A = Adafruit_SHT31();
Adafruit_SHT31 sht31B = Adafruit_SHT31();
void setup()
{
Serial.begin(115200);
Wire.begin();
if (myMux.begin() == false) {
Serial.println("Mux not detected. Freezing...");
while (1);
}
Serial.println("Mux detected");
byte currentPortNumber = myMux.getPort();
Serial.print("CurrentPort: ");
Serial.println(currentPortNumber);
// initialisation SHT31 A
myMux.setPort(2);
if (!sht31A.begin(0x44)) {
Serial.println("Couldn't find sensor A");
while (1) delay(1);
}
// initialisation SHT31 B
myMux.setPort(3);
if (!sht31B.begin(0x44)) {
Serial.println("Couldn't find sensor B");
while (1) delay(1);
}
}
void loop()
{
myMux.setPort(2);
float temp = sht31A.readTemperature();
float hum = sht31A.readHumidity();
Serial.print("SHT31 A temperature = ");
Serial.print(temp);
Serial.println(" *C");
Serial.print("SHT31 A humidity = ");
Serial.print(hum);
Serial.println(" %\n");
myMux.setPort(3);
temp = sht31B.readTemperature();
hum = sht31B.readHumidity();
Serial.print("SHT31 B temperature = ");
Serial.print(temp);
Serial.println(" *C");
Serial.print("SHT31 B humidity = ");
Serial.print(hum);
Serial.println(" %\n");
delay(10000);
}
Mon doigt est posé sur le capteur A. Voici ce qu'affiche le sketch :
Mux detected
CurrentPort: 255
SHT31 A temperature = 30.34 *C
SHT31 A humidity = 69.97 %
SHT31 B temperature = 22.81 *C
SHT31 B humidity = 41.96 %
A chaque fois que l'on veut communiquer avec le module A il suffit d'appeler :
myMux.setPort(2);
A chaque fois que l'on veut communiquer avec le module B il suffit d'appeler :
myMux.setPort(3);
3.2. Afficheurs OLED
On peut aisément faire la même chose avec 2 petits afficheurs OLED SSD1306, pour afficher des informations sur l'un ou sur l'autre.
Ici encore l'alimentation du TCA9548 et des écrans est en 3.3V.
La librairie de Bill Greiman SSD1306Ascii est nécessaire (installable depuis l'IDE).
Voici le code :
#include <Wire.h>
#include <SparkFun_I2C_Mux_Arduino_Library.h>
#include "SSD1306Ascii.h"
#include "SSD1306AsciiAvrI2c.h"
QWIICMUX myMux;
SSD1306AsciiAvrI2c displayA;
SSD1306AsciiAvrI2c displayB;
void setup()
{
Serial.begin(115200);
Wire.begin();
pinMode(13, OUTPUT);
if (myMux.begin() == false) {
Serial.println("Mux not detected. Freezing...");
while (1);
}
Serial.println("Mux detected");
byte currentPortNumber = myMux.getPort();
Serial.print("CurrentPort: ");
Serial.println(currentPortNumber);
delay(2000); // nécessaire à la mise sous tension
// initialisation OLED A
myMux.setPort(2);
Serial.println("initialisation OLED A");
displayA.begin(&Adafruit128x32, 0x3C);
displayA.setFont(System5x7);
displayA.set1X();
displayA.setCursor(0, 0);
displayA.clearToEOL();
displayA.print("INITIALIZED");
// initialisation OLED B
myMux.setPort(3);
Serial.println("initialisation OLED B");
displayB.begin(&Adafruit128x32, 0x3C);
displayB.setFont(System5x7);
displayB.set1X();
displayB.setCursor(0, 0);
displayB.clearToEOL();
displayB.print("INITIALIZED");
delay(500);
displayA.set2X();
displayB.set2X();
digitalWrite(13, HIGH);
}
void loop()
{
static int toggle = -1;
myMux.setPort(2);
displayA.setCursor(0, 0);
displayA.clearToEOL();
if (toggle != HIGH) {
displayA.print("SCREEEN A");
}
myMux.setPort(3);
displayB.setCursor(0, 0);
displayB.clearToEOL();
if (toggle != LOW) {
displayB.print("SCREEEN B");
}
delay(1000);
toggle = toggle == LOW ? HIGH : LOW;
}
Un délai d'au moins une seconde est nécessaire entre l'initialisation du TCA9548 et celle des écrans, si l'on met sous tension le montage. Lors d'un reset ce délai n'est pas utile. Je n'ai pas d'explication.
3.3. Adresse du TCA9548
A noter : si l'on désire utiliser une adresse alternative du TCA9548 il suffit de passer cette adresse à la méthode begin() :
if (myMux.begin(0x71) == false) {
Serial.println("Mux not detected. Freezing...");
while (1);
}
Dans ce cas (0x71) il faudra relier la broche A0 au +5V, ou 3.3V, suivant le cas.
4. Conclusion
Voici un petit composant bien pratique lorsque l'on est confronté à une situation de conflit sur un bus I2C.
Cordialement
Henri
Merci Henri pour cet article, je vais essayer de mettre en application avec 2 écrans 128x32 ( adresse i2c unique) que je possède pour un affichage d'infos de torque moteur dans mon simulateur d'avion à partir d'une Nano
RépondreSupprimerBernard
Si les deux afficheurs sont éloignés l'un de l'autre, ou sur deux faces d'un boîtier, c'est intéressant, sinon il existe des 128x64.
RépondreSupprimerBonjour et merci pour ce petit tuto , j aimerais savoir si la démarche est la même avec deux matrix-bicolore 8x8 ayant la même adresse? car j'ai testé a ma manière en suivant un peu la tient mais aucun résultat.
RépondreSupprimerPavrick
matrix-bicolore 8x8 : c'est assez imprécis comme description. Que dire ?
SupprimerSi ce sont bien des matrices I2C du genre Adafruit LED Backpack, il n'y a pas de raison que cela ne fonctionne pas, avec la librairie qui convient à ces matrices.
Effectivement il s'agit bien de ces matrice. voici mon code au niveau du setup je pense que c'est la ou viens le problème vu que' au niveau du terminal il y'a ecrit MAT NOT DETECTED .j'aurais vraiment besoin d'une aide de votre part pour m identifier ce qui ne va pas.Merci
Supprimer#include
#include
#include "Adafruit_LEDBackpack.h"
#include
QWIICMUX TCA;
Adafruit_BicolorMatrix matrixG = Adafruit_BicolorMatrix();
Adafruit_BicolorMatrix matrixD = Adafruit_BicolorMatrix();
void setup(void) {
Serial.begin(9600);
Wire.begin();
if (TCA.begin(0x74) == false) {
Serial.println("Mat not detected\n");
while (1);
}
Serial.println("8x8 LED Matrix Test");
TCA.setPort(2);
if (!matrixG.begin(0x70)) {
Serial.println("Couldn't find matrixG");
while (1) delay(1);
}
TCA.setPort(6);
if (!matrixD.begin(0x70)) {
Serial.println("Couldn't find matrixG");
while (1) delay(1);
}
}
voici les librairies utilisées
Supprimer#include < Wire.h >
#include < Adafruit_GFX.h >
#include "Adafruit_LEDBackpack.h"
#include < SparkFun_I2C_Mux_Arduino_Library.h >
Je conseillerais d'utiliser le sketch i2c-scanner (chercher sur google), afin de déterminer la vraie adresses I2C du TCA9548.
Supprimermerci beaucoup pour votre aide finalement sa fonctionne il s'agit bien de trouver la bonne adresse encore merci
Supprimersans oublier que j'utilise un Arduino méga 2560
RépondreSupprimer