Осуществление разных способов связи между модулями esp32

от автора

Микроконтроллер esp32 примечателен многим, однако его наиболее известной характеристикой (которая, кстати, вполне себе «перевернула» рынок в своё время) является встроенная возможность осуществления связи по bluetooth и wi-fi. Эти способы коммуникации позволяют микроконтроллеру осуществлять как скоростную связь с устройствами, так и энергосберегающую. Именно об этих способах мы и поговорим в этой статье.

Достаточно часто перед использующими этот микроконтроллер встаёт задача связи его с другими аналогичными устройствами. Поэтому мне показалось, что будет достаточно полезным рассмотреть 2 достаточно распространённых способа коммуникации устройств. Начнём мы с энергоэффективного протокола BLE.

Что такое Bluetooth? Это беспроводной стандарт связи для обмена данными на коротком расстоянии. Как и WiFi, Bluetooth работает на частоте 2.4 ГГц.

image
Источник картинки: wikihandbk.com

Bluetooth применяется во множестве разных ситуаций, где требуется беспроводное управление и передача данных. Например:

  • Передача аудиоданных в наушники или аудиосистему автомобиля
  • Коммуникация между периферийными устройствами и ПК
  • Передача данных между Bluetooth-устройствами

Другими словами, Bluetooth используется в ситуациях, когда для передачи данных между устройствами требуется непрерывное сквозное («точка-точка») подключение.

Что такое Bluetooth Low Energy (BLE)? – это энергосберегающий вариант Bluetooth, и его главная область применения – это передача маленьких порций данных на короткие расстояния. Этот стандарт предназначен для очень маломощных проектов, питаемых от батареек-таблеток.

image
Источник картинки: wikihandbk.com

В отличие от Bluetooth, который включён постоянно, BLE-устройство постоянно находится в спящем режиме, кроме ситуаций, когда оно подключено к другим устройствам. Благодаря этому BLE-устройства потребляют очень мало питания. Эта функция крайне полезна для коммуникации типа M2M (англ. «machine-to-machine», т.е. «между машинами»), т.к. позволяет делать проекты из маленьких устройств, питаемых от батареек и работающих очень долгое время.

Из-за этого стандарт BLE идеален для проектов, где требуется периодический обмен небольшими порциями данных – например, в медицине, фитнесе, отслеживании объектов, навигации, безопасности и домашней автоматизации.

О других различиях между Bluetooth и BLE можно посмотреть в таблице ниже:

Bluetooh Low Energy (BLE) Bluetooh:
Базовый режим (Base Rate, BR) /
Дополнительный режим (Enhanced Date Rate, EDR)
Оптимизирован для: Передача данных “короткими очередями” Постоянный поток данных
Диапазон частот ISM-диапазон 2.4 ГГц
(2.402 — 2.480 ГГц)
ISM-диапазон 2.4 ГГц
(2.402 — 2.480 ГГц)
Каналы 40 каналов с диапазоном 2 МГц
(3 канала для оповещений, 37 каналов для
данных)
79 каналов с диапазоном 1 МГц
Использование
каналов
Псевдослучайная перестройка
рабочей частоты (FHSS)
Псевдослучайная перестройка
рабочей частоты (FHSS)
Модуляция GFSK GFSK, π/4 DQPSK, 8DPSK
Энергопотребление Примерно от 0.01х до 0.5х
относительно опорной величины
(зависит от способа применения)
1 (опорная величина)
Скорость передачи данных * LE2М РНУ: 2 Мбит/с
* LE1М РНУ: 1 Мбит/с
* LE Coded РНУ (S=2): 500 Кбит/с
* LE Coded РНУ (s=8): 125 Кбит/с
* EDR РНУ (8DPSK): 3 Мбит/с
* EDR РНУ (п/4 DQPSK): 2 Мбит/с
* BR PHY (GFSK): 1 Мбит/с
Макс. мощность * Класс 1: 100 мВТ (+20 дБм)
* Класс 1.5: 10 мВт (+10 дБм)
* Класс 2: 2.5 мВт (+4 дБм)
* Класс 3: 1 мВт (0 дБм)
* Класс 1: 100 мВт (+20 дБм)
* Класс 2: 2.5 мВт (+4 дм)
* Класс 3: 1 мВт (0 дБм)
Сетевая топология * “Точка-точка” (включая “пикосеть”)
* Вещание
* Ячеистая сеть
“Точка-точка” (включая “пикосеть”)

В стандарте Bluetooth Low Energy предусмотрено два типа устройств: сервер и клиент.
Сервер оповещает о своём существовании, чтобы его могли найти другие устройства, а также содержит данные для считывания клиентом. Клиент сканирует близлежащие устройства и, найдя искомый сервер, подключается к нему и начинает прослушивать входящие данные. Этот тип коммуникации называют «сквозным» или «точка-точка».

