Данное руководство представляет собой техническое описание процесса организации обмена данными между двумя микроконтроллерами 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 | 45 | Скачать |
![]() |
Код для ESP32 Master.ino | 2 Kb | 42 | Скачать |
Уроки ESP32 (заметки)
20 марта , 2025
Комментариев:0
Файлов для скачивания:2
Фото:2
Понравилась статья? Нажми
Виджеты для Easy HMI
Читайте также
Мы в соц сетях
Комментарии