Průvodce pro TCA9548A I2C multiplexer: ESP32

04.03.2023 Arduino #i2c #esp32 #multiplexer

Příklad, jak rozšířit porty sběrnice I2C (ESP32, ESP8266, Arduino) pomocí multiplexeru TCA9458A 1-to-8 I2C. Tento kus hardwaru je užitečný, pokud chcete ovládat více I2C zařízení se stejnou I2C adresou. Například více OLED displejů nebo více senzorů jako BME280.


Představení TCA9548A 1-to-8 I2C multiplexer

Komunikační protokol I2C vám umožňuje komunikovat s více zařízeními I2C na stejné sběrnici I2C, pokud všechna zařízení mají jedinečnou adresu I2C. Nebude to však fungovat, pokud chcete připojit více I2C zařízení se stejnou adresou.

I2C multiplexer TCA9548A umožňuje komunikovat až s 8 I2C zařízeními se stejnou I2C sběrnicí. Multiplexer komunikuje s mikrokontrolérem pomocí komunikačního protokolu I2C. Poté můžete vybrat, kterou I2C sběrnici na multiplexeru chcete adresovat.

Chcete-li adresovat konkrétní port, stačí do multiplexeru poslat jeden bajt s požadovaným číslem výstupního portu.

Vlastnosti multiplexeru TCA9548A

Zde je shrnutí jeho hlavních funkcí:

  • 1 až 8 obousměrných překládacích spínačů
  • Aktivní-nízký resetovací vstup
  • Tři adresové kolíky – až 8 zařízení TCA9548A na stejné sběrnici I2C
  • Výběr kanálu přes I2C sběrnici
  • Rozsah provozního napájecího napětí: 1,65V až 5,5V
  • 5V tolerantní piny

Podrobnější popis naleznete v datovém listu.

Adresa I2C multiplexeru TCA9548A

Multiplexer TCA9548A komunikuje s mikrokontrolérem pomocí komunikačního protokolu I2C. Potřebuje tedy I2C adresu. Adresa multiplexeru je konfigurovatelná. Můžete vybrat hodnotu od 0x70 do 0x77 úpravou hodnot pinů A0, A1 a A2, jak je uvedeno v tabulce níže.

A0 A1 A2 Adresa I2C
LOW LOW LOW 0x70
HIGH LOW LOW 0x71
LOW HIGH LOW 0x72
HIGH HIGH LOW 0x73
LOW LOW HIGH 0x74
HIGH LOW HIGH 0x75
LOW HIGH HIGH 0x76
HIGH HIGH HIGH 0x77

Na stejnou I2C sběrnici tedy můžete připojit až 8 multiplexerů TCA9548A, což vám umožní připojit 64 zařízení se stejnou adresou pouze pomocí jedné I2C sběrnice mikrokontroléru.

Například pokud se připojíteA0,A1, aA2na GND, nastaví adresu 0x70 pro multiplexer.

Pinout TCA9548A

Následující tabulka popisuje Pinout TCA9584A.

Kolík Popis
VIN Napájí multiplexer
GND Připojte k GND
SDA Připojte ke kolíku SDA hlavního mikrokontroléru
SCL Připojte ke kolíku SCL hlavního mikrokontroléru
RST Active low RST pin—lze použít k resetování multiplexeru
A0 Vybírá I2C adresu multiplexeru – připojte se ke GND nebo VCC
A1 Vybírá I2C adresu multiplexeru – připojte se ke GND nebo VCC
A2 Vybírá I2C adresu multiplexeru – připojte se ke GND nebo VCC
SD0 SDA pro kanál 0
SC0 SCL pro kanál 0
SD1 SDA pro kanál 1
SC1 SCL pro kanál 1
SD2 SDA pro kanál 2
SC2 SCL pro kanál 2
SD3 SDA pro kanál 3
SC3 SCL pro kanál 3
SD4 SDA pro kanál 4
SC4 SCL pro kanál 4
SD5 SDA pro kanál 5
SC5 SCL pro kanál 5
SD6 SDA pro kanál 6
SC6 SCL pro kanál 6
SD7 SDA pro kanál 7
SC7 SCL pro kanál 7

