BLE的Server通常是提供多种Service的设备,每个Service底下包含了多个Characteristic,每个Characteristic的值通常都代表一定的意义。这种设备通常需要通过广播来告诉别的设备自己是谁,能提供什么样的数据,所以也成为“从设备”。
BLE的Client通常Scan周围的BLE设备,然后发现了自己感兴趣的设备,并且匹配到了相应的Service UUId和Characteristic UUID后,即可获取上述BLE Server提供的数据。
下面的例子中:ESP32-C6是BLE SERVER,是从设备,把自己广播给周围的设备。
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
void BLEBegin(){
// Create the BLE Device
BLEDevice::init(/*BLE名称*/"UART Service");
// Create the BLE Server
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic
pTxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY
);
pTxCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pRxCharacteristic->setCallbacks(new MyCallbacks());
// Start the service
pService->start();
// Start advertising
pServer->getAdvertising()->addServiceUUID(SERVICE_UUID);
pServer->getAdvertising()->start();
Serial.println("Waiting a client connection to notify...");
}
上述代码中,启动广播之前,把自己能提供的SERVICE UUID也广播出去。接下来是手机BLE助手上看一下。
通过BLE助手向CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" 写入数据:
完整代码如下:
/*
Video: https://www.youtube.com/watch?v=oCMOYS71NIU
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
Ported to Arduino ESP32 by Evandro Copercini
Create a BLE server that, once we receive a connection, will send periodic notifications.
The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE"
Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with "NOTIFY"
The design of creating the BLE server is:
1. Create a BLE Server
2. Create a BLE Service
3. Create a BLE Characteristic on the Service
4. Create a BLE Descriptor on the characteristic
5. Start the service.
6. Start advertising.
*/
/* 该示例演示了蓝牙数据透传,烧录代码,打开串口监视器,打开手机的BLE调试助手
* 1.即可看见ESP32发送的数据--见APP使用图
* 2.通过BLE调试助手的输入框可向ESP32发送数据--见APP使用图
* 该示例由BLE_uart示例更改而来
*/
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
BLEServer *pServer = NULL;
BLECharacteristic * pTxCharacteristic;
bool deviceConnected = false;
uint8_t txValue = 0;
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
//蓝牙连接/断开处理。当有连接/断开事件发生时自动触发
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) { //当蓝牙连接时会执行该函数
Serial.println("蓝牙已连接");
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) { //当蓝牙断开连接时会执行该函数
Serial.println("蓝牙已断开");
deviceConnected = false;
delay(500); // give the bluetooth stack the chance to get things ready
pServer->startAdvertising(); // restart advertising
}
};
/****************数据接收部分*************/
/****************************************/
//蓝牙接收数据处理。当收到数据时自动触发
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = (pCharacteristic->getValue()).c_str();//接收数据,并赋给rxValue
//if(rxValue == "ON"){Serial.println("开灯");} //判断接收的字符是否为"ON"
if (rxValue.length() > 0) {
Serial.println("*********");
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++){
Serial.print(rxValue[i]);
}
Serial.println();
Serial.println("*********");
}
}
};
/***************************************/
/****************************************/
void setup() {
Serial.begin(115200);
BLEBegin(); //初始化蓝牙
}
void loop() {
/****************数据发送部分*************/
/****************************************/
if (deviceConnected) { //如果有蓝牙连接,就发送数据
pTxCharacteristic->setValue("Hello"); //发送字符串
pTxCharacteristic->notify();
delay(10); // bluetooth stack will go into congestion, if too many packets are sent
pTxCharacteristic->setValue("DFRobot"); //发送字符串
pTxCharacteristic->notify();
delay(10); // bluetooth stack will go into congestion, if too many packets are sent
}
/****************************************/
/****************************************/
}
void BLEBegin(){
// Create the BLE Device
BLEDevice::init(/*BLE名称*/"UART Service");
// Create the BLE Server
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic
pTxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY
);
pTxCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pRxCharacteristic->setCallbacks(new MyCallbacks());
// Start the service
pService->start();
// Start advertising
pServer->getAdvertising()->addServiceUUID(SERVICE_UUID);
pServer->getAdvertising()->start();
Serial.println("Waiting a client connection to notify...");
}