ELECTRONICS

Библиотека Wire

встроена в средуArduino, встроенаверсия ядро AVR 1.8.8

Шина 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 использует семибитный: делите на два.

Где используется на сайте

Что дальше