Стандарт BLE предусматривает и другие типы подключения:

  • Режим вещания. Сервер передаёт данные нескольким клиентам, подключённым к нему.
  • Ячеистая сеть. Все устройства подключены друг к другу. Это тип соединения, когда в сети несколько устройств и у каждого из них по несколько подключений.

Теперь давайте рассмотрим несколько важных терминов, касающихся BLE.

GATT — расшифровывается как «generic attributes» («общие атрибуты»). Эта спецификация определяет иерархию данных, которую BLE-устройство демонстрирует другим BLE-устройствам, подключённым к нему. Другими словами, GATT определяет то, как два BLE-устройства отправляют и получают стандартные сообщения.

image
Источник картинки: wikihandbk.com

На верхнем уровне этой иерархии – профиль, состоящий из одного или более сервисов. Каждый сервис содержит как минимум одну характеристику, а также может отсылать к другим сервисам.

Характеристики всегда находятся внутри сервисов, и это то место, где, собственно, хранятся данные во всей этой GATT-иерархии. Характеристика имеет уникальный идентификатор (UID), значение и свойства.

Кроме того, после значения характеристики могут идти дескрипторы, которые дополняют метаданные, содержащиеся в объявлении характеристики.

Каждый сервис, характеристика и дескриптор имеют собственный UUID (англ. «universally unique identifier», что переводится как «универсальный уникальный идентификатор»). UUID – это уникальное 128-битное (16-байтное) число вроде такого:

55072829-bc9e-4c53-938a-74a6d4c78776

Сокращённые UUID для всех сервисов, характеристик, профилей и т.д. можно найти на сайте Bluetooth SIG.

Но если вашему приложению нужен собственный UUID, его можно сгенерировать при помощи этого UUID-генератора.

Итак, теперь, когда мы немного ознакомились с теоретической стороной вопроса, посмотрим, как это можно было бы реализовать на базе esp32.

Так как мы осуществляем связь двух модулей esp32 между собой — нам понадобится серверный и клиентский код.

Посмотрим общий случай такой реализации и начнём с серверной части:

Сначала мы подключаем необходимые библиотеки:

#include <BLEDevice.h> #include <BLEUtils.h> #include <BLEServer.h>

Генерируем с помощью сервиса, указанного выше, уникальные UUID:

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b" #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

Создаём BLE-устройство:

  BLEDevice::init("Eto moye imya");

Создаём BLE-сервер:

  BLEServer *pServer = BLEDevice::createServer();

Создаём сервис и характеристику с указанными UUID:

  BLEService *pService = pServer->createService(SERVICE_UUID);   BLECharacteristic *pCharacteristic = pService->createCharacteristic(                                          CHARACTERISTIC_UUID,                                          BLECharacteristic::PROPERTY_READ |                                          BLECharacteristic::PROPERTY_WRITE                                        );

После чего устанавливаем начальное значение характеристики, запускаем сервис и начинаем широковещательную рассылку уведомлений:

  pCharacteristic->setValue("Всем привет!");   pService->start();   BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();   pAdvertising->addServiceUUID(SERVICE_UUID);   pAdvertising->setScanResponse(true);   pAdvertising->setMinPreferred(0x06);     pAdvertising->setMinPreferred(0x12);   BLEDevice::startAdvertising();   Serial.println("Характеристика установлена! Теперь вы можете прочитать её на телефоне!");

После прошивки программы в микроконтроллер в мониторе COM-порта появляются приветственные сообщения:

Теперь посмотрим на клиентскую часть.

Также подключаем необходимую библиотеку:

#include "BLEDevice.h"

Далее указываем UUID сервиса и характеристики (должны совпадать с таковыми на сервере):

static BLEUUID serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b"); static BLEUUID    charUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8");

Так как клиентская часть содержит достаточно большое количество служебного кода, в разы превышающего серверный код, имеет смысл остановиться на главном: после осуществления поиска и успешного соединения с сервером клиент обновляет характеристику сервиса на удалённом сервере:

if (connected) {     String newValue = "Time since boot: " + String(millis()/1000);     Serial.println("Setting new characteristic value to \"" + newValue + "\"");     pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length());   }else if(doScan){     BLEDevice::getScan()->start(0);     } 

И в мониторе COM-порта клиента эта картина выглядит следующим образом:

Таким образом, используя энергоэффективный метод связи с использованием BLE, вы можете реализовывать свои интересные применения этого типа связи.

Поговорим теперь и о связи с использованием Wi-Fi

Здесь одно устройство также будет играть роль сервера, а другое — клиента.
Структура вкладок сервер выглядит следующим образом:

Структура вкладок клиента:

Вообще говоря, схема работы выглядит примерно так: «я сам себе и дедушка, и любимый внук» 🙂

То есть: 1) запущена wi-fi сеть; 2) запущен сервер и на клиенте, и на точке доступа;

Подробнее рассмотрим код сервера на точке доступа

Для работы нам понадобятся следующие библиотеки:

#include "WiFi.h" #include "ESPAsyncWebServer.h" #include <HTTPClient.h>