TCA9548A I2C multiplexer - výběr sběrnice I2C

Jak již bylo zmíněno dříve, pro výběr konkrétní I2C sběrnice pro čtení/zápis dat stačí odeslat jeden bajt do multiplexeru s požadovaným číslem výstupního portu (0 až 7).

K tomu můžete jednoduše použít následující uživatelsky definovanou funkci:

void TCA9548A(uint8_t bus){
  Wire.beginTransmission(0x70);  // TCA9548A address is 0x70
  Wire.write(1 << bus);          // send byte to select bus
  Wire.endTransmission();
  Serial.print(bus);
}

Poté stačí zavolat tuto funkci a před odesláním příkazů I2C předat jako argument číslo portové sběrnice, kterou chcete ovládat. Chcete-li například ovládat zařízení připojené ke sběrnici číslo 3, před voláním dalších příkazů I2C byste zavolali následující řádek (všimněte si, že začíná na 0):

TCA9548A(2);

Více OLED displejů s I2C multiplexním obvodem

Připojte čtyři OLED displeje, jak je znázorněno na následujícím schématu. Používáme autobusy číslo 2, 3, 4 a 5. Můžete si vybrat jakékoli jiné číslo portu.

Také se připojujeme A0,A1, a A2 na GND. Tím se vybere adresa 0x70 pro multiplexer.

Zde jsou výchozí I2C piny v závislosti na mikrokontroléru, který používáte:

Mikrokontrolér I2C kolíky
ESP32 GPIO 22 (SCL), GPIO 21 (SDA)
ESP8266 GPIO 5 (D1) (SCL), GPIO 4 (D2) (SDA)
Arduino Uno A5 (SCL), A4 (SDA)

Instalace knihoven

K ovládání OLED displeje použijeme následující knihovny. Ujistěte se, že máte nainstalované tyto knihovny:

Pokud používáte VS Code s rozšířením PlatformIO, zkopírujte následující do platformio.ini soubor, který obsahuje knihovny.

lib_deps = adafruit/Adafruit SSD1306@^2.4.6
	adafruit/Adafruit GFX Library@^1.10.10

Zkopírujte následující kód do vašeho Arduino IDE a nahrajte jej na vaši desku. Bude to fungovat hned.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

// Select I2C BUS
void TCA9548A(uint8_t bus){
  Wire.beginTransmission(0x70);  // TCA9548A address
  Wire.write(1 << bus);          // send byte to select bus
  Wire.endTransmission();
  Serial.print(bus);
}

void setup() {
  Serial.begin(115200);

  // Start I2C communication with the Multiplexer
  Wire.begin();

  // Init OLED display on bus number 2
  TCA9548A(2);
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  } 
  // Clear the buffer
  display.clearDisplay();

  // Init OLED display on bus number 3
  TCA9548A(3);
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  } 
  // Clear the buffer
  display.clearDisplay();

  // Init OLED display on bus number 4
  TCA9548A(4);
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  } 
  // Clear the buffer
  display.clearDisplay();

  // Init OLED display on bus number 5
  TCA9548A(5);
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  } 
  // Clear the buffer
  display.clearDisplay();

  // Write to OLED on bus number 2
  TCA9548A(2);
  display.clearDisplay();
  display.setTextSize(8);
  display.setTextColor(WHITE);
  display.setCursor(45, 10);
  // Display static text
  display.println("1");
  display.display(); 

  // Write to OLED on bus number 3
  TCA9548A(3);
  display.clearDisplay();
  display.setTextSize(8);
  display.setTextColor(WHITE);
  display.setCursor(45, 10);
  // Display static text
  display.println("2");
  display.display(); 

  // Write to OLED on bus number 4
  TCA9548A(4);
  display.clearDisplay();
  display.setTextSize(8);
  display.setTextColor(WHITE);
  display.setCursor(45, 10);
  // Display static text
  display.println("3");
  display.display(); 

  // Write to OLED on bus number 5
  TCA9548A(5);
  display.clearDisplay();
  display.setTextSize(8);
  display.setTextColor(WHITE);
  display.setCursor(45, 10);
  // Display static text
  display.println("4");
  display.display(); 
}

