Гид по технологиям

Соединение двух Arduino по I2C: мастер и слейв

6 min read Embedded Обновлено 30 Dec 2025
Соединение двух Arduino по I2C
Соединение двух Arduino по I2C

Введение

Связь между двумя Arduino полезна, когда одна плата собирает данные с датчиков, а другая выполняет обработку, отображение или управление. I2C (Inter-Integrated Circuit) — простой двухпроводной протокол, подходящий для коротких удалённостей на одной плате или соседних макетных платах.

Важно: I2C требует общей земли (GND) у всех устройств на шине и подтягивающие резисторы (pull-up) на линиях SDA и SCL.

Что такое I2C?

I2C — последовательный двухпроводный протокол связи для обмена данными между микросхемами и микроконтроллерами. Кратко: мастер инициирует передачу, у каждого слейва есть уникальный адрес, линии — SDA (данные) и SCL (тактирование).

Определение в одну строку: I2C — это двухпроводная шина для обмена небольшими сообщениями между устройствами с адресацией.

Как работает I2C?

I2C использует две двунаправленные линии:

  • SDA — последовательные данные.
  • SCL — тактовая линия.

Мастер генерирует тактовые импульсы и старт/стоп-фреймы. Передача идёт блоками байт: адрес слейва + бит чтения/записи, затем подтверждения (ACK/NACK) и полезная нагрузка.

Демонстрация обмена по I2C

Ошибка адресации или отсутствие подтягивающих резисторов часто вызывает зависания шины.

Плюсы и ограничения

  • Плюсы: простая проводка, несколько мастеров/слейвов, короткие сообщения без сложной физики.
  • Ограничения: скорость ограничена (стандартно до 100 кбит/с, быстрый режим 400 кбит/с и выше у некоторых устройств), чувствительность к шуму и длине проводов.

Примечание по питанию: устройства с уровнями 3.3 В можно подключать к 5 В шине только через согласующие преобразователи уровней; альтернативно используйте подтягивание к 3.3 В и убедитесь, что все устройства поддерживают такой уровень.

Аппаратное подключение Arduino по I2C

Необходимые компоненты:

  • Две платы Arduino (одна мастер, другая слейв).
  • Макетка (breadboard) или провода для прямого соединения.
  • Провода (jumper wires).
  • Два подтягивающих резистора 4.7 кОм (4.7 kΩ → 4.7 кОм).

Подключение:

  1. Соедините SDA обеих плат вместе.
  2. Соедините SCL обеих плат вместе.
  3. Соедините GND плат между собой (общая земля).
  4. Подтяните SDA и SCL к линии питания через резисторы 4.7 кОм (обычно к 5 В или к 3.3 В, в зависимости от логики устройств).

Изображение для Arduino Uno (расположение выводов SDA/SCL):

Распиновка I2C для Arduino Uno

Изображение для Arduino Nano (распиновка I2C):

Распиновка I2C для Arduino Nano

Подтягивающие резисторы нужны даже если на плате уже есть встроенные подтяжки в некоторых модулях — внешние 4.7 кОм дают предсказуемые уровни и лучшую совместимость.

Библиотека Wire

Wire — встроенная библиотека Arduino для работы с I2C. Она упрощает отправку и приём данных между платами.

Короткий пример подключения заголовка:

#include 

Основные функции Wire (одна строка объяснения каждой):

  • Wire.begin() — подключение к шине I2C (мастер или слейв в зависимости от аргумента).
  • Wire.beginTransmission(addr) — начать передачу к слейву с адресом addr.
  • Wire.write(data) — записать байт(ы) в буфер передачи.
  • Wire.endTransmission() — завершить передачу и отправить данные.
  • Wire.requestFrom(addr, qty) — запросить qty байт от слейва с адресом addr.
  • Wire.available() — проверить, есть ли ожидаемые байты для чтения.
  • Wire.read() — прочитать байт из входного буфера.
  • Wire.onReceive(handler) — зарегистрировать обработчик прихода данных (в слейве).
  • Wire.onRequest(handler) — зарегистрировать обработчик на чтение запросов мастера (в слейве).

