1 蓝牙技术总结

1.1 蓝牙4.0协议
- 蓝牙4.0是协议,4.0是协议版本号,蓝牙4.0是2010年6月由SIG(Special Interest Group)发布的蓝牙标准,它有2种模式:
BLE(Bluetooth low energy)只能与4.0协议设备通信,适应节能且仅收发少量数据的设备(如家用电子)
BR/EDR(Basic Rate / Enhanced Data Rate),向下兼容(能与3.0/2.1/2.0通信),适应收发数据较多的设备(如耳机)这个模式常常也有人称之为“传统蓝牙”或“经典蓝牙”。
- 可以这样理解,蓝牙4.0协议包含BLE,BLE隶属于蓝牙4.0协议的一部分

1.2 GATT概念

2 客户端及服务端进行板间数据交互
2.1 ESP32 S3蓝牙客户端
#include "BLEDevice.h"
#define bleServerName "ESP32-S-test"
static BLEUUID ServiceUUID("91bad492-b950-4226-aa2b-4ede9fa42f59");
static BLEUUID VCharacteristicUUID("cba1d466-344c-4be3-ab3f-189f80dd7518");
static BLEUUID ICharacteristicUUID("ca73b3ba-39f6-4ab3-91ae-186dc9577d99");
static BLEUUID PCharacteristicUUID("92ddd762-3e7d-11ed-b878-0242ac120002");
static boolean doConnect = false;
static boolean connected = false;
static BLEAddress *pServerAddress;
static BLERemoteCharacteristic* VCharacteristic;
static BLERemoteCharacteristic* ICharacteristic;
static BLERemoteCharacteristic* PCharacteristic;
const uint8_t notificationOn[] = {0x1, 0x0};
const uint8_t notificationOff[] = {0x0, 0x0};
char* V_Value;
char* I_Value;
char* W_Value;
boolean new_V_State = false;
boolean new_I_State = false;
boolean new_W_State = false;
bool connectToServer(BLEAddress pAddress) {
BLEClient* pClient = BLEDevice::createClient();
pClient->connect(pAddress);
USBSerial.println(" - Connected to server");
BLERemoteService* pRemoteService = pClient->getService(ServiceUUID);
if (pRemoteService == nullptr) {
USBSerial.print("Failed to find our service UUID: ");
USBSerial.println(ServiceUUID.toString().c_str());
return (false);
}
VCharacteristic = pRemoteService->getCharacteristic(VCharacteristicUUID);
ICharacteristic = pRemoteService->getCharacteristic(ICharacteristicUUID);
PCharacteristic = pRemoteService->getCharacteristic(PCharacteristicUUID);
if (VCharacteristic == nullptr || ICharacteristic == nullptr || PCharacteristic == nullptr) {
USBSerial.print("Failed to find our characteristic UUID");
return false;
}
USBSerial.println(" - Found our characteristics");
VCharacteristic->registerForNotify(VNotifyCallback);
ICharacteristic->registerForNotify(INotifyCallback);
PCharacteristic->registerForNotify(PNotifyCallback);
return true;
}
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
if (advertisedDevice.getName() == bleServerName) {
advertisedDevice.getScan()->stop();
pServerAddress = new BLEAddress(advertisedDevice.getAddress());
doConnect = true;
USBSerial.println("Device found. Connecting!");
}
}
};
static void VNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData, size_t length, bool isNotify) {
V_Value = (char*)pData;
new_V_State = true;
}
static void INotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData, size_t length, bool isNotify) {
I_Value = (char*)pData;
new_I_State = true;
}
static void PNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData, size_t length, bool isNotify) {
W_Value = (char*)pData;
new_W_State = true;
}
void printReadings(){
USBSerial.print("- V_Value:");
USBSerial.println(V_Value);
USBSerial.print("- I_Value:");
USBSerial.println(I_Value);
USBSerial.print("- W_Value:");
USBSerial.println(W_Value);
}
void setup() {
USBSerial.begin(115200);
USBSerial.println("Starting Arduino BLE Client application...");
BLEDevice::init("");
BLEScan* pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true);
pBLEScan->start(30);
}
void loop() {
if (doConnect == true) {
if (connectToServer(*pServerAddress)) {
USBSerial.println("We are now connected to the BLE Server.");
VCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOn, 2, true);
ICharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOn, 2, true);
PCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOn, 2, true);
connected = true;
} else {
USBSerial.println("We have failed to connect to the server; Restart your device to scan for nearby BLE server again.");
}
doConnect = false;
}
if (new_V_State || new_I_State || new_W_State){
new_V_State = false;
new_I_State = false;
new_W_State = false;
printReadings();
}
delay(100);
}
2.2 ESP32 S3蓝牙服务端
- 作为服务器使用,Server可以传入一组回调函数,分别会在有客户端设备接入时和断开连接时触发。
在有设备接入后Advertising广播会被停止,所以要在设备断开连接时重新开启广播,可以通过此处的回调函数知道设备是否断开连接。
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#define bleServerName "ESP32-S-test"
unsigned long lastTime = 0;
unsigned long timerDelay = 100;
bool deviceConnected = false;
float Volt = 220.00;
float Current = 20.00;
float Power = 440.00;
static char V_Value[8];
static char I_Value[8];
static char W_Value[8];
#define SERVICE_UUID "91bad492-b950-4226-aa2b-4ede9fa42f59"
BLECharacteristic VCharacteristic(
"cba1d466-344c-4be3-ab3f-189f80dd7518",
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY |
BLECharacteristic::PROPERTY_INDICATE
);
BLEDescriptor VDescriptor(BLEUUID((uint16_t)0x2902));
BLECharacteristic ICharacteristic(
"ca73b3ba-39f6-4ab3-91ae-186dc9577d99",
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY |
BLECharacteristic::PROPERTY_INDICATE
);
BLEDescriptor IDescriptor(BLEUUID((uint16_t)0x2902));
BLECharacteristic PCharacteristic(
"92ddd765-3e7d-11ed-b878-0242ac120002",
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY |
BLECharacteristic::PROPERTY_INDICATE
);
BLEDescriptor PDescriptor(BLEUUID((uint16_t)0x2902));
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
void setup() {
USBSerial.begin(115200);
BLEDevice::init(bleServerName);
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *bmeService = pServer->createService(SERVICE_UUID);
bmeService->addCharacteristic(&VCharacteristic);
VDescriptor.setValue("V");
VCharacteristic.addDescriptor(&VDescriptor);
bmeService->addCharacteristic(&ICharacteristic);
IDescriptor.setValue("I");
ICharacteristic.addDescriptor(&IDescriptor);
bmeService->addCharacteristic(&PCharacteristic);
PCharacteristic.setValue("P");
PCharacteristic.addDescriptor(&PDescriptor);
bmeService->start();
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pServer->getAdvertising()->start();
USBSerial.println("Waiting a client connection to notify...");
}
void loop() {
if (deviceConnected) {
USBSerial.println("client connected.");
if ((millis() - lastTime) > timerDelay) {
dtostrf(Volt,6,2,V_Value);
VCharacteristic.setValue(V_Value);
VCharacteristic.notify();
dtostrf(Current,6,2,I_Value);
ICharacteristic.setValue(I_Value);
ICharacteristic.notify();
dtostrf(Power,6,2,W_Value);
PCharacteristic.setValue(W_Value);
PCharacteristic.notify();
USBSerial.print(" - V_Value: ");
USBSerial.println(V_Value);
USBSerial.print(" - I_Value: ");
USBSerial.println(I_Value);
USBSerial.print(" - W_Value: ");
USBSerial.println(W_Value);
lastTime = millis();
}
}
else{USBSerial.println("client connection failed.");}
delay(50);
}