void loop() {

}

Jak kód funguje

Nejprve naimportujte požadované knihovny pro ovládání OLED displeje: Adafruit_GFX a Adafruit_SSD1306. Knihovna Wire je pro použití komunikačního protokolu I2C.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

Definujte šířku a výšku OLED.

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

Vytvořit Adafruit_SSD1306 pro komunikaci s OLED displejem.

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

Ke komunikaci se všemi displeji můžete použít stejnou instanci. V takovém případě musíte vymazat vyrovnávací paměť displeje (display.clearDisplay()) před zápisem do jiného OLED.

Případně můžete vytvořit více Adafruit_SSD1306 instance, jedna pro každý OLED. V takovém případě nemusíte vyrovnávací paměť mazat.

Vyberte kanál I2C

TheTCA9548A()lze zavolat funkci pro výběr sběrnice, se kterou chcete komunikovat. Odešle bajt do multiplexeru s číslem portu.

// Select I2C BUS
void TCA9548A(uint8_t bus){
  Wire.beginTransmission(0x70);  // TCA9548A address
  Wire.write(1 << bus);          // send byte to select bus
  Wire.endTransmission();
  Serial.print(bus);
}

Tuto funkci musíte volat vždy, když chcete vybrat port I2C.

setup()

V setup(), inicializovat sériovou komunikaci pro účely ladění.

Serial.begin(115200);

Spusťte I2C komunikaci na výchozích I2C pinech s I2C multiplexerem.

Wire.begin();

Poté inicializujte každý displej. Následující řádky ukazují příklad pro první OLED displej (je připojen na sběrnici číslo 2).

//Init OLED display on bus number 2
TCA9548A(2);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
  Serial.println(F("SSD1306 allocation failed"));
  for(;;);
} 
// Clear the buffer
display.clearDisplay();

Inicializace ostatních displejů je podobná, ale musíte zavolatTCA9548A()funkce s odpovídajícím číslem sběrnice I2C.

Pak něco napište na displeje. Nezapomeňte, že musíte zavolatTCA9548A()funkce pokaždé, když chcete přepínat mezi OLED. Před zápisem čehokoli na OLED také musíte vymazat vyrovnávací paměť displeje.

// Write to OLED on bus number 2
TCA9548A(2);
display.clearDisplay();
display.setTextSize(8);
display.setTextColor(WHITE);
display.setCursor(45, 10);
// Display static text
display.println("1");
display.display(); 

V tomto případě pouze tiskneme na každý displej jiné číslo. Zde je příklad pro OLED číslo 4 (je připojen ke sběrnici číslo 5).

// Write to OLED on bus number 5
TCA9548A(5);
display.clearDisplay();
display.setTextSize(8);
display.setTextColor(WHITE);
display.setCursor(45, 10);
// Display static text
display.println("4");
display.display();

A takto kód funguje.

Následující kód ukazuje podobný příklad, ale s použitím víceAdafruit_SSD1306instance. Všimněte si, že před zápisem na displej není nutné vymazat vyrovnávací paměť.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

