Данное руководство представляет собой техническое описание процесса организации обмена данными между двумя микроконтроллерами ESP32 с использованием протокола I2C (Inter-Integrated Circuit). I2C - это синхронный последовательный протокол, широко применяемый для связи между микроконтроллерами и периферийными устройствами. В данном уроке одна плата ESP32 будет настроена как ведущее устройство (Master), а другая - как ведомое (Slave). Программирование микроконтроллеров будет осуществляться в среде разработки Arduino IDE. Руководство предоставляет подробные инструкции по подключению, настройке и программированию, а также примеры кода для реализации I2C-взаимодействия.
I2C (Inter-Integrated Circuit) – это синхронный, последовательный, полудуплексный протокол связи, разработанный компанией Philips. Он предназначен для соединения микроконтроллеров и различных периферийных устройств, таких как датчики, дисплеи, EEPROM и другие.

Микроконтроллер ESP32 оснащен двумя аппаратными интерфейсами I2C, которые могут быть настроены как в режиме ведущего, так и в режиме ведомого устройства. Согласно технической документации ESP32, интерфейсы I2C поддерживают:
Примечание: Подтягивающие резисторы (pull-up resistors) на линиях SDA и SCL являются неотъемлемой частью шины I2C. Они обеспечивают высокий уровень сигнала на линиях, когда шина неактивна. Типичное значение подтягивающих резисторов составляет 4.7 кОм.
Для организации I2C-взаимодействия между двумя платами ESP32 будут использованы следующие компоненты и настройки:

