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); // 初始关闭LED
if (!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); // 设置初始值为0
BLE.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 5
DHT 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通信功能。