Где находятся выводы SDA/SCL на разных Arduino

  • На Uno: SDA — A4, SCL — A5 (старые платы), также есть выводы SDA/SCL рядом с коннектором.
  • На Nano: SDA — A4, SCL — A5 (или отдельные пины у некоторых версий).

Всегда проверяйте распиновку конкретной модели.

Пример: простой мастер, читающий данные со слейва

Ниже пример кода мастера, который запрашивает 6 байт у слейва с адресом 8 и печатает их в Serial Monitor.

#include 

void setup() {
  Wire.begin(); // подключиться к I2C как мастер
  Serial.begin(9600); // старт Serial для вывода
}

void receiveData() {
  int address = 8;
  int bytesToRead = 6;
  Wire.requestFrom(address, bytesToRead);
  while (Wire.available()) {
    char data = Wire.read();
    Serial.print(data);
  }
  delay(500);
}

void loop() {
  receiveData();
}

Пояснения:

  • Wire.requestFrom() блокирует до тех пор, пока не придут байты или таймаут.
  • Всегда проверяйте, сколько байт реально пришло через Wire.available().

Пример: простой слейв, отвечающий на запросы мастера

Код слейва, который отвечает строкой “hello “ (6 байт) при запросе мастера:

#include 

void setup() {
  Wire.begin(8); // присоединиться к шине как слейв с адресом 8
  Wire.onRequest(requestEvent); // зарегистрировать обработчик запросов
}

void loop() {
  delay(100);
}

void requestEvent() {
  Wire.write("hello "); // отправить 6 байт в ответ мастеру
}

Важно: Wire.write в слейве отправляет данные только при вызове requestEvent; не пытайтесь вызывать отправку вне контекста запроса.

Пример: пересылка температуры с DHT11 через I2C

Схема: датчик DHT11 подключён к слейв-Arduino (например, к пину 4). Слейв читает температуру и, по запросу мастера, отправляет одно байтовое значение температуры.

Пример DHT11 с двумя Arduino по I2C

Код мастера (запрашивает 1 байт и печатает температуру):

#include 

void setup() {
  Wire.begin();
  Serial.begin(9600);
  Serial.println("Мастер инициализирован!");
}

void loop() {
  Wire.requestFrom(8, 1); // запросить 1 байт температуры у слейва
  if (Wire.available()) {
    byte temperature = Wire.read(); // прочитать байт температуры
    Serial.print("Температура: ");
    Serial.print(temperature);
    Serial.println(" °C");
  }
  delay(2000); // ждать 2 секунды
}

Код слейва с DHT11 (читает значение и отвечает на запрос мастера):

#include 
#include 

#define DHTPIN 4
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
byte temperature;

void setup() {
  Wire.begin(8); // адрес слейва 8
  Wire.onRequest(requestEvent);
  dht.begin();
}

void loop() {
  delay(2000); // ждать стабилизации датчика
  float t = dht.readTemperature();
  if (!isnan(t)) {
    temperature = (byte)t; // округление до целого, при необходимости используйте другое представление
  }
}

void requestEvent() {
  Wire.write(temperature); // отправить температуру мастеру
}

Советы:

  • Если температура может быть отрицательной либо с дробной частью, используйте два байта или фиксированный формат (например, целая часть ×10).
  • DHT сенсоры медленны; уважайте требования по времени между измерениями (обычно ≥2 с).

Поиск адресов устройств (I2C Scanner)

Иногда на шине уже есть устройства, и вы не знаете их адрес. Скрипт-сканер перебирает адреса от 1 до 126 и сообщает, где есть ответ.

#include 

void setup() {
  Wire.begin();
  Serial.begin(9600);
  while (!Serial);
  Serial.println("\nI2C Scanner");
}

void loop() {
  byte error, address;
  int nDevices = 0;

  Serial.println("Scanning...");
  for (address = 1; address < 127; address++) {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0) {
      Serial.print("I2C device found at address 0x");
      if (address < 16) Serial.print("0");
      Serial.print(address, HEX);
      Serial.println(" !");
      nDevices++;
    } else if (error == 4) {
      Serial.print("Unknown error at address 0x");
      if (address < 16) Serial.print("0");
      Serial.println(address, HEX);
    }
  }
  if (nDevices == 0) Serial.println("No I2C devices found\n");
  else Serial.println("done\n");

  delay(5000);
}