Для установления соединения между двумя платами ESP32 по шине I2C необходимо выполнить следующие подключения:
| ESP32 Master (Ведущий) | ESP32 Slave (Ведомый) |
|---|---|
| SDA (GPIO 21)* | SDA (GPIO 21)* |
| SCL (GPIO 22)* | SCL (GPIO 22)* |
| GND | GND |
* Указаны стандартные выводы для ESP32 DOIT V1.
Важно:
Общая схема взаимодействия между ведущим (Master) и ведомым (Slave) устройствами ESP32 по I2C выглядит следующим образом:
| ESP32 Master (Ведущий) | ESP32 Slave (Ведомый) |
|---|---|
| 1. Устанавливает свой I2C-адрес. | |
| 2. Устанавливает функции обратного вызова (callback functions): - для чтения принятых сообщений (onReceive); - для обработки запросов от ведущего (onRequest). |
|
| 3. Инициализирует шину I2C с указанием адреса ведомого устройства. | |
| 4. Начинает I2C-взаимодействие на шине. | |
| 5. Отправляет сообщение ведомому устройству (начинает передачу). | |
| 6. Читает принятое сообщение. | |
| 7. Запрашивает данные у ведомого устройства. | |
| 8. Отправляет данные ведущему устройству. |
В качестве примера кода для настройки ESP32 в качестве ведомого устройства I2C используется пример из библиотеки Wire.h.
/*
*Обмен данными между двумя платами ESP32 по шине I2C.
* https://arduino-tex.ru/news/208/obmen-dannymi-mezhdu-dvumya-platami-esp32-po-shine-i2c.html
*/
#include "Wire.h"
#define I2C_DEV_ADDR 0x55 // I2C-адрес ведомого устройства
uint32_t i = 0; // Переменная-счетчик
// Функция обратного вызова, выполняемая при запросе данных от ведущего
void onRequest() {
Wire.print(i++); // Отправка значения счетчика
Wire.print(" Packets.");
Serial.println("onRequest"); // Вывод в последовательный порт
Serial.println();
}
// Функция обратного вызова, выполняемая при получении данных от ведущего
void onReceive(int len) {
Serial.printf("onReceive[%d]: ", len); // Вывод длины принятого сообщения
while (Wire.available()) {
Serial.write(Wire.read()); // Чтение и вывод принятых байтов
}
Serial.println();
}
void setup() {
Serial.begin(115200); // Инициализация последовательного порта
Serial.setDebugOutput(true);
Wire.onReceive(onReceive); // Установка функции обратного вызова для приема данных
Wire.onRequest(onRequest); // Установка функции обратного вызова для отправки данных
Wire.begin((uint8_t)I2C_DEV_ADDR); // Инициализация I2C с указанием адреса ведомого
/*#if CONFIG_IDF_TARGET_ESP32 //Потенциально нужная часть кода для некоторых версий ESP32.
char message[64];
snprintf(message, 64, "%lu Packets.", i++);
Wire.slaveWrite((uint8_t *)message, strlen(message));
Serial.print("Printing config %lu", i);
#endif*/
}
void loop() {
// Ведомое устройство не выполняет никаких действий в основном цикле
}
Пояснения к коду (Slave):
#include "Wire.h": Подключение библиотеки Wire.h для работы с I2C.#define I2C_DEV_ADDR 0x55: Определение I2C-адреса ведомого устройства.onRequest(): Функция, вызываемая, когда ведущее устройство запрашивает данные. В данном примере отправляется значение переменной i и строка " Packets.".onReceive(): Функция, вызываемая, когда ведомое устройство получает данные от ведущего. В данном примере принятые данные выводятся в последовательный порт.Wire.onReceive(onReceive);: Регистрация функции onReceive как обработчика события приема данных.Wire.onRequest(onRequest);: Регистрация функции onRequest как обработчика события запроса данных.Wire.begin((uint8_t)I2C_DEV_ADDR);: Инициализация I2C-интерфейса в режиме ведомого устройства с указанным адресом. Используются стандартные выводы SDA и SCL.#if CONFIG_IDF_TARGET_ESP32 - в документации упоминается метод Wire.slaveWrite(), который, теоретически, должен записывать данные для ответа в буфер перед приемом запроса от ведущего, но на практике код работает и без него. Возможно, этот метод необходим для каких-то конкретных реализаций ESP32, поэтому оставим его закомментированным.В качестве примера кода для настройки ESP32 в качестве ведущего устройства I2C используется пример из библиотеки Wire.h.
/*
*Обмен данными между двумя платами ESP32 по шине I2C.
* https://arduino-tex.ru/news/208/obmen-dannymi-mezhdu-dvumya-platami-esp32-po-shine-i2c.html
*/
#include "Wire.h"
#define I2C_DEV_ADDR 0x55 // I2C-адрес ведомого устройства
uint32_t i = 0; // Переменная-счетчик
void setup() {
Serial.begin(115200); // Инициализация последовательного порта
Serial.setDebugOutput(true);
Wire.begin(); // Инициализация I2C в режиме ведущего
}
void loop() {
delay(5000); // Задержка 5 секунд
// Отправка сообщения ведомому устройству
Wire.beginTransmission(I2C_DEV_ADDR); // Начало передачи данных ведомому устройству
Wire.printf("Hello World! %lu", i++); // Отправка сообщения
uint8_t error = Wire.endTransmission(true); // Завершение передачи
Serial.printf("endTransmission: %u\n", error); // Вывод кода ошибки
// Запрос данных у ведомого устройства
uint8_t bytesReceived = Wire.requestFrom(I2C_DEV_ADDR, 15); // Запрос 15 байт данных
Serial.printf("requestFrom: %u\n", bytesReceived);
if (bytesReceived > 0) { // Если получены данные
uint8_t temp[bytesReceived];
Wire.readBytes(temp, bytesReceived); // Чтение принятых байтов
Serial.print("Received data: ");
for (uint8_t i = 0; i < bytesReceived; i++) {
Serial.printf("0x%02X ", temp[i]); // Вывод в шестнадцатеричном формате
}
Serial.write(temp, bytesReceived);
Serial.println();
}
}
Пояснения к коду (Master):
#include "Wire.h": Подключение библиотеки Wire.h.#define I2C_DEV_ADDR 0x55: Определение I2C-адреса ведомого устройства (должно совпадать с адресом, установленным в коде ведомого устройства).Wire.begin();: Инициализация I2C-интерфейса в режиме ведущего устройства. Используются стандартные выводы SDA и SCL.Wire.beginTransmission(I2C_DEV_ADDR);: Начало передачи данных ведомому устройству с указанным адресом.Wire.printf("Hello World! %lu", i++);: Формирование и отправка сообщения ведомому устройству.Wire.endTransmission(true);: Завершение передачи данных. Параметр true указывает на отправку стоп-бита, сигнализирующего об окончании передачи.Wire.requestFrom(I2C_DEV_ADDR, 16);: Запрос 16 байт данных у ведомого устройства с указанным адресом.Wire.readBytes(temp, bytesReceived);: Чтение принятых байтов в массив temp.Serial.write(temp, bytesReceived); использовалась функция log_print_buf(temp, bytesReceived), выводящая принятый буфер, но ее описание отсутствует. Для корректного вывода данных в серийный порт заменяем вызов.Для демонстрации обмена данными необходимо:

Ожидаемые результаты:


Заключение:
Данное руководство предоставило подробную информацию о настройке и использовании протокола I2C для организации обмена данными между двумя платами ESP32. Были рассмотрены основные принципы работы I2C, аппаратные особенности ESP32, схема подключения, а также приведены примеры программного кода для реализации режима ведущего и ведомого устройства. Предоставленная информация позволяет разработчикам создавать собственные проекты, использующие I2C-взаимодействие между микроконтроллерами ESP32, а также интегрировать ESP32 с различными I2C-периферийными устройствами.
Дополнительная информация к данному уроку:
Понравился урок: Обмен данными между двумя платами ESP32 по шине I2C? Не забудь поделиться с друзьями в соц. сетях.
А также подписаться на наш канал на YouTube, вступить в группу Вконтакте, в Telegram.
Спасибо за внимание!
Технологии начинаются с простого!
Фотографии к статье
Файлы для скачивания
| Код для ESP32 Slave.ino | 2 Kb | 162 | Скачать | |
| Код для ESP32 Master.ino | 2 Kb | 159 | Скачать |
Уроки ESP32 (заметки)
20 марта , 2025
Комментариев:0
Файлов для скачивания:2
Фото:2
Понравилась статья? Нажми
Читайте также
Мы в соц сетях
Комментарии