Сканер I2C для Arduino: найти адрес любого устройства за минуту
Экран пустой, а провода целые: LCD 1602 с I2C-адаптером подключен по всем правилам, контраст выкручен синим подстроечником, пример с сайта скопирован буква в букву — но вместо текста два ряда прямоугольников или тишина. Подозрение обычно падает на дисплей, а виноват почти всегда адрес: в примере стоит 0x27, плата адаптера отвечает на 0x3F, и все посылки уходят в пустоту. Перебор адресов перепрошивками стоит вечер; сканер шины отвечает за минуту.
Ниже — как сканер устроен внутри (одна пустая посылка на адрес и код возврата), готовые три десятка строк для Serial Monitor, интерактивная распиновка с SDA/SCL и таблица адресов ходовых модулей от LCD до BMP280. Для OLED на SSD1306 есть отдельная страница про подключение и адрес 0x3C — со схемой и рабочим скетчем.
Как сканер находит адрес: пустая посылка и код возврата
Механика простая до неприличия. Сканер берёт адрес, отправляет в эфир beginTransmission(addr) и тут же закрывает посылку endTransmission() — не переслав ни одного байта. Если на линии живёт устройство с таким номером, оно тянет SDA вниз в момент проверки девятого бита: мастер видит подтверждение, и endTransmission возвращает ноль. Никто не откликнулся — вернётся другой код, адрес пропускается. Перебор идёт не с нуля и не до 127: номера 0-7 и 120-127 зарезервированы соглашением под служебные цели, поэтому рабочий диапазон сканера — 8-119. Что означает каждый код возврата, разобрано в уроке про коды endTransmission.
На Uno, Nano и Pro Mini шина I2C живёт на аналоговых пинах: SDA — A4, SCL — A5, и это же видно на распиновке ниже — нажмите на пины, чтобы посмотреть их роли. У Mega и Mega 2560 под I2C выделены отдельные пины 20 и 21, у ESP32 по умолчанию это GPIO 21 и 22. Перепутанные SDA и SCL — самая массовая причина, по которой сканер молчит: посылки уходят, но никто их не признаёт. Базовый принцип поиска устройств разобран подробнее в уроке про поиск адресов на шине.
Нажимайте на выводы платы — функции, подводные камни и подсказки по каждому пину.
Подгружаем интерактив…
Сканер целиком: три десятка строк и Serial Monitor
#include <Wire.h> void setup() { Wire.begin(); Serial.begin(9600); Serial.println("Сканер I2C запущен, ищу устройства...");} void loop() { byte naideno = 0; for (byte addr = 8; addr < 120; addr++) { Wire.beginTransmission(addr); // старт посылки на адрес byte otvet = Wire.endTransmission(); // 0 = устройство откликнулось if (otvet == 0) { Serial.print("Отклик на адрес 0x"); if (addr < 16) Serial.print("0"); // ведущий ноль для красоты Serial.println(addr, HEX); naideno++; } } if (naideno == 0) { Serial.println("Шина молчит: проверьте SDA, SCL и питание модуля"); } else { Serial.print("Устройств на шине: "); Serial.println(naideno); } delay(5000); // новый проход раз в пять секунд}Вывод лаконичен: строка с адресом — устройство живо; тишина или фраза про пустую шину — беда в монтаже, а не в коде. Прогоняйте сканер после каждой смены схемы: он отвечает за минуту, а угадывание адресов по форумам стоит вечера. Бонус — сканер видит всё сразу: если на шине окажутся два LCD с разными чипами адаптеров, вы увидите и 0x27, и 0x3F одновременно. Версия с диагностикой по кодам возврата на каждый адрес — в уроке про сканер I2C с разбором ответов.
Адреса ходовых модулей: шпаргалка
| Модуль | Чип | Адрес | Примечание |
|---|---|---|---|
| LCD 1602/2004 с I2C-адаптером | PCF8574 | 0x27 | Самый частый ответ синей платы-адаптера |
| LCD с адаптером новой ревизии | PCF8574A | 0x3F | Внешне не отличить: разница спрятана в чипе |
| OLED-дисплей 0,96 дюйма | SSD1306 | 0x3C | Реже встречается 0x3D — при SA0 на плюсе |
| Датчик давления BMP280 | BMP280 | 0x76 или 0x77 | Ножка SDO на земле — 0x76, на плюсе — 0x77 |
| Часы реального времени | DS3231 | 0x68 | Адрес зашит в чипе и не переключается |
| Расширитель портов | PCF8574 | 0x20-0x27 | Ножки A0-A2 дают восемь адресов на выбор |
Самая частая пара в таблице — 0x27 и 0x3F у одного и того же LCD: на плате-адаптере стоит расширитель PCF8574 или его собрат PCF8574A, и это разные чипы с разными диапазонами адресов при одинаковой разводке. Внешне платы не различить — только сканером. OLED на SSD1306 почти всегда сидит на 0x3C, а у BMP280 адрес выбирается ножкой SDO — удобно, когда нужен второй датчик того же типа. Дальше адрес отправляется в библиотеку: как он превращается в рабочие строки на экране — в уроке про адрес LCD 0x27 или 0x3F, а полная схема сборки — на странице про подключение LCD по I2C.
- LCD 1602/2004: подставить адрес в конструктор LiquidCrystal_I2C lcd(0x27, 16, 2);
- OLED на SSD1306: адрес идёт вторым аргументом в display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
- BMP280: bmp.begin(0x76) — или 0x77, как показал сканер;
- Любой модуль: подписать найденный адрес маркером прямо на плате — второй раз сканировать не придётся.