Перейти к содержанию

Как связать две Arduino по I2C?

Обновлено Редакция GAW

I2C позволяет связать две платы двумя сигнальными проводами и землёй. Это та же шина, к которой подключают датчики, просто вместо датчика стоит вторая Arduino в роли ведомого устройства.

Подключение

ЛинияArduino Uno или Nano (ATmega328P)Куда подключить
SDAA4 (PC4)к SDA второй платы
SCLA5 (PC5)к SCL второй платы
GNDGNDк GND второй платы

Номера выводов других плат сводит таблица пинов Arduino. Земля обязательна: без неё уровни на линиях ничем не привязаны.

Подтяжки

Выходы I2C — с открытым стоком, и шине нужна одна пара резисторов к питанию на обе платы. Библиотека Wire при инициализации сама включает встроенные подтяжки ATmega328P — 20–50 кОм на каждой плате, то есть у двух плат они оказываются параллельно. Наш расчёт по формуле TI SLVA689A для 50 кОм и ёмкости 100 пФ:

tr=0,8473⋅50 кОм⋅100 пФ≈4,2 мксt_r = 0{,}8473 \cdot 50\ \text{кОм} \cdot 100\ \text{пФ} \approx 4{,}2\ \text{мкс}

Даже две такие подтяжки параллельно (25 кОм) дают около 2,1 мкс. Это больше 1000 нс, допустимых в Standard-mode по UM10204, поэтому ставят внешние 4,7 кОм — с ними фронт около 0,4 мкс; встроенные подтяжки при этом почти ничего не меняют. Точнее подобрать резистор поможет калькулятор подтяжек I²C.

Роли и адрес

Одна плата — ведущая: она формирует такты и начинает обмен. Вторая — ведомая с адресом, на который отвечает. Адреса 0000 XXX и 1111 XXX по UM10204 зарезервированы, поэтому для своих устройств остаётся 0x08–0x77 — 112 адресов (наш расчёт). В библиотеке Wire ведомая плата получает адрес при инициализации и обрабатывает приём и запрос данных в обработчиках событий.

Две ведущие платы на одной шине возможны благодаря арбитражу, но усложняют программу. Как устроена шина, рассказано в статье «Шина I²C».

Похожие вопросы

Могут ли обе Arduino быть ведущими?

Протокол это допускает: I2C — шина с несколькими ведущими, и UM10204 описывает арбитраж, при котором проигравший ведущий уступает шину. Но программа должна обрабатывать проигрыш и повторять передачу, поэтому проще оставить одного ведущего, который сам опрашивает вторую плату.

Можно ли так соединить Arduino на 5 В и ESP32 на 3,3 В?

Только через преобразователь уровней. Если подтянуть шину к 5 В, на выводы ESP32 придёт напряжение выше его питания. Если к 3,3 В — для выводов TWI ATmega328P при 5 В единица гарантирована только от 0,7 · 5 = 3,5 В (табл. 29-14 даташита), и 3,3 В ниже этого порога; к тому же Wire включает на Arduino встроенные подтяжки к 5 В.

На какое расстояние можно разнести платы?

I2C рассчитан на связь внутри устройства: ёмкость каждой линии не должна превышать 400 пФ, а у провода она растёт с длиной. Несколько десятков сантиметров обычно работают на 100 кГц; для метров между платами берут UART через RS-485 или CAN.

Источники

  1. Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet (DS40002061B, 2020) — разд. 22.2 — шина TWI соединяет до 128 устройств двумя линиями, нужна только пара подтягивающих резисторов, механизмы разрешения конфликтов встроены в протокол; разд. 22.2.2 — выходы с открытым стоком образуют монтажное И, все AVR на шине должны быть включены, число устройств ограничено ёмкостью 400 пФ и 7-битным адресом; выводы PC4 (SDA) и PC5 (SCL); встроенный подтягивающий резистор вывода 20–50 кОм; разд. 29.7, табл. 29-14 — для выводов TWI VIH не меньше 0,7 VCC, VIL не больше 0,3 VCC
  2. NXP. UM10204 I2C-bus specification and user manual (Rev. 7.0, 1 October 2021) — разд. 3.1.12, табл. 4 — зарезервированы адреса 0000 XXX и 1111 XXX; табл. 11 — время нарастания в Standard-mode не больше 1000 нс, ёмкость линии до 400 пФ; I2C — шина с несколькими ведущими, арбитражем и синхронизацией тактов
  3. Texas Instruments. SLVA689A: I2C Bus Pullup Resistor Calculation (revised October 2026) — ур. 5 — время нарастания tr = 0,8473 · Rp · Cb
  4. Arduino. ArduinoCore-avr 1.8.6, библиотека Wire, файл libraries/Wire/src/utility/twi.c — twi_init: «activate internal pullups for twi» — digitalWrite(SDA, 1) и digitalWrite(SCL, 1), то есть встроенные подтяжки к питанию платы включаются при инициализации Wire; twi_disable их отключает

Нашли ошибку?