【物联网】BLE Fundamentals 核心概念总结-广告-读写特征-LED控制-传感器通知-上下游通信过程
BLE 开发完整指南与应用
一、BLE 核心概念总结
1. 角色定义
- Peripheral(外设):Arduino Nano 33 IoT,作为数据提供者
- Central(中心设备):树莓派/手机,作为数据消费者
2. 通信模式
- Advertising(广告):设备广播自身存在
- Connection(连接):建立稳定通信链路
- GATT 通信:通过服务/特征进行数据交换
3. 数据操作类型
- Read:中心设备读取数据
- Write:中心设备写入命令
- Notify:外设主动推送数据
二、核心库函数详解
1. BLE 初始化
#include <ArduinoBLE.h> // 引入BLE库if (!BLE.begin()) { // 初始化BLE模块Serial.println("Failed to initialize BLE!");while (true); // 初始化失败则停止
}
2. 设备配置
// 设置设备标识(重要:使用唯一名称)
BLE.setDeviceName("Arduino_Sensor_xx"); // 内部设备名
BLE.setLocalName("Arduino_Sensor_xx"); // 广播显示名
BLE.setConnectable(true); // 允许连接(默认为true)
3. 服务与特征创建
// 定义UUID(必须唯一)
#define SERVICE_UUID "12345678-1234-1234-1234-123456789abc"
#define SENSOR_CHAR_UUID "87654321-4321-4321-4321-cba987654321"
#define COMMAND_CHAR_UUID "11111111-2222-3333-4444-555555555555"// 创建服务
BLEService sensorService(SERVICE_UUID);// 创建特征(不同权限组合)
BLEStringCharacteristic sensorCharacteristic(SENSOR_CHAR_UUID,BLERead | BLENotify, // 可读+通知100 // 最大数据长度
);BLEStringCharacteristic commandCharacteristic(COMMAND_CHAR_UUID, BLEWrite, // 只写20 // 命令通常较短
);
4. 服务组装与广播
// 添加特征到服务
sensorService.addCharacteristic(sensorCharacteristic);
sensorService.addCharacteristic(commandCharacteristic);// 添加服务到BLE栈
BLE.addService(sensorService);// 设置广告服务并开始广播
BLE.setAdvertisedService(sensorService);
BLE.advertise();
5. 事件处理循环
void loop() {BLE.poll(); // 必须定期调用,处理BLE事件// 检查特征写入if (commandCharacteristic.written()) {String command = commandCharacteristic.value();processCommand(command); // 处理接收到的命令}// 定期发送传感器数据static unsigned long lastSend = 0;if (millis() - lastSend > 5000) { // 每5秒发送一次sendSensorData();lastSend = millis();}
}
三、四个示例代码的详细注释与应用
1. BLE_advertise.ino - 基础广告示例
// 作用:仅广播设备存在,不接受连接
// 应用:测试设备可见性,调试广播设置#include <ArduinoBLE.h>void setup() {Serial.begin(9600);if (!BLE.begin()) {Serial.println("Failed to initialize BLE!");while (true);}BLE.setDeviceName("YourName"); // 设置设备名BLE.setLocalName("YourName"); // 设置广播名BLE.setConnectable(false); // 禁止连接,纯广播模式BLE.advertise(); // 开始广播Serial.println("BLE advertising started...");
}void loop() {BLE.poll(); // 维持BLE栈运行// 纯广播模式,无其他操作
}
2. BLE_read-write.ino - 读写特征示例
// 作用:提供可读写的文本特征
// 应用:调试基本的BLE通信,测试命令传输#include <ArduinoBLE.h>#define SERVICE_UUID "19B10000-E8F2-537E-4F6C-D104768A1214"
#define CHARACTERISTIC_UUID "19B10001-E8F2-537E-4F6C-D104768A1214"BLEService customService(SERVICE_UUID);
BLECharacteristic rwCharacteristic(CHARACTERISTIC_UUID,BLERead | BLEWrite, // 读写权限20 // 最大20字节
);void setup() {Serial.begin(9600);if (!BLE.begin()) {Serial.println("Failed to initialize BLE!");while (true);}BLE.setDeviceName("YourName");BLE.setLocalName("YourName");BLE.setAdvertisedService(customService);customService.addCharacteristic(rwCharacteristic);BLE.addService(customService);rwCharacteristic.writeValue("Hello World"); // 设置初始值BLE.advertise();Serial.println("BLE advertising with read/write characteristic started...");
}void loop() {BLE.poll();if (rwCharacteristic.written()) {String newValue = String((const char*)rwCharacteristic.value());Serial.print("Characteristic written: ");Serial.println(newValue);// 在这里可以添加命令处理逻辑}delay(100);
}
3. BLE_LED-ctrl.ino - LED控制示例
// 作用:通过BLE控制LED
// 应用:学习如何通过BLE控制执行器#include <ArduinoBLE.h>#define SERVICE_UUID "19B20000-E8F2-537E-4F6C-D104768A1214"
#define LED_CHAR_UUID "19B20001-E8F2-537E-4F6C-D104768A1214"BLEService ledService(SERVICE_UUID);
BLECharacteristic ledCharacteristic(LED_CHAR_UUID,BLEWrite | BLERead, // 读写权限1 // 1字节数据(0或1)
);void setup() {Serial.begin(9600);pinMode(LED_BUILTIN, OUTPUT);digitalWrite(LED_BUILTIN, LOW); // 初始关闭LEDif (!BLE.begin()) {Serial.println("Failed to initialize BLE!");while (true);}BLE.setDeviceName("YourName");BLE.setLocalName("YourName");BLE.setAdvertisedService(ledService);ledService.addCharacteristic(ledCharacteristic);BLE.addService(ledService);uint8_t off = 0;ledCharacteristic.writeValue(off); // 设置初始值为0BLE.advertise();Serial.println("BLE LED Control service started");
}void loop() {BLE.poll();if (ledCharacteristic.written()) {uint8_t value = ledCharacteristic.value()[0]; // 读取第一个字节if (value == 1) {digitalWrite(LED_BUILTIN, HIGH);Serial.println("LED ON");} else {digitalWrite(LED_BUILTIN, LOW);Serial.println("LED OFF");}}
}
4. BLE_sensor-notify.ino - 传感器通知示例
// 作用:实时推送传感器数据
// 应用:学习如何实现实时数据流#include <ArduinoBLE.h>
#include <Arduino_LSM6DS3.h> // IMU传感器库BLEService imuService("19B10000-E8F2-537E-4F6C-D104768A1214");
BLECharacteristic imuDataCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify, // 可读+通知权限32 // 足够存储传感器数据
);void setup() {Serial.begin(9600);if (!IMU.begin()) { // 初始化IMU传感器Serial.println("Failed to initialize IMU!");while (1);}if (!BLE.begin()) {Serial.println("Starting BLE failed!");while (1);}BLE.setLocalName("YourName");BLE.setAdvertisedService(imuService);imuService.addCharacteristic(imuDataCharacteristic);BLE.addService(imuService);imuDataCharacteristic.setValue("0.00,0.00,0.00"); // 初始值BLE.advertise();Serial.println("BLE advertising with sensor notify characteristic started...");
}void loop() {BLEDevice central = BLE.central(); // 检查中心设备连接if (central) {Serial.print("Connected to central: ");Serial.println(central.address());while (central.connected()) { // 保持连接时持续发送数据float x, y, z;if (IMU.accelerationAvailable()) {IMU.readAcceleration(x, y, z);// 格式化传感器数据String imuString = String(x, 2) + "," + String(y, 2) + "," + String(z, 2);Serial.println("Sending: " + imuString);// 更新特征值(会自动通知订阅的客户端)imuDataCharacteristic.setValue(imuString.c_str());}delay(100); // 10Hz更新频率}Serial.print("Disconnected from central: ");Serial.println(central.address());}
}
四、具体应用方案
1. 上游通信(传感器数据 → BLE → MQTT)
// Arduino端 - 传感器数据特征
BLEStringCharacteristic dhtCharacteristic(DHT_CHAR_UUID,BLERead | BLENotify, // 可读+通知100
);// 定期更新传感器数据
void updateDHTData() {float temp = dht.readTemperature();float humidity = dht.readHumidity();String jsonData = "{\"temp\":" + String(temp) + ",\"humidity\":" + String(humidity) + "}";dhtCharacteristic.writeValue(jsonData); // 自动通知订阅者
}
2. 下游通信(MQTT → BLE → 执行器控制)
// Arduino端 - 命令特征
BLEStringCharacteristic commandCharacteristic(COMMAND_CHAR_UUID,BLEWrite, // 只写权限20
);// 处理接收到的命令
void loop() {BLE.poll();if (commandCharacteristic.written()) {String command = commandCharacteristic.value();if (command == "LED_ON") {digitalWrite(LED_PIN, HIGH);Serial.println("LED turned ON via BLE");} else if (command == "LED_OFF") {digitalWrite(LED_PIN, LOW);Serial.println("LED turned OFF via BLE");}else if (command == "BUZZER_BEEP") {playTone(1000, 200);Serial.println("Buzzer activated via BLE");}}
}
3. 完整的代码结构
#include <ArduinoBLE.h>
#include <DHT.h>// UUID定义
#define SERVICE_UUID "你的服务UUID"
#define DHT_CHAR_UUID "你的传感器特征UUID"
#define CMD_CHAR_UUID "你的命令特征UUID"// 引脚定义
#define DHT_PIN 2
#define LED_PIN LED_BUILTIN
#define BUZZER_PIN 5DHT dht(DHT_PIN, DHT11);
BLEService sensorService(SERVICE_UUID);
BLEStringCharacteristic dhtCharacteristic(DHT_CHAR_UUID, BLERead | BLENotify, 100);
BLEStringCharacteristic cmdCharacteristic(CMD_CHAR_UUID, BLEWrite, 20);void setup() {// 初始化串口、传感器、引脚// 初始化BLE并配置服务特征// 开始广播
}void loop() {BLE.poll();// 处理命令if (cmdCharacteristic.written()) {processCommand(cmdCharacteristic.value());}// 定期发送传感器数据static unsigned long lastSend = 0;if (millis() - lastSend > 5000) {sendSensorData();lastSend = millis();}
}void processCommand(String command) {// 处理各种控制命令
}void sendSensorData() {// 读取并发送传感器数据
}
五、调试与测试建议
1. 使用 nRF Connect 应用测试
- 扫描确认设备可见性
- 连接后查看服务特征结构
- 测试读写操作
- 订阅通知观察实时数据
2. 串口调试输出
Serial.println("BLE connected!"); // 连接事件
Serial.print("Received: "); // 数据接收
Serial.println(receivedData);
Serial.print("Sending: "); // 数据发送
Serial.println(sensorData);
3. 分阶段测试
- 先测试BLE基础通信
- 再测试传感器数据读取
- 然后测试执行器控制
- 最后集成完整功能
这个完整的指南应该能帮助你在成功实现BLE通信功能。