Иногда вам может понадобиться использовать с Ардуино более одного устройства с одним и тем же адресом I2C шины. Например, четыре OLED-дисплея для большого дисплея или семь датчиков температуры в инкубаторе.
Проблемы такого типа можно решить с помощью мультиплексора TCA9548A 1-to-8, и в этой статье мы рассмотрим, как это сделать с некоторыми примерами.
Приступая к работе
Во-первых, рассмотрим сам мультиплексор TCA9548A. TCA9548A — это шлюз между вашим Ардуино и восемью отдельными I2C шинами.
Стороны TCA9548A у вас есть одна шина с Ардуино. С другой стороны TCA9548A у вас есть восемь шин I2C, и только одна из них может быть подключена к Ардуино одновременно.
TCA9548 может функционировать при напряжении от 1,8 до 5 В и работать с устройствами, которые имеют рабочее напряжение от 1,8 до 5 В. Это очень удобно, так как, например,вы можете использовать устройства с питанием 3,3В с 5 вольтовой Ардуино. Итак, приступим.
Вставьте модуль в макетную плату и подключите его, как показано ниже:
Мы используем красные и синие линии питания макетной платы как 5В и GND соответственно. Подключим 5В и GND от Ардуино к линии питания макетной платы. Выводы A0, A1 и A2 подключим к GND, а A4/A5 к SDA/SCL соответственно к модулю:
Электрические соединения следующие (модуль TCA9548 — Ардуино):
- Vin к 5В
- GND к GND
- A0 к GND
- A1 к GND
- A2 к GND
- SDA к A4
- SCL к A5
Далее мы рассмотрим адрес I2C шины для TCA9548A. Используя схему подключения, показанную выше, адрес I2C шины будет 0x70. Вам нужно изменить его только в том случае, если одно из ваших устройств также имеет адрес 0x70.
Изменение адреса I2C TCA9548A
Адрес I2C шины TCA9548A путем подключения контактов A0, A1 и A2 модуля TCA9548A. По умолчанию мы используем адрес 0x70, подключив A0…A2 к GND (низкий уровень сигнала). Используя ниже приведенную таблицу, вы можете изменить конфигурацию, выбрав необходимый адрес из диапазона 0x70…0x77:

