I2C-сканер: знаходимо адреси всіх модулів і лагодимо «датчик не знайдено»
Найкорисніший скетч для будь-якого проєкту з I2C. Перебираємо всі 127 адрес, підписуємо знайдені пристрої і розбираємо п'ять причин, чому модуль не відповідає: від переплутаних SDA/SCL до відсутньої підтяжки і конфлікту адрес.
Про проєкт
«Sensor not found» — найчастіша помилка в проєктах з дисплеями й датчиками на I2C. Перш ніж шукати проблему в бібліотеці, варто з'ясувати, чи взагалі пристрій відповідає на шині і за якою адресою. Для цього існує I2C-сканер: він по черзі звертається до кожної адреси й дивиться, чи хтось відповість.
Що потрібно
- ESP32 DevKit (або Arduino)
- Будь-які I2C-модулі: у прикладі AHT20, BMP280, OLED SSD1306 і розширювач PCF8574
Схема
Усі модулі — паралельно на одні й ті самі два проводи:
| Сигнал | ESP32 | Arduino Uno | ESP32-C3 SuperMini |
|---|---|---|---|
| SDA | GPIO21 | A4 | GPIO8 |
| SCL | GPIO22 | A5 | GPIO9 |
| VCC | 3V3 | 5V | 3V3 |
Як працює сканер
Кожен обмін по I2C починається з адреси. Пристрій, що впізнав свою адресу, відповідає бітом ACK. Wire.endTransmission() повертає 0, якщо ACK прийшов, і 2, якщо ні. Сканер просто перебирає адреси від 1 до 126.
Код
// I2C-сканер: які адреси відповідають на шині
#include <Wire.h>
const char* guess(uint8_t a) { // типові пристрої за адресою
switch (a) {
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: return "PCF8574 / LCD 1602";
case 0x38: return "AHT10 / AHT20";
case 0x3C: case 0x3D: return "OLED SSD1306";
case 0x40: return "INA219";
case 0x48: return "ADS1115";
case 0x5A: return "MLX90614";
case 0x68: return "DS3231 / MPU6050";
case 0x76: case 0x77: return "BME280 / BMP280";
default: return "?";
}
}
void scan() {
Serial.println("Сканую I2C...");
int found = 0;
for (uint8_t addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
if (Wire.endTransmission() == 0) {
Serial.printf(" 0x%02X %s\n", addr, guess(addr));
found++;
}
}
Serial.printf("Знайдено пристроїв: %d\n\n", found);
}
void setup() {
Serial.begin(115200);
Wire.begin(); // ESP32: SDA 21, SCL 22
scan();
}
void loop() {
delay(5000);
scan(); // від'єднайте модуль — і побачите, що він зник
}
У симуляторі видаліть провід SDA одного з модулів або змініть його адресу у властивостях — наступне сканування це покаже.
П'ять причин, чому модуль «не знайдено»
- Переплутані SDA і SCL. Найчастіша помилка. Сканер не знайде нічого — поміняйте проводи місцями.
- Не та адреса. BME280/BMP280 буває 0x76 або 0x77, OLED — 0x3C або 0x3D, LCD 1602 — 0x27 або 0x3F. Бібліотеки мають адресу за замовчуванням, і вона часто не збігається з вашим модулем. Передайте ту, що знайшов сканер:
bme.begin(0x76). - Немає підтяжки. Лініям I2C потрібні резистори 4.7–10 кОм до VCC. На модулях вони майже завжди є; якщо «голий» датчик не знаходиться — додайте їх.
- Конфлікт адрес. Два однакові датчики на одній шині мають однакову адресу. Переставте перемичку адреси на одному з них (SDO, A0–A2) або використайте другу шину: на ESP32 є
Wire1. - Живлення і рівні. Модуль на 5 В без стабілізатора не працює від 3.3 В, а 5-вольтова підтяжка на модулі шкодить входам ESP32. Для змішаних систем потрібен перетворювач рівнів (BSS138).
Корисно знати
- Довжина проводів. I2C розрахований на плату, а не на будинок: до 30–50 см на 100 кГц. Для довших ліній зменште частоту
Wire.setClock(50000)або візьміть диференційний розширювач. - Адреси 0x00–0x07 і 0x78–0x7F зарезервовані, тому сканер їх пропускає.