Второй LCD для метеостанции я заказывал по той же ссылке, что и первый, — с шага «такой же дисплей, только дешёвая доставка». Скетч не менял ни на символ: LiquidCrystal_I2C lcd(0x27, 16, 2) — этот конструктор к тому моменту работал у меня на трёх сборках. На новом экране горела подсветка, верхняя строка была залита квадратами, нижняя пустая. Я переткнул провода, трижды перепрошил плату, успел обвинить контакт в макетке и одну из линий шины. Ответ нашёлся, когда я наконец запустил сканер шины: Device found at address 0x3F. Одна цифра. Разница в одном байте конструктора — а поведение сборки менялось от «работает» до «верхняя строка квадратов», и ни один перенос провода это не чинил. В конструкторе стояло 0x27, а модуль отвечал на 0x3F, потому что на его переходнике был чип не PCF8574, а PCF8574A.
С тех пор сканер шины идёт у меня первым делом к любому новому I2C-устройству — раньше любых уроков и примеров. В этом уроке разберём, откуда у «одинаковых» дисплеев два разных адреса, что делают паяные перемычки A0–A2, как за двадцать секунд узнать адрес своего модуля готовым скетчем и что делать, когда устройств на шине несколько. В конце соберём в симуляторе тренажёр сканера — с кнопкой, тумблером и честным «нашёл/не нашёл». Если вы ещё не подключали LCD по I2C вовсе, начните с урока про первый текст — там базовая схема из четырёх проводов.
Откуда берутся два адреса: PCF8574 против PCF8574A
Символьный LCD сам по себе ничего не знает про I2C: у HD44780 параллельная шина, о которой мы говорили в разборе его внутренностей. На двухпроводную жизнь его переводит переходник с чипом-расширителем портов, и вот тут начинается лотерея. Классический чип называется PCF8574, у него на шине есть собрат PCF8574A — логика идентична один в один, но заводской адрес другой: у PCF8574 базовый адрес 0x20, у версии с буквой A — 0x38. Отсюда и вся путаница: внешне переходники не отличить, надписи на плате не про адрес, а половина продавцов сама не знает, что отгружает в этом месяце.
У каждого из этих чипов по три адресных вывода — A0, A1, A2, и на платах дисплеев они выведены паяными перемычками. Замкнул перемычку — адрес сдвинулся вверх на 1, 2 или 4. На большинстве готовых переходников для LCD эти выводы подтянуты к питанию, поэтому из диапазона 0x20–0x27 получается верхний адрес 0x27, а из диапазона 0x38–0x3F — верхний 0x3F. Замечательно, что диапазоны не пересекаются: даже если на шине висят два дисплея, один на PCF8574, второй на PCF8574A, они слышат друг друга только когда их позовут по имени. Этим мы воспользуемся ближе к концу урока.
Посчитаем арифметику на пальцах, чтобы перемычки перестали быть магией. База PCF8574 — 0x20; замкнутый A2 добавляет 4, A1 — 2, A0 — единицу. Все три подтянуты — 0x20 + 4 + 2 + 1 = 0x27, всё сходится с типовым модулем. На плате это три контактные площадки с маркировкой A0, A1, A2 — замыкаются каплей припоя, паяльник на полминуты. И предупреждение из личного архива: встречаются модули с промежуточными настройками. Один мой экран неделю числился «бракованным», потому что все крутили конструктор между 0x27 и 0x3F, а модуль при этом жил на 0x26 — чужая рука до меня уже замкнула A1.
| Чип на переходнике | Диапазон адресов | Что стоит на модуле чаще всего | Куда сдвигают перемычки |
|---|---|---|---|
| PCF8574 | 0x20–0x27 | 0x27 | 0x20, 0x21, 0x24 и соседние |
| PCF8574A | 0x38–0x3F | 0x3F | 0x38, 0x39, 0x3C и соседние |
#include <Wire.h> void setup() { Wire.begin(); Serial.begin(9600); Serial.println("Skanirovanie I2C..."); int found = 0; for (byte addr = 8; addr < 120; addr++) { Wire.beginTransmission(addr); if (Wire.endTransmission() == 0) { Serial.print("Ustroistvo na adrese 0x"); Serial.println(addr, HEX); found++; } } if (found == 0) Serial.println("Nichego ne naydeno");} void loop() {}Механика сканера простая, но её стоит понимать, а не копировать вслепую. beginTransmission(addr) только готовит пакет в памяти — по шине ничего не уходит. endTransmission() отправляет адрес и ждёт: если устройство с таким адресом на шине есть, оно тянет линию данных в ответ (это называется подтверждением, ACK), и функция возвращает 0. Никого дома — вернётся не ноль, и сканер молча идёт дальше. Диапазон от 8 до 119 не случаен: адреса ниже 0x08 и выше 0x77 зарезервированы стандартом шины, на них отвечать нечему. При стандартной частоте шины 100 кГц одна попытка занимает десятки микросекунд, весь прогон по 112 адресам — доли секунды, поэтому сканировать можно хоть в каждом setup().
Найденное число подставьте в конструктор LiquidCrystal_I2C lcd(0x3F, 16, 2) — и загружайте скетч из урока про первый текст. Больше ничего менять не нужно: размеры экрана в конструкторе к адресу не относятся. Мой рабочий порядок для нового модуля выглядит так: подключил четыре провода, залил сканер, посмотрел на порт, вписал адрес, забыл о проблеме навсегда.
Мелочь, которая экономит вторые двадцать секунд: Serial.println(addr, HEX) печатает число без префикса и без ведущего нуля — адрес 0x08 будет выглядеть как «8». Поэтому «0x» в строке вывода я пишу заранее, руками, как в скетче выше. Если на шине несколько устройств, сканер напечатает по строке на каждое: дисплей и модуль часов дают две строки с разными адресами — это нормальная картина, а не сбой. И заведите привычку хранить найденный адрес в комментарии к скетчу: через полгода он понадобится снова, а запускать сканер заново лень.
Тренажёр сканера в симуляторе
Движок симулятора рисует дисплей честно — он собирает его прямо из вашего кода, как в настоящем скетче, — но шину I2C не моделирует: Wire-сканер в виртуальной среде получил бы ответ на любой адрес. Поэтому тренировать будем не скетч, а сам навык: понимать, что сканер перебирает адреса по порядку и ждёт ответ. Тумблер на пине D3 выбирает, какой чип стоит на вашем «виртуальном» модуле — PCF8574 с адресом 0x27 или PCF8574A с 0x3F. Кнопка на D2 делает шаг сканера: в списке шесть типовых адресов, как будто перебор идёт по настоящей шине. Светодиод на D12 загорается в тот момент, когда перебираемый адрес совпал с адресом модуля, — это и есть тот самый ACK, только глазами.
Попробуйте два сценария подряд: найдите 0x27, затем щёлкните тумблер и просканируйте заново — теперь тот же перебор молчит на первых адресах и находит 0x3F. Ровно это происходит на столе, когда заказанные партией дисплеи приходят с разными чипами.
Список адресов в тренажёре короткий не для экономии: на реальных LCD-переходниках ответ почти всегда лежит в диапазонах из таблицы выше, и перебирать все 112 адресов вручную нет смысла — железный сканер делает это быстрее, чем вы успеете моргнуть. Смысл тренажёра в другом: прочувствовать ритм перебора и момент, когда тишина сменяется ответом. Когда этот момент наступает на ожидаемом адресе, рука сама тянется записать число в конструктор — это и есть навык.
Когда адресов стало два, а устройств на шине — несколько, начинается самое интересное. Два LCD на одной шине подключаются параллельно: SDA к SDA, SCL к SCL, питание общее, — и живут по разным адресам без всяких мультиплексоров. Я так делал в пультовой сборке: 16x2 с текущими показаниями на 0x27 и 20x4 с журналом на 0x3F, адресация строк у него своя, об этом был урок про 20x4. Проблемы начинаются, когда два устройства получили одинаковый адрес: шина начинает отвечать кашей, сканер видит странные значения. Лечится перепайкой перемычек на одном из модулей — тем самым сдвигом на 1, 2 или 4, про который была таблица выше. Уровень выше — крошечные дисплеи на SSD1306, которые тоже сидят на этой же паре линий со своим адресом: навык сканера переносится на них без изменений.
Если тема шины увлекла, дальше по прямой: как I2C устроен на уровне сигналов и полный разбор сканера с разбором всех веток кода в разделе про Wire. А когда экран наконец отвечает на правильный адрес, но текста всё равно не видно — вернитесь к уроку про контраст и пин V0: в девяти случаях из десяти там виновата ручка, а не шина.
- Запустите сканер из code-блока на реальной сборке и запишите адрес в комментарии к скетчу — привычка хранить адрес рядом с кодом экономит повторные запуски.
- В тренажёре найдите оба адреса по очереди и посчитайте, на каком шаге сканера случилось совпадение, — это подскажет, насколько длинный диапазон реально перебирается.
- Добавьте в список тренажёра адрес 0x21 и убедитесь, что сканер проходит его мимо при обоих положениях тумблера.
- Подключите к реальной шине два устройства (дисплей и, например, RTC-модуль) и запустите сканер: он напечатает обе строки с разными адресами за один прогон.
- За адрес отвечает чип переходника: PCF8574 живёт в 0x20–0x27, PCF8574A — в 0x38–0x3F; модули чаще всего настроены на 0x27 или 0x3F
- Сканер перебирает адреса и смотрит на ответ endTransmission(): ноль — устройство подтвердилось
- Диапазон сканирования 8–119: крайние адреса зарезервированы стандартом и опрашивать их незачем
- Перемычки A0–A2 сдвигают адрес внутри диапазона чипа — так разводят два устройства с совпавшими адресами
- Порядок действий при молчащем дисплее: питание, потом SDA/A4 и SCL/A5, потом контакт, и только потом код
- 1. Что означает ноль, который вернул Wire.endTransmission()?
- 2. В каком диапазоне живут адреса чипов PCF8574A?
- 3. Сканер не нашёл ни одного устройства. Что проверяем первым?
- 4. Зачем на переходнике LCD три паяные перемычки A0, A1, A2?
- 5. На шине два дисплея, оба отвечают на 0x27. Как их развести?
Частые вопросы по теме урока
- Что означает ноль, который вернул Wire.endTransmission()?
- Ноль — это ACK: кто-то на шине узнал свой адрес и подтянул линию данных в ответ. Именно на ноль и опирается сканер. Устройство с этим адресом ответило подтверждением
- В каком диапазоне живут адреса чипов PCF8574A?
- Версия с буквой A отличается именно адресом: база 0x38, то есть диапазон 0x38–0x3F. У обычного PCF8574 база 0x20. 0x38–0x3F
- Сканер не нашёл ни одного устройства. Что проверяем первым?
- Пустой ответ означает физически пустую шину. Порядок такой: 5 В и GND, потом SDA на A4 и SCL на A5, потом контакт в макетке. Версию библиотеки LiquidCrystal_I2C
- Зачем на переходнике LCD три паяные перемычки A0, A1, A2?
- Каждая замкнутая перемычка добавляет к адресу 1, 2 или 4. Так два одинаковых модуля разводят по разным адресам. Они сдвигают адрес внутри диапазона чипа
- На шине два дисплея, оба отвечают на 0x27. Как их развести?
- Адрес зашит в чипе переходника и меняется только перемычками A0–A2. Один модуль сдвигают на соседний адрес, и оба живут на одной паре линий. Перепаять адресные перемычки на одном из модулей