ESP32 使用Iphone手机接收BLE蓝牙服务端的数据

实验效果

使用Iphone手机通过蓝牙连接ESP32,

ESP32 BLE(服务端)定时发送数据给手机(客户端),ESP32串口显示发送的数据。

ESP32 & BLE的关键概念

基础概念请查看这一篇:ESP32 使用Iphone手机发送数据给BLE蓝牙服务端

这里新增一些概念:

Descriptors(描述符)

参考:https://www.bluetooth.com/specifications/assigned-numbers/

  • 0x2901 Characteristic User Description 它提供一个用户可读的特性描述,用于在客户端呈现或记录目的,以帮助用户理解该特性的用途。
  • 0x2902 Client Characteristic Configuration 这是一个客户端使用的描述符,用于订阅或取消订阅特定特性的通知(Notification)和指示(Indication)。
  • 0x2903 Server Characteristic Configuration 描述符供服务器使用,以指示特性是否会在服务器端被广播。
  • 0x2904 Characteristic Presentation Format 指定了特性值的格式,比如特性值的数据类型、指数(如在浮点型中的用法),单位(如千克、伏特等),以及数值是否有一个命名空间。
  • 0x2905 Characteristic Aggregate Format 当一个特性由多个值组成时,这个描述符定义了这些值如何聚合在一起。
  • 0x2906 Valid Range 指明特性值的有效范围,用于约束该特性可能的取值范围。
  • 0x2907 External Report Reference 参照外部报告的描述符,它允许特性引用服务外部定义的一个或多个报告。
  • 0x2908 Report Reference 这个描述符是用来与特性相关联的报告的引用。它在HID(人机接口设备)服务中非常常用。
  • 0x2909 Number of Digitals 当特性用来表示一系列数字时,这个描述符定义了如何编码这些数字。
  • 0x290A Value Trigger Setting 用于定义触发特性值的变化通知或者读取的条件。
  • 0x290B Environmental Sensing Configuration 与环境感测相关的配置信息,例如触发设置和测量间隔。
  • 0x290C Environmental Sensing Measurement 包含环境感测测量的具体参数,如采样函数、应用级别的分类或者测量周期等。
  • 0x290D Environmental Sensing Trigger Setting 用于环境感测特性的触发设置,例如在特定条件下触发读取或通知。
  • 0x290E Time Trigger Setting 定义特性值变化的时间触发条件,如固定时间间隔、一个段时间后或者预定的时间。
  • 0x290F Complete BR-EDR Transport Block Data 这个描述符与Bluetooth Basic Rate/Enhanced Data Rate (BR/EDR)方案有关,用来处理特性值的传输块数据。
  • 0x2910 Observation Schedule 允许特性定义在特定时间观察或测量的日程。
  • 0x2911 Valid Range and Accuracy 描述特性值的有效范围和准确度,通常与环境感测服务配合使用。 这些描述符通常用于赋予BLE特性更多的上下文和控制信息,让客户端设备能更加精确地理解和利用这些特性。描述符的正确实现和使用可以使BLE服务更加健壮和用户友好。

虽然提供这么多类型的描述符号,但在ESP的BLE库中可以看到只有2902和2904这个有定义:
https://github.com/espressif/arduino-esp32/tree/master/libraries/BLE/src

BOM

ESP32 开发板 x1

Iphone 手机 x1

接线

只用使用USB线连接ESP32开发板,然后在电脑上传程序即可。

之后就是在手机操作连接了。

程序代码

// Welcome to LingShunLAB.com

// 引入BLE功能所需的库
#include 
#include 
#include 
#include 

float sand_value;
bool deviceConnected = false; // 用于储存设备连接状态
// 计时器变量
unsigned long lastTime = 0;
unsigned long timerDelay = 3000;

// 定义BLE UUID
// 可以在以下网站,生成唯一的UUID
// https://www.uuidgenerator.net/
#define SERVICE_UUID "034cabfe-4e54-4845-940f-f5539f8bd41a"
#define SEND_DATA_CHARACTERISTIC_UUID "7161df75-d924-45a4-9076-6b01918059e4"

// 创建带有通知属性的BLE应用服务,并为其添加描述符
BLECharacteristic sendDataCharacteristics(SEND_DATA_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor sendDataUserDescriptionDescriptor((uint16_t)0x2901);

// 定义一个类来处理服务器事件,例如连接和断开连接时设置设备连接状态
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };
    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};

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

  BLEDevice::init("LingShun"); // 初始化设备,并命名为「LingShun」
  BLEServer *pServer = BLEDevice::createServer(); // 创建BLE服务器:
  pServer->setCallbacks(new MyServerCallbacks()); // 设置服务器的回调:
  // 创建BLE服务:
  BLEService *sendDataService = pServer->createService(SERVICE_UUID);
  // 给BLE特性(Characteristic)添加一个用户描述(User Description)
  sendDataUserDescriptionDescriptor.setValue("Send data to iphone");
  sendDataCharacteristics.addDescriptor(&sendDataUserDescriptionDescriptor);
  // 将应用添加到服务中
  sendDataService->addCharacteristic(&sendDataCharacteristics);
  //  创建一个BLE2902描述符实例,并设置开启通知功能
  BLE2902* desc = new BLE2902();
  desc->setNotifications(true);
  sendDataCharacteristics.addDescriptor(desc);
  // 启动服务
  sendDataService->start();
  // 开始广播
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pServer->getAdvertising()->start();
  Serial.println("Waiting a client connection to notify...");
}

void loop() {
  if (deviceConnected) {
    // 每 timerDelay 时间则发送一次数据
    if ((millis() - lastTime) > timerDelay) {
      sand_value = 123.321;

      // 浮点数保留2位小数转换为字符串的例子
      char valueTemp[15];
      //snprintf() 是一个 C 语言标准库函数,
      // 用于格式化输出字符串,并将结果写入到指定的缓冲区
      snprintf(valueTemp, sizeof(valueTemp), "%.2f", sand_value);

      // 设置服务应用 sendDataCharacteristics 的值设置
      sendDataCharacteristics.setValue(valueTemp);
      // 通知已连接的设备
      sendDataCharacteristics.notify();

      // 串口显示发送的数据
      Serial.print(" - valueTemp: ");
      Serial.println(valueTemp);

      lastTime = millis();
    }
  }
}

Iphone 查看接收到ESP32发送过来的信息

已经确保把程序上传成功后,就可以继续以下iphone手机连接蓝牙的操作:

1,下载可连接BLE的APP

在这个例子中使用Iphone系统的蓝牙搜索是无法找到ESP32蓝牙服务端的,需要下载一个「LightBlue」的App进系连接和操作。

打开「App Store」在搜索框中输入「lightblue」,找到如下App,进行安装

image-20240509145327473

2,查看接收到的数据

连接蓝牙设备 -> 点开应用服务 -> 点击「Listen for notifications」

image-20240515112800524

可以看到接收到的数据是「0x3132332E3332」,
这一串16进制,每两位为一个数,转换成10进制,
然后对照ASCII 码表,

最终转换成「123.32」字符串。

3,查看串口的信息

image-20240515112906498