Тестирование
Сейчас нам необходимо проверить правильность подключения модуля TCA9548A к Ардуино, запустив скетч сканера I2C, который вернет адрес шины подключенного устройства.
Скопируйте и вставьте этот скетч в Ардуино IDE и загрузите его:
#include <Wire.h> void setup() { Wire.begin(); Serial.begin(115200); Serial.println("\nI2C Scanner"); } void loop() { byte error, address; int nDevices; Serial.println("Scanning..."); nDevices = 0; for(address = 1; address < 127; address++ ) { Wire.beginTransmission(address); error = Wire.endTransmission(); if (error == 0) { Serial.print("I2C device found at address 0x"); if (address<16) { Serial.print("0"); } Serial.println(address,HEX); nDevices++; } else if (error==4) { Serial.print("Unknow error at address 0x"); if (address<16) { Serial.print("0"); } Serial.println(address,HEX); } } if (nDevices == 0) { Serial.println("No I2C devices found\n"); } else { Serial.println("done\n"); } delay(5000); }
Затем откройте монитор последовательного порта и установите скорость передачи данных 115200. Вы должны увидеть что-то вроде этого:
Как видите, наш сканер вернул адрес 0x70, что соответствует схеме подключения, описанной в таблице адресов шины, упомянутой ранее. Если вы не добились успеха, отключите Ардуино от компьютера и хорошенько проверьте проводку — затем попробуйте еще раз.
Управление селектором шины
Применение TCA9548A простое – для подключения вашего устройства к I2C в обычном режиме необходимо проинструктировать TCA9548A использовать одну из восьми шин, которыми он управляет.
Для этого мы отправляем байт данных в регистр шины TCA9548A, который указывает, какую из восьми шин мы хотим использовать. Каждый бит байта используется для включения или выключения определенной шины, причем MSB (старший значащий бит) — для шины 7 и LSB (младший значащий бит) — для шины 0.
Например, если вы отправили:
0b00000001 (в двоичном формате) — это активирует нулевую шину.
0b00010000 (в двоичном формате) — это активирует пятую шину.
Как только вы выбрали определенную шину, TCA9548A перенаправляет все данные из I2C Ардуино в эту шину.
По большому счету управление всеми восьми устройствами сводится к выбору необходимой I2C шины перед отправкой данных с Ардуино. Как это делать, мы продемонстрируем позже.
Чтобы облегчить себе жизнь, мы можем написать небольшую функцию для легкого выбора необходимой шины:
void TCA9548A(uint8_t bus) { Wire.beginTransmission(0x70); // TCA9548A адрес 0x70 Wire.write(1 << bus); // отправляем байт на выбранную шину Wire.endTransmission(); }
Эта функция принимает номер шины и помещает «1» в регистр шины TCA9548A в соответствии с нашими требованиями. Затем вы просто вызываете эту функцию прямо перед тем, как потребуется получить доступ к устройству на определенной шине I2C. Например:
устройство на шине 0: TCA9548A (0)
устройство на шине 6: TCA9548A (6)
Краткое замечание о подтягивающих резисторах
Вам по-прежнему необходимо использовать подтягивающие резисторы на всех восьми шинах I2C, идущих от TCA9548A. Если вы используете готовый модуль, например, такой как в нашем случае, то на нем уже имеются такие резисторы и вам не нужно о них беспокоиться.
В противном случае проверьте datasheet своих устройств, чтобы определить подходящее сопротивление подтягивающих резисторов. Если такая информация недоступна, попробуйте использовать резисторы сопротивлением 10 кОм.
Управляем нашим первым устройством
В качестве примера используем крошечный OLED-дисплей с диагональю 0,49 дюйма. Он имеет четыре контакта, которые необходимо подключить следующим образом (OLED — TCA9548A/Ардуино):
- GND к GND
- Vcc к Ардуино 3,3 В
- CL к TCA9548A SC0 (шина № 0)
- DA к TCA9548A SD0 (шина № 0)
OLED работает от 3,3В, поэтому мы запитываем его напрямую от вывода 3,3В Ардуино.
Теперь скопируйте и загрузите нижеприведенный скетч в Ардуино, и через мгновение на OLED-дисплее отобразятся некоторые числа, отсчитывающиеся в обратном порядке:
#include <Arduino.h> #include <U8g2lib.h> #include <Wire.h> void TCA9548A(uint8_t bus) { Wire.beginTransmission(0x70); // TCA9548A адрес 0x70 Wire.write(1 << bus); // отправляем байт на выбранную шину Wire.endTransmission(); } U8G2_SSD1306_64X32_1F_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); void setup() { Wire.begin(); u8g2.begin(); } void loop() { TCA9548A(0); // сообщаем TCA9548A, что мы хотим использовать I2C шину №0 (для связи с OLED) for (int a = 999; a >= 0; --a) { u8g2.clearBuffer(); // очищаем внутреннюю память u8g2.setFont(u8g2_font_inb24_mr ); // выбираем подходящий шрифт u8g2.setCursor(0, 24); u8g2.print(a); a = a - 47; u8g2.sendBuffer(); // выводим содержимое внутренней памяти дисплея delay(100); } }
Как это работает? Мы вставили функцию выбора шины в строку 9 скетча, а затем вызвали функцию в строке 26, чтобы сообщить TCA9548A, что мы хотим использовать нулевую I2C шину. Затем остальная часть скетча – обычное использование OLED дисплея.
Управление двумя устройствами
Добавим еще одно устройство — модуль датчика атмосферного давления BMP180. Мы подключим его к седьмой I2C шине TCA5948A. В данном случае к предыдущей схеме нужно добавить еще два соединения, а именно (BMP180 — TCA9548A/Ардуино):
- CL к TCA9548A SC7 (шина № 7)
- DA к TCA9548A SD7 (шина № 7)
Теперь скопируйте и загрузите нижеприведенный скетч в Ардуино, и через мгновение на OLED дисплее появиться температура окружающей среды в целых градусах Цельсия:
#include <Arduino.h> #include <U8g2lib.h> #include <Adafruit_BMP085.h> #include <Wire.h> U8G2_SSD1306_64X32_1F_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); Adafruit_BMP085 bmp; int temperature; void TCA9548A(uint8_t bus) { Wire.beginTransmission(0x70); // TCA9548A адрес 0x70 Wire.write(1 << bus); // отправляем байт на выбранную шину Wire.endTransmission(); } void setup() { Wire.begin(); u8g2.begin(); TCA9548A(7); // выбираем I2C шину №7 для BMP180 if (!bmp.begin()) { Serial.println("Could not find a valid BMP085 sensor, check wiring!"); while (1) {} } } void loop() { // сначала получаем температуру от BMP180 TCA9548A(7); // выбираем I2C шину №7 для BMP180 temperature = int(bmp.readTemperature()); // далее отображаем температуру на OLED TCA9548A(0); // выбираем I2C шину №0 для OLED u8g2.clearBuffer(); // очищаем внутреннюю память u8g2.setFont(u8g2_font_inb24_mr ); // выбираем подходящий шрифт u8g2.setCursor(0, 24); u8g2.print(temperature); u8g2.sendBuffer(); delay(100); }
Как это работает? Мы как обычно настраиваем библиотеки и необходимый код для OLED, BMP180 и TCA5948A.
Нам нужно инициализировать BMP180. Для этого сначала в строке 29 мы выбираем I2C шину №7 перед запуском BMP180.
В строке 40 мы снова запрашиваем I2C шину №7 у TCA9548A, а затем считываем температуру от BMP180. В строке 44 мы запрашиваем I2C шину №0 у TCA9548A, а затем отображаем температуру на OLED. Затем все повторяется снова.
Краткое примечание о контакте сброса
Более продвинутые пользователи будут рады узнать, что они могут сбросить статус TCA9548A, чтобы восстановиться работу после сбоя шины. Для этого просто подайте на контакт RESET низкий логический уровень.
Теперь с помощью нашего рабочего примера вы можете понять, насколько легко использовать TCA9548A и получить доступ ко всем восьми шинам I2C через одну шину вашего Ардуино.

Прекрасная статья, всё написано ясно и четко, просто бери и делай! Спасибо.