Конфигурируем точку доступа, а также определяем адрес сервера на клиенте, куда будем обращаться с точки доступа:

const char* ssid = "ESP32-Access-Point"; const char* password = "123456789"; const char* SlaveServerName = "http://192.168.4.2/post"; 

Запускаем сервер на 80 порту:

AsyncWebServer server(80); void setup() {   Serial.begin(115200);   Serial.println();   Serial.print("Setting AP (Access Point)…");   WiFi.softAP(ssid, password);   IPAddress IP = WiFi.softAPIP();   Serial.print("AP IP address: ");   Serial.println(IP);   Server ();//запустили сервер для входящих POST-запросов }

Функция Server (), вызывающаяся в последней строке (выше), служит для прослушивания входящих POST-запросов и реализована во вкладке server:

void Server () {     server.on(     "/post",     HTTP_POST,     [](AsyncWebServerRequest * request){},     NULL,     [](AsyncWebServerRequest * request, uint8_t *data, size_t len, size_t index, size_t total) {  //      IsReadyForRead = false;       for (size_t i = 0; i < len; i++) {         Serial.write(data[i]);       }         Serial.println();         request->send(200);   });       server.begin(); }

Ну и в методе loop () — мы вызываем тестовую функцию TestSender, которая отсылает сообщение клиенту:

void loop() {TestSender ();}  void TestSender () {     WiFiClient client;     HTTPClient http;           // Your Domain name with URL path or IP address with path     http.begin(client, SlaveServerName);      // отсылаем то, что получили //    If you need an HTTP request with a content type: text/plain     http.addHeader("Content-Type", "text/plain");       int httpResponseCode = http.POST("Привет!");      Serial.print("HTTP Response code: ");     Serial.println(httpResponseCode);      // Освобождаем ресурсы     http.end();  }

Теперь рассмотрим код клиента точки доступа

Подключаем необходимые библиотеки:

#include <WiFi.h> #include <HTTPClient.h> #include <Wire.h> #include "ESPAsyncWebServer.h"

Задаём логин и пароль точки доступа, к которой будем подключаться:

const char* ssid = "ESP32-Access-Point"; const char* password = "123456789";

Определяем адрес для обращений на сервере (у точки доступа):

const char* MainServerName = "http://192.168.4.1/post";

Подключаемся к точке доступа и запускаем сервер для прослушки входящих POST-запросов:

AsyncWebServer server(80);  void setup() {   Serial.begin(115200);     WiFi.begin(ssid, password);   Serial.println("Connecting");   while(WiFi.status() != WL_CONNECTED) {     delay(500);     Serial.print(".");   }   Serial.println("");   Serial.print("Connected to WiFi network with IP Address: ");   Serial.println(WiFi.localIP());    Server ();//запустили сервер для входящих POST-запросов   }

Функция Server () — в последней строке (выше) полностью аналогична таковой у точки доступа и служит для прослушивания POST-запросов:

void Server () {     server.on(     "/post",     HTTP_POST,     [](AsyncWebServerRequest * request){},     NULL,     [](AsyncWebServerRequest * request, uint8_t *data, size_t len, size_t index, size_t total) {  //      IsReadyForRead = false;       for (size_t i = 0; i < len; i++) {         Serial.write(data[i]);       }         Serial.println();         request->send(200);   });       server.begin(); }

Ну и в методе loop () — мы вызываем тестовую функцию TestSender (), которая отсылает сообщение на POST-сервер, запущенный на точке доступа:

 void loop() {TestSender ();}  void TestSender () {     WiFiClient client;     HTTPClient http;     http.begin(client, MainServerName);      // отсылаем то, что получили //    If you need an HTTP request with a content type: text/plain     http.addHeader("Content-Type", "text/plain");       int httpResponseCode = http.POST("И тебе привет!");      Serial.print("HTTP Response code: ");     Serial.println(httpResponseCode);      // Освобождаем ресурсы     http.end(); }

После включения обоих модулей esp32 вот так эта картина выглядит в мониторе COM-порта точки доступа:

И клиента:

Библиотеку для работы wi-fi варианта можно скачать здесь: ESPAsyncWebServer
Все необходимые библиотеки для работы BLE-варианта устанавливаются автоматически при инсталляции поддержки esp32 в Arduino IDE.

Код сервера и клиента для BLE можно скачать здесь, для wi-fi варианта — тут.

Код для обоих вариантов полностью рабочий и протестирован. «Бери и используй!» 🙂

Вот такими интересными способами вы можете наладить связь между 2-мя и более устройствами esp32. Успехов в проектировании!


НЛО прилетело и оставило здесь промокоды для читателей нашего блога:

15% на все тарифы VDS (кроме тарифа Прогрев) — HABRFIRSTVDS.

20% на выделенные серверы AMD Ryzen и Intel Core HABRFIRSTDEDIC.


ссылка на оригинал статьи https://habr.com/ru/company/first/blog/596741/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *