Освой Arduino играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

ESP32: Bluetooth

Посылаем данные через последовательный порт
Регистрируем события
Включаем светодиод с телефона
Узнать адрес ESP32-устройства
Присвоить новое имя устройству

В состав платы входит классический Bluetooth. Пример можно найти в разделе Examples/BluetoothSerial/SerialToSerialBT. В примере используется библиотека BluetoothSerial.

Bluetooth Low Energy (BLE) также доступен на плате. Это тема другой статьи

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


#include "BluetoothSerial.h"
 
BluetoothSerial SerialBT;
 
void setup() {
  SerialBT.begin("ESP32");
}
 
void loop() {
  SerialBT.println("Hello World");
  delay(1000);
}

В реальных устройствах всё-таки не помешает дополнительная проверка.


void setup() {
  Serial.begin(115200);

  if (!SerialBT.begin("ESP32")) {
    Serial.println("An error occurred initializing Bluetooth");
  } else {
    Serial.println("Bluetooth initialized");
  }
}

Посылаем данные через последовательный порт

В Windows вы можете обнаружить плату через специальное окно настроек "Bluetooth & other devices" (англ.версия). Затем в диспетчере устройств нужно посмотреть появившегося номер COM-порта. После этого в Arduino IDE нужно выбрать данный порт и открыть "Монитор порта", в котором будут появляться сообщения.

Сначала напишем простой скетч, который будет считывать данные с компьютера или смартфона.


#include "BluetoothSerial.h"

BluetoothSerial SerialBT;

void setup() {
  Serial.begin(115200);

  if (!SerialBT.begin("ESP32")) {
    Serial.println("An error occurred initializing Bluetooth");
  }
}

void loop() {
  while (SerialBT.available()) {
    Serial.write(SerialBT.read());
  }

  delay(50);
}

Данные удобно посылать через приложение Putty. В настройках выбираем тип соединения Serial и выставляем скорость. Главное - не ошибиться с номером порта, попробуйте методом перебора.

Putty General

Затем в блоке Terminal выбираем настройки Force on.

Putty Terminal

После запуска появляется чёрный экран консоли, в котором можно вводить команды.

Putty Console

Посылаемые команды отображаются в мониторе порта.

Serial Monitor

Регистрируем события

Мы посылаем сообщения вслепую, не зная, соединился ли клиент к плате. Чтобы избежать этой проблемы, можем добавить в скетч функцию обратного вызова через register_callback(). Тем самым мы сможем отслеживать момент соединения компьютера (Putty).


#include "BluetoothSerial.h"

BluetoothSerial SerialBT;

void callback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param){
  if(event == ESP_SPP_SRV_OPEN_EVT){
    Serial.println("Client Connected");
  }
}

void setup() {
  Serial.begin(115200);

  SerialBT.register_callback(callback);

  if (!SerialBT.begin("ESP32")) {
    Serial.println("An error occurred initializing Bluetooth");
  }
  else {
    Serial.println("Bluetooth initialized");
  }
}

void loop() {
  while (SerialBT.available()) {
    Serial.write(SerialBT.read());
  }

  delay(50);
}

Снова запустите скетч и установите соединение через Putty. В успешном случае в мониторе порта появится сообщение Client Connected.

Можно не только отследить наступление события подключения клиента к плате, но и его адрес. Добавим немного дополнительного кода в функцию обратного вызова.


#include "BluetoothSerial.h"

BluetoothSerial SerialBT;

void callback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param) {
  if (event == ESP_SPP_SRV_OPEN_EVT) {
    Serial.println("Client Connected");
    
    Serial.println("Client Connected has address:");

    for (int i = 0; i < 6; i++) {
      Serial.printf("%02X", param->srv_open.rem_bda[i]);
      if (i < 5) {
        Serial.print(":");
      }
    }
    Serial.println("--------------");
  }
}

void setup() {
  Serial.begin(115200);

  SerialBT.register_callback(callback);

  if (!SerialBT.begin("ESP32")) {
    Serial.println("An error occurred initializing Bluetooth");
  }
  else {
    Serial.println("Bluetooth initialized");
  }
}

void loop() {
  while (SerialBT.available()) {
    Serial.write(SerialBT.read());
  }

  delay(50);
}

Снова пытаемся соединиться с платой с компьютера или телефона и получаем адреса подключаемых устройств. На скриншоте показано, как я дважды подключался к плате с разных устройств.

Client Bluetooth

Включаем светодиод с телефона