Adafruit_SSD1306 display1(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
Adafruit_SSD1306 display2(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
Adafruit_SSD1306 display3(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
Adafruit_SSD1306 display4(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

// Select I2C BUS
void TCA9548A(uint8_t bus){
  Wire.beginTransmission(0x70);  // TCA9548A address
  Wire.write(1 << bus);          // send byte to select bus
  Wire.endTransmission();
  Serial.print(bus);
}

void setup() {
  Serial.begin(115200);

  // Start I2C communication with the Multiplexer
  Wire.begin();

  // Init OLED display on bus number 2 (display 1)
  TCA9548A(2);
  if(!display1.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  } 
  // Clear the buffer
  display1.clearDisplay();

  // Init OLED display on bus number 3
  TCA9548A(3);
  if(!display2.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  } 
  // Clear the buffer
  display2.clearDisplay();

  // Init OLED display on bus number 4
  TCA9548A(4);
  if(!display3.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  } 
  // Clear the buffer
  display3.clearDisplay();

  // Init OLED display on bus number 5
  TCA9548A(5);
  if(!display4.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  } 
  // Clear the buffer
  display4.clearDisplay();

  // Write to OLED on bus number 2
  TCA9548A(2);
  display1.setTextSize(8);
  display1.setTextColor(WHITE);
  display1.setCursor(45, 10);
  // Display static text
  display1.println("1");
  display1.display(); 

  // Write to OLED on bus number 3
  TCA9548A(3);
  display2.setTextSize(8);
  display2.setTextColor(WHITE);
  display2.setCursor(45, 10);
  // Display static text
  display2.println("2");
  display2.display(); 

  // Write to OLED on bus number 4
  TCA9548A(4);
  display3.setTextSize(8);
  display3.setTextColor(WHITE);
  display3.setCursor(45, 10);
  // Display static text
  display3.println("3");
  display3.display(); 

  // Write to OLED on bus number 5
  TCA9548A(5);
  display4.setTextSize(8);
  display4.setTextColor(WHITE);
  display4.setCursor(45, 10);
  // Display static text
  display4.println("4");
  display4.display();
}

void loop() {

}

Čtení více snímačů BME280 — TCA9548A I2C multiplexer

V této části se dozvíte, jak číst data z více snímačů BME280 pomocí multiplexeru TCA9548A I2C. Budeme číst data ze čtyř senzorů, ale můžete připojit až 8 senzorů.

Připojte čtyři snímače BME280, jak je znázorněno na následujícím schématu. Používáme autobusy číslo 2, 3, 4 a 5. Můžete si vybrat jakákoli jiná čísla portů.

Také se připojujeme A0, A1, a A2 na GND. Tím se vybere adresa 0x70 pro multiplexer.

Zde jsou výchozí I2C piny v závislosti na mikrokontroléru, který používáte:

Mikrokontrolér I2C kolíky
ESP32 GPIO 22 (SCL), GPIO 21 (SDA)
ESP8266 GPIO 5 (D1) (SCL), GPIO 4 (D2) (SDA)
Arduino Uno A5 (SCL), A4 (SDA)

Instalace knihoven

Ke čtení ze snímače BME280 použijeme následující knihovny. Ujistěte se, že máte nainstalované tyto knihovny:

Knihovny můžete nainstalovat pomocí Správce knihoven Arduino. Přejděte do  Skica  >  Zahrnout knihovnu  >  Spravovat knihovny  a vyhledejte název knihovny.

Pokud používáte VS Code s rozšířením PlatformIO, zkopírujte následující doplatformio.inisoubor, který obsahuje knihovny.

lib_deps = adafruit/Adafruit Unified Sensor @ ^1.1.4
            adafruit/Adafruit BME280 Library @ ^2.1.2 

Po instalaci knihoven můžete pokračovat.

Zkopírujte následující kód do vašeho Arduino IDE a nahrajte jej na vaši desku. Bude to fungovat hned.

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

#define SEALEVELPRESSURE_HPA (1022)

Adafruit_BME280 bme1; // I2C
Adafruit_BME280 bme2; // I2C
Adafruit_BME280 bme3; // I2C
Adafruit_BME280 bme4; // I2C

// Select I2C BUS
void TCA9548A(uint8_t bus){
  Wire.beginTransmission(0x70);  // TCA9548A address
  Wire.write(1 << bus);          // send byte to select bus
  Wire.endTransmission();
}

void printValues(Adafruit_BME280 bme, int bus) {
  TCA9548A (bus);
  Serial.print("Sensor number on bus");
  Serial.println(bus);
  Serial.print("Temperature = ");
  Serial.print(bme.readTemperature());
  Serial.println(" *C");

  Serial.print("Pressure = ");
  Serial.print(bme.readPressure() / 100.0F);
  Serial.println(" hPa");

  Serial.print("Approx. Altitude = ");
  Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
  Serial.println(" m");

  Serial.print("Humidity = ");
  Serial.print(bme.readHumidity());
  Serial.println(" %");

  Serial.println();
}

void setup() {
  Serial.begin(115200);

  // Start I2C communication with the Multiplexer
  Wire.begin();

  // Init sensor on bus number 2
  TCA9548A(2);
  if (!bme1.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor on bus 2, check wiring!");
    while (1);
  }
  Serial.println();

  // Init sensor on bus number 3
  TCA9548A(3);
  if (!bme2.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor on bus 2, check wiring!");
    while (1);
  }
  Serial.println();

  // Init sensor on bus number 4
  TCA9548A(4);
  if (!bme3.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor on bus 2, check wiring!");
    while (1);
  }
  Serial.println();

  // Init sensor on bus number 5
  TCA9548A(5);
  if (!bme4.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor on bus 2, check wiring!");
    while (1);
  }
  Serial.println();
}

void loop() { 
  //Print values for sensor 1
  printValues(bme1, 2);
  printValues(bme2, 3);
  printValues(bme3, 4);
  printValues(bme4, 5);
  delay(5000);
}

Jak kód funguje

Nejprve importujte požadované knihovny pro ovládání displeje BME280: Adafruit_BME280 a Adafruit_Sensor. Knihovna Wire pro použití komunikačního protokolu I2C.

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

Poté musíte vytvořit několik instancí Adafruit_BME280, jeden pro každý senzor:bme1, bme2, bme3, a bme4.

Adafruit_BME280 bme1; // I2C
Adafruit_BME280 bme2; // I2C
Adafruit_BME280 bme3; // I2C
Adafruit_BME280 bme4; // I2C

Vyberte kanál I2C

TCA9548A() lze zavolat funkci pro výběr sběrnice, se kterou chcete komunikovat. Odešle bajt do multiplexeru s číslem portu.

// Select I2C BUS
void TCA9548A(uint8_t bus){
  Wire.beginTransmission(0x70);  // TCA9548A address
  Wire.write(1 << bus);          // send byte to select bus
  Wire.endTransmission();
  Serial.print(bus);
}

Tuto funkci musíte volat vždy, když chcete vybrat port I2C.

Funkce printValues()

Poté vytvoříme funkci printValues() což nám umožňuje vytisknout v Serial Monitor hodnoty pro každý senzor. Tato funkce nám umožňuje předat Adafruit_BME280 instance a její sběrnice.

Uvnitř funkce vybereme I2C sběrnici, se kterou chceme hovořit, zavoláním na TCA9548A() funkce a projetí autobusem jako argument.

TCA9548A (bus);

Poté použijeme obvyklé funkce k získání hodnot ze senzoru.

Serial.print("Sensor number on bus");
Serial.println(bus);
Serial.print("Temperature = ");
Serial.print(bme.readTemperature());
Serial.println(" *C");

Serial.print("Pressure = ");
Serial.print(bme.readPressure() / 100.0F);
Serial.println(" hPa");

Serial.print("Approx. Altitude = ");
Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
Serial.println(" m");

Serial.print("Humidity = ");
Serial.print(bme.readHumidity());
Serial.println(" %");

setup()

V setup(), inicializovat sériovou komunikaci pro účely ladění.

Serial.begin(115200);

Spusťte I2C komunikaci na výchozích I2C pinech s I2C multiplexerem.

Wire.begin();

Poté inicializujte každý senzor. Následující řádky ukazují příklad prvního snímače BME280 (je připojen na sběrnici číslo 2 a odkazuje na bme1 instance).

//Init sensor on bus number 2
TCA9548A(2);
if (!bme1.begin(0x76)) {
  Serial.println("Could not find a valid BME280 sensor on bus 2, check wiring!");
  while (1);
}
Serial.println();

Inicializace ostatních senzorů je podobná, ale musíte zavolatTCA9548A()funkce s odpovídajícím číslem sběrnice I2C. Také nezapomeňte, že každý senzor má svou vlastní instanci.

loop()

V loop(), nazýváme printValues() funkce pro každý senzor.

printValues(bme1, 2);
printValues(bme2, 3);
printValues(bme3, 4);
printValues(bme4, 5);

Literatura:

Guide for TCA9548A I2C Multiplexer: ESP32, ESP8266, ArduinoRandom Nerd Tutorials [online]. USA: RNT, 2022 [cit. 2022-08-19]. Dostupné z: https://randomnerdtutorials.com/tca9548a-i2c-multiplexer-esp32-esp8266-arduino/