Библиотека Wire
Шина I2C: два провода, до сотни устройств с разными адресами. На ней сидят дисплеи, часы, датчики.
I2C — шина из двух проводов: данные SDA и такт SCL. У каждого устройства свой адрес, обычно шестнадцатеричное число вроде 0x27 или 0x68, и плата обращается к ним по очереди. На UNO это выводы A4 и A5, на Mega — 20 и 21, у ESP32 по умолчанию GPIO21 и GPIO22.
Напрямую с Wire пишут редко: библиотеки дисплеев и датчиков используют её внутри. Но знать её нужно в двух случаях: чтобы найти адрес неизвестного модуля сканером и чтобы читать регистры чипа, к которому библиотеки нет.
Установка и подключение
Ставить ничего не нужно: библиотека входит в среду Arduino и доступна сразу после установки. Достаточно строки подключения в начале скетча.
#include <Wire.h>Создание объекта — обычно до setup():
Wire.begin(); // в setup(); объект Wire уже создан библиотекой
Wire.setClock(400000); // необязательно: 400 кГц вместо 100 кГц, если все устройства умеютМетоды
Только то, что нужно в обычном скетче. Сигнатуры сверены с версией ядро AVR 1.8.8.
begin()- Включить шину как ведущее устройство. Обязательно перед любым обменом.
begin(uint8_t address)- Включить как ведомое с адресом — когда плата сама отвечает другому контроллеру.
setClock(uint32_t hz)- Частота шины: 100000 по умолчанию, 400000 для быстрых устройств.
beginTransmission(uint8_t address)- Начать посылку устройству с адресом. Дальше write(), потом endTransmission().
write(uint8_t byte)- Положить байт в буфер посылки. Есть вариант write(buf, len).
endTransmission()- Отправить буфер. Возвращает 0 при успехе, 2 — никто не ответил по адресу; на этом построен сканер.
requestFrom(uint8_t address, uint8_t count)- Запросить count байт у устройства. Возвращает, сколько пришло.
available()- Сколько байт принято и ещё не прочитано.
read()- Прочитать один принятый байт.
onReceive(void (*f)(int))- В режиме ведомого: функция, которую вызовут при получении данных.
onRequest(void (*f)())- В режиме ведомого: функция, которая отдаёт данные по запросу ведущего.
setWireTimeout(uint32_t us, bool reset)- Таймаут ожидания шины: без него зависшее устройство вешает плату навсегда.
Пример
#include <Wire.h>
// сканер I2C: печатает адреса всех устройств на шине
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println("Ищу устройства...");
for (byte addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
if (Wire.endTransmission() == 0) { // 0 — кто-то ответил
Serial.print("Найден адрес 0x");
Serial.println(addr, HEX);
}
}
Serial.println("Готово");
}
void loop() {}Первое, что запускают с любым новым I2C-модулем. Если сканер ничего не нашёл — проблема в проводах или питании, а не в библиотеке дисплея.
На чём попадаются
Дисплей молчит, сканер ничего не находит
Перепутаны SDA и SCL или нет общей земли. У модулей на 3,3 В при подключении к UNO иногда не хватает подтяжки — но чаще всего дело всё же в проводах.
Плата зависает при отключении датчика
Wire по умолчанию ждёт ответа бесконечно. setWireTimeout() заставляет вернуться с ошибкой.
Два устройства с одним адресом
На одной шине так нельзя. У многих модулей адрес меняется перемычкой; иначе — второй экземпляр Wire на других выводах (ESP32) или мультиплексор TCA9548.
Адрес в даташите 0x4E, а сканер показывает 0x27
Даташиты иногда указывают адрес со сдвигом на бит чтения/записи. Arduino использует семибитный: делите на два.
Где используется на сайте
- Дисплей LCD 1602: схема подключения и скетч
- OLED SSD1306: схема подключения и скетч
- Часы DS3231: схема подключения и скетч
- Гироскоп MPU6050: схема подключения и скетч
- Датчик давления BMP280: схема подключения и скетч