Типичные проблемы и их решения

  • Шина “виснет” (нет ответов): проверьте общую землю, подтягивающие резисторы и целостность проводки.
  • Несоответствие уровней питания: если один модуль 3.3 В, а другой 5 В — используйте уровень-переводчик (level shifter) или подтягивайте к 3.3 В и убедитесь, что 5 В плата допускает 3.3 В как логический HIGH.
  • Неправильный адрес: используйте I2C Scanner.
  • Медленные или потерянные данные: уменьшите длину проводов, экранируйте или используйте более высокое качество проводки.
  • Конфликт нескольких мастеров: реализуйте арбитраж и убедитесь в корректной логике перехвата шины (сложно вручную).

Мини‑методология: как быстро настроить проект

  1. Подключите GND между платами.
  2. Соедините SDA и SCL.
  3. Поставьте подтягивающие резисторы 4.7 кОм к соответствующему уровню питания (3.3 В или 5 В).
  4. Загрузите скетч-сканер и убедитесь, что устройства видны.
  5. Назначьте адрес слейву и протестируйте простую передачу строки.
  6. Переключитесь на реальный формат данных (температура, строка, массив байт).
  7. Добавьте обработку ошибок и таймауты.

Чеклисты по ролям

Разработчик прошивки:

  • Проверить распиновку и питание.
  • Написать модульный код для мастера/слейва.
  • Добавить логирование (Serial).

Интегратор аппаратной части:

  • Убедиться в наличии общей земли.
  • Установить подтягивающие резисторы 4.7 кОм.
  • Проверить согласование уровней напряжения.

Тестировщик/QA:

  • Запустить I2C Scanner.
  • Проверить устойчивость при перезагрузке одного устройства.
  • Смоделировать потерю данных и проверить поведение мастера.

Критерии приёмки

  • Мастер успешно запрашивает и получает данные от слейва в 5 из 5 последовательных запросов.
  • При отключении датчика слейв не блокирует шину (обрабатывает или возвращает корректный код ошибки).
  • При разном напряжении (3.3 В / 5 В) подключение защищено уровневым преобразователем.

1‑строчный глоссарий

I2C — двухпроводной протокол связи (SDA, SCL) с адресацией устройств; мастер инициирует передачу, слейв отвечает.

Диаграмма принятия решения (Mermaid)

flowchart TD
  A[Нужно ли несколько плат?] -->|Да| B{Короткая шина и много устройств?}
  B -->|Да| C[I2C]
  B -->|Нет, нужна высокая скорость| D[SPI]
  A -->|Нет| E[Одна плата — не нужно I2C]
  C --> F[Реализовать Wire и подтяжки]
  D --> G[Реализовать SPI: MOSI/MISO/SCLK/SS]

Заключение

I2C — практичный выбор для простого обмена данными между несколькими Arduino на одной шине. Библиотека Wire обеспечивает базовый функционал для реализации мастер/слейв взаимодействия. Всегда проверяйте адреса устройств, согласование уровней и наличие общих GND. Начните с простого примера и постепенно добавляйте обработку ошибок и форматирование данных.

Важное: протестируйте систему в реальной аппаратной конфигурации и используйте I2C Scanner перед развёртыванием.


Image credits: Arduino I2C documentation

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

RDP: полный гид по настройке и безопасности
Инфраструктура

RDP: полный гид по настройке и безопасности

Android как клавиатура и трекпад для Windows
Гайды

Android как клавиатура и трекпад для Windows

Советы и приёмы для работы с PDF
Документы

Советы и приёмы для работы с PDF

Calibration в Lightroom Classic: как и когда использовать
Фото

Calibration в Lightroom Classic: как и когда использовать

Отключить Siri Suggestions на iPhone
iOS

Отключить Siri Suggestions на iPhone

Рисование таблиц в Microsoft Word — руководство
Office

Рисование таблиц в Microsoft Word — руководство