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/