Посылать данные можно с Android-телефона. Сначала в настройках нужно присоединиться к плате, а затем через приложение, которое умеет работать как Bluetooth-терминал (например, Bluetooth Terminal), увидеть поступающие сообщения или отправлять собственные команды.

Немного видоизменённый пример, в котором добавлена проверка на поступление символов 0 и 1 с Android-устройства (код для Android).


// Подключаем библиотеку
#include "BluetoothSerial.h"

// Проверка, что Bluetooth доступен на плате
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

// Создаём экземпляр класса
BluetoothSerial SerialBT;

int LED = 2; // встроенный светодиод

void setup() {
  Serial.begin(115200); // включаем передачу данных у последовательного порта
  SerialBT.begin("ESP32"); // Может придумать своё имя
  Serial.println("The device started, now you can pair it with bluetooth!");
  pinMode(LED, OUTPUT);
}

void loop() {
  if (Serial.available()) {
    SerialBT.write(Serial.read());
  }
  if (SerialBT.available()) {
    char incomingChar = SerialBT.read();
    Serial.write(incomingChar);

    // При символе "1" включаем светодиод
    if (incomingChar == '1')
    {
      digitalWrite(LED, HIGH);
      Serial.println("On");
    }
    // При символе "0" выключаем светодиод
    if ( incomingChar == '0')
    {
      digitalWrite(LED, LOW);
      Serial.println("Off");
    }
  }
  delay(20);
}

После заливки скетча нужно дождаться появления надписи "The device started, now you can pair it with bluetooth!" в мониторе порта.

Дальше нужно послать команды. Это можно сделать через программу на Android (ссылка на исходник дана выше) или можно использовать готовую программу Bluetooth Terminal.

Bluetooth Terminal также может получать данные из платы. Вам нужно набрать любое слово в мониторе порта и оно отобразится на телефоне.

В последнее время наткнулся на новый терминал Serial Bluetooth Terminal с открытыми исходниками для Android-устройств Classic Bluetooth и BLE.

Узнать адрес ESP32-устройства

С помощью низкоуровневых функций можно узнать адрес-устройства.

У каждого Bluetooth-устройства есть адрес, по которому можно определить изготовителя. На сайте можно вбить адрес и получить имя производителя.


#include "esp_bt_main.h"
#include "esp_bt_device.h"

bool initBluetooth()
{
  if (!btStart()) {
    Serial.println("Failed to initialize controller");
    return false;
  }

  if (esp_bluedroid_init() != ESP_OK) {
    Serial.println("Failed to initialize bluedroid");
    return false;
  }

  if (esp_bluedroid_enable() != ESP_OK) {
    Serial.println("Failed to enable bluedroid");
    return false;
  }
}

void printDeviceAddress() {

  const uint8_t* point = esp_bt_dev_get_address();

  for (int i = 0; i < 6; i++) {
    char str[3];
    sprintf(str, "%02X", (int)point[i]);
    Serial.print(str);

    if (i < 5) {
      Serial.print(":");
    }
  }
}

void setup() {
  Serial.begin(115200);

  initBluetooth();
  printDeviceAddress();
}

void loop() {}

После запуска скетча откройте монитор порта. Там вы должны увидеть адрес вида 24:0A:C4:27:07:66. Скопируйте адрес и определите производителя через сайт (ссылка выше). В моём случае это оказался Espressif Inc.

Присвоить новое имя устройству

Функция esp_bt_dev_set_device_name() позволяет присвоить устройству новое имя.


#include "esp_bt_main.h"
#include "esp_gap_bt_api.h"
#include "esp_bt_device.h"

bool initBluetooth(const char *deviceName)
{
  if (!btStart()) {
    Serial.println("Failed to initialize controller");
    return false;
  }

  if (esp_bluedroid_init() != ESP_OK) {
    Serial.println("Failed to initialize bluedroid");
    return false;
  }

  if (esp_bluedroid_enable() != ESP_OK) {
    Serial.println("Failed to enable bluedroid");
    return false;
  }

  esp_bt_dev_set_device_name(deviceName);

  esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
}

void setup() {
  Serial.begin(115200);

  if (!initBluetooth("ESP32 BT")) {
    Serial.println("Bluetooth init failed");
  };
}

void loop() {}

Запустите пример и откройте монитор порта. Если никаких сообщений вы не видите, значит инициализация модуля прошла успешно. Теперь можете открыть окно настроек в Windows или на Android-телефоне и посмотреть список доступных Bluetooth-устройств. В списке вы должны увидеть устройство под именем "ESP32 BT".

Дополнительные материалы

Bluetooth для Arduino

Реклама