Второй экран я купил для той же полки: сверху время, снизу список будильников. Модули оказались братьями-близнецами — LCD1602 с одинаковыми переходниками PCF8574, оба по умолчанию на 0x27. Каждый по отдельности работал идеально. Вместе — тишина и мусор: верхний рисовал кракозябры, нижний молчал, а сканер упрямо видел ровно один адрес 0x27, хотя на шине висели два устройства.
Это и есть конфликт адресов — редкий у разных модулей и почти законный у одинаковых. Для пары «LCD плюс часы» проблемы не бывает — 0x27 и 0x68 далеки друг от друга, мы их расселяли в уроке про LCD и RTC на одной шине. Здесь разберём самое интересное: что физически происходит на шине, когда двое откликаются на одно имя, как сдвинуть адрес джамперами A0-A2 и когда достаёшь последний аргумент — мультиплексор TCA9548A, который вместо перемычек даёт восемь независимых шин.
Двое на одно имя: что происходит на шине
Механика поломки простая и беспощадная. Мастер открывает передачу на адрес 0x27 — и откликаются оба: оба начинают двигать линию SDA в такт. Пока биты совпадают, шина живёт как ни в чём не бывало. Расходятся биты — и два транзистора тянут линию в разные стороны: один к земле, другой отпускает её к подтяжке. На линии получается средний уровень, мастер читает не то, что передавалось, — мусор. Хуже того: конфликт нестабилен — повезёт с битами, кадр пройдёт; не повезёт — кадр битый, поэтому симптомы плавают от запуска к запуску.
Диагноз ставится по трём симптомам. Первый: каждый модуль по отдельности работает идеально. Второй: вместе — мусор или тишина. Третий: сканер показывает один адрес, хотя устройств заведомо два. Сканер при этом не виноват — он честно сообщает, что на 0x27 кто-то есть; различить двоих он не в состоянии, для этого и придуманы джамперы. Тот же конфликт поджидает не только одинаковые экраны: часы DS3231 и гироскоп MPU6050 оба живут на 0x68 — об этой паре мы вспоминали в уроке про сканер адресов.
Насчёт страха сгоревших плат — успокою: токи при конфликте ограничены подтяжкой, миллиамперы, ничего не выгорает. Проблема в другом: данные портятся тихо. Иногда мусор виден сразу — кракозябры на экране; иногда нет: мастер читает правдоподобные, но битые значения, и часы раз в минуту показывают 45 секунд вместо 59. Логический анализатор покажет наложение фронтов, но чаще хватает трёх симптомов выше.
| Способ | Что даёт | Цена вопроса |
|---|---|---|
| Джамперы A0-A2 | 8 адресов внутри 0x20-0x27 | бесплатно, если перемычки есть на плате |
| Другая партия: PCF8574A | диапазон 0x38-0x3F | придётся купить переходник другой ревизии |
| Вторая плата и вторая шина | полная изоляция | вторая Uno и отдельные два пина на мастере |
| Мультиплексор TCA9548A | 8 независимых шин за один адрес | модуль около двух долларов и пара строк кода |
Разберём джамперы, они же адресные входы A0, A1, A2. Семибитный адрес PCF8574 складывается из двух частей: старшие четыре бита зашиты в чип — это база 0x20, а младшие три бита берутся с входов: бит равен единице, если вход подтянут к питанию, нулю — если к земле. Перебор трёх битов даёт восемь адресов: 0x20, 0x21, 0x22 и дальше до 0x27. Тот же приём у мультиплексора TCA9548A — база 0x70 и те же три входа; у OLED-экранов SSD1306 адрес меняется перепайкой одного резистора между 0x3C и 0x3D. У той же памяти AT24C32 с модуля часов три адресных входа — 0x50-0x57, целая лестница вариантов.
Мой первый тупик здесь: на дешёвом переходнике джамперов не оказалось вовсе — три площадки на плате были запаяны «в ноль», и адрес 0x27 высечен в камне. Я честно искал переключатель, которого не существовало. Выход вышел скучным: переходник с блоком джамперов стоит те же деньги, а перекусывание дорожек на площадках — работа для паяльной станции и твёрдой руки, не для вечернего макетирования.
Другие модули разъезжаются похожим образом. У гироскопа MPU6050 есть ножка ADO: на земле — 0x68, на питании — 0x69, что и спасает соседство с часами. У датчиков погоды BME280 и BMP280 вход SDO выбирает между 0x76 и 0x77. Универсальное правило: сначала даташит на предмет адресных входов, потом покупка второго однотипного модуля — и проверка сканером каждой новой двери сразу после перекидки перемычек.
Калькулятор адреса: три бита на пальцах
#include <Wire.h> // База PCF8574 зашита в чип, три младших бита берутся с джамперовvoid printAddr(byte a2, byte a1, byte a0) { byte addr = 0x20 | (a2 << 2) | (a1 << 1) | a0; Serial.print("a2="); Serial.print(a2); Serial.print(" a1="); Serial.print(a1); Serial.print(" a0="); Serial.print(a0); Serial.print(" addr=0x"); Serial.println(addr, HEX);} void setup() { Wire.begin(); Serial.begin(9600); Serial.println("Все 8 адресов PCF8574 по джамперам:"); for (byte a2 = 0; a2 <= 1; a2++) for (byte a1 = 0; a1 <= 1; a1++) for (byte a0 = 0; a0 <= 1; a0++) printAddr(a2, a1, a0);} void loop() { Wire.beginTransmission(0x27); // старый экран: стучимся как раньше byte code0 = Wire.endTransmission(); Wire.beginTransmission(0x26); // второй экран после перекидки джамперов byte code1 = Wire.endTransmission(); Serial.print("code27="); Serial.print(code0); Serial.print(" code26="); Serial.println(code1); delay(3000);}Разбор — в двух строках математики. Выражение (a2 << 2) | (a1 << 1) | a0 собирает из трёх битов число от 0 до 7: бит a2 весит 4, a1 — 2, a0 — 1. Операция ИЛИ с базой 0x20 пристаивает это число к зашитой части адреса. Проверка на пальцах: a2=1, a1=0, a0=1 — это 4+0+1=5, адрес 0x25; все три перемычки на земле — 0x20, все на питании — 0x27.
В loop() скетч пингует обе двери: старый экран на 0x27 и перекочевавший на 0x26. На живой плате оба кода должны вернуть 0 — соседи разъехались, шина снова здорова. Дальше в рабочем скетче каждому объекту LiquidCrystal_I2C достаётся свой адрес: lcd0(0x27) и lcd1(0x26), и два экрана живут на одних и тех же двух проводах независимо.
Если после перекидки сканер всё равно видит один адрес — первым подозреваемым контакт перемычки. Дешёвые перемычки-кепки болтаются на штырьках, а на части модулей перемычки запаяны «в ноль» ещё на заводе, о чём знает только даташит. Прошлитесь сканером по всему диапазону 0x20-0x27: если новая дверь не появилась ни на одном из восьми адресов, дело не в формуле, а в железе.
TCA9548A: восемь шин за один адрес
Когда конфликтных модулей много или перемычек нет, достаю мультиплексор TCA9548A. Чип-диспетчер сидит между мастером и остальными: со стороны Arduino одна шина, наружу выходят восемь независимых — SD0/SC0 до SD7/SC7. Сам мультиплексор занимает один адрес, по умолчанию 0x70, и уводится теми же джамперами A0-A2 до 0x77. Выбор канала — один байт-маска: передали бит номер n — все последующие передачи уходят на шину номер n, и устройства на остальных каналах просто не видят эти байты.
Скетч с двумя одинаковыми экранами на каналах 0 и 1 — ниже. Оговорка честности: мультиплексор движок симулятора не эмулирует, скетч рассчитан на живую плату; механику выбора адресов и пинги дверей можно посмотреть в sim-блоке выше. Модуль TCA9548A стоит около двух долларов, и это дешевле любого вечера с глючной шиной: восемь одинаковых OLED-экранов на каналах 0-7 — рабочий сценарий витрин и табло. Сканер через мультиплексор гоняют по каналам по очереди: выбрали канал ноль — прогнали сканер, выбрали канал один — снова прогнали; так собирается карта адресов всех восьми подшин. Единственная оговорка: устройства с адресами 0x70-0x77 сажают на подшины неохотно — они пересекаются с самим мультиплексором и его клонами.
#include <Wire.h>#include <LiquidCrystal_I2C.h> // Оба экрана на 0x27, но живут на разных каналах TCA9548ALiquidCrystal_I2C lcd0(0x27, 16, 2);LiquidCrystal_I2C lcd1(0x27, 16, 2); void muxSelect(byte channel) { Wire.beginTransmission(0x70); // адрес самого мультиплексора Wire.write(1 << channel); // маска: бит канала 0-7 Wire.endTransmission();} void setup() { Wire.begin(); muxSelect(0); // всё, что ниже, идёт на канал 0 lcd0.init(); lcd0.backlight(); lcd0.setCursor(0, 0); lcd0.print("Kanal 0"); muxSelect(1); // переключились на канал 1 lcd1.init(); lcd1.backlight(); lcd1.setCursor(0, 0); lcd1.print("Kanal 1");} void loop() {}Как выбираю между способами. Один конфликтующий модуль — джамперы или другая партия: бесплатно и без новых деталей. Перемычек нет, а перекусывать дорожки не хочется — заказываю переходник с джамперами или сразу TCA9548A. Модулей с одинаковыми адресами три и больше — мультиплексор без вариантов: восемь каналов закрывают вопрос на годы; я гоняю на одном таком модуле пять однотипных датчиков давления без единого конфликта за два года, а адрес самого диспетчера уводится теми же тремя входами, если в проекте уже живёт второй мультиплексор.
И не забывайте про переселение слейвов: если на шине уже живут часы на 0x68, второй слейв с адресом 0x68 не заводите — сдвигайте на 0x09, правило из урока про мастера и слейва. Джамперы к тому же дают модулю вторую жизнь: перекинутый адрес спасает шину за десять секунд без паяльника. Паре «LCD плюс RTC» из предыдущего урока все эти пляски не нужны в принципе: конфликт у 0x27 и 0x68 случиться негде. Если же первый экран у вас ещё не завёлся — начните с урока про первый текст на LCD, а сюда возвращайтесь с двумя одинаковыми модулями.
- Два устройства с одним адресом отвечают мастеру одновременно: при несовпадении битов на SDA получается мусор
- Адрес PCF8574 = 0x20 плюс три бита с джамперов A0-A2: восемь адресов от 0x20 до 0x27
- Адресные входы соединяют строго с землёй или питанием: висячий вход даёт плавающий адрес
- TCA9548A — восемь независимых шин за один адрес 0x70-0x77; канал выбирается байтом-маской 1 << n
- У DS3231 и DS1307 адрес 0x68 не настраивается: два RTC на одной шине — только через мультиплексор
- 1. На шине два одинаковых LCD, оба на 0x27. Что увидит сканер?
- 2. Джамперы A2=1, A1=0, A0=1. Какой адрес получит PCF8574?
- 3. Куда соединять адресные входы A0-A2?
- 4. Что делает запись Wire.write(1 << 3) в передаче на адрес 0x70?
- 5. На шине уже живут часы DS3231 на 0x68. Можно ли добавить вторые DS3231?
Частые вопросы по теме урока
- На шине два одинаковых LCD, оба на 0x27. Что увидит сканер?
- Оба отвечают подтверждением на один адрес, для сканера это один занятый адрес. Различить двоих он не в состоянии — это работа для джамперов, а при их отсутствии — для мультиплексора. Один адрес 0x27 — двоих сканер различить не может
- Джамперы A2=1, A1=0, A0=1. Какой адрес получит PCF8574?
- Биты весят 4, 2 и 1: 4+0+1=5, плюс база 0x20 — адрес 0x25. 0x25
- Куда соединять адресные входы A0-A2?
- Висячий вход не означает ноль: уровень не определён, адрес плавает. Соединяйте входы с землёй или питанием и проверяйте сканером — новая дверь обязана появиться в диапазоне 0x20-0x27. Строго на землю или на питание
- Что делает запись Wire.write(1 << 3) в передаче на адрес 0x70?
- 0x70 — адрес самого TCA9548A, байт-маска с одним битом включает канал: 1 << 3 — это канал номер 3. Выбирает канал 3 мультиплексора TCA9548A
- На шине уже живут часы DS3231 на 0x68. Можно ли добавить вторые DS3231?
- У DS3231 адрес зашит в кристалл, адресных входов нет. Два RTC уживаются только на разных шинах мультиплексора. Да, но через мультиплексор: адрес 0x68 не настраивается