本帖最后由 御坂10032号 于 2024-6-10 01:38 编辑
在这篇帖子中,我将详细讲解一个基于nRF52芯片的蓝牙低功耗(BLE)UART示例程序。该程序使用Adafruit的Bluefruit库来实现BLE功能,并包括了几个关键的BLE服务。我们将逐步解析代码,了解其每个部分的功能。此外,我们还将简要介绍蓝牙协议的基本概念。
蓝牙概述
蓝牙是一种短距离无线通信技术,广泛应用于各种设备之间的数据传输。蓝牙标准由蓝牙技术联盟(Bluetooth Special Interest Group,SIG)制定和维护。蓝牙技术主要有两种模式:
- 经典蓝牙(BR/EDR):适用于高数据传输速率和音频传输的应用,如无线耳机和音箱。
- 蓝牙低功耗(BLE):针对低功耗和间歇性数据传输的应用,如智能手表、健康监测设备和IoT设备。
蓝牙低功耗(BLE)
BLE是蓝牙4.0引入的技术,专门设计用于低功耗应用。其特点包括:
- 低功耗:适用于电池供电设备。
- 快速连接:可以快速建立和断开连接,节省能量。
- 灵活的数据传输:支持小数据包的高效传输。
BLE设备主要分为两类:
- 外围设备(Peripheral):广播其存在,并等待中心设备连接。
- 中心设备(Central):扫描外围设备并发起连接。
蓝牙协议稍微复杂,不过好在Sparkfun 提供的Arduino支持中包括了对蓝牙的支持。同时还有大量的蓝牙demo供我们学习。这些Arduino蓝牙的适配大大的降低了使用这一块MCU开发项目时的困难程度。
我们可以在下述位置找到示例代码
#include <bluefruit.h>
我们首先引入了Bluefruit库,它提供了对蓝牙功能的支持,使我们能够轻松地构建BLE应用。
// BLE Service
BLEDfu bledfu; // OTA DFU service
BLEDis bledis; // device information
BLEUart bleuart; // uart over ble
BLEBas blebas; // battery
之后,我们初始化了几个BLE服务对象,包括(OTA的服务暂时还没发现怎么用):
- BLEDfu:支持空中下载(OTA)的DFU服务。
- BLEDis:设备信息服务。
- BLEUart:通过BLE实现的UART服务。
- BLEBas:电池服务,用于监控电池状态。
void startAdv(void)
{
// 设置广播数据包
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
// Include bleuart 128-bit uuid 设置蓝牙广播的唯一标识
Bluefruit.Advertising.addService(bleuart);
// Secondary Scan Response packet (optional)
Bluefruit.ScanResponse.addName();
/* Start Advertising 开始广播
* - Enable auto advertising if disconnected
* - Interval: fast mode = 20 ms, slow mode = 152.5 ms
* - Timeout for fast mode is 30 seconds
* - Start(timeout) with timeout = 0 will advertise forever (until connected)
*/
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
}
startAdv函数负责设置并启动蓝牙广播:
-
设置广告包:
- 添加标志信息,指示设备为普通可连接模式。
- 添加发射功率信息。
- 添加BLE UART服务的UUID。
-
设置扫描响应包:
-
启动广告:
- 配置在断开连接时自动重新开始广播。
- 设置广播间隔和超时时间。
- 开始广播,参数为0表示广播将持续进行直到设备连接 (如果持续没有设备连接的话,开发板上的LED灯将持续闪烁)。
void connect_callback(uint16_t conn_handle)
{
// 获取当前连接的引用
BLEConnection* connection = Bluefruit.Connection(conn_handle);
char central_name[32] = { 0 };
connection->getPeerName(central_name, sizeof(central_name));
Serial.print("Connected to ");
Serial.println(central_name);
}
/**
* 连接断开时调用的回调函数
* @param conn_handle 连接句柄
* @param reason 断开原因
*/
void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
(void) conn_handle;
(void) reason;
Serial.println();
Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX);
}
这些回调函数在设备连接和断开连接时被调用:
-
连接回调函数:
-
断开连接回调函数:
void loop()
{
// Forward data from HW Serial to BLEUART
while (Serial.available())
{
// 延迟以等待足够的输入,因为我们有一个有限的传输缓冲区
delay(2);
uint8_t buf[64];
int count = Serial.readBytes(buf, sizeof(buf));
bleuart.write(buf, count);
}
// 从BLEUART转发到HW Serial
while (bleuart.available())
{
uint8_t ch;
ch = (uint8_t) bleuart.read();
Serial.write(ch);
}
}
loop函数实现了串口和BLE UART之间的数据转发:
-
从硬件串口转发数据到BLE UART:
- 如果串口有数据可读,读取数据到缓冲区,并通过BLE UART发送出去。
-
从BLE UART转发数据到硬件串口:
- 如果BLE UART有数据可读,读取一个字节并通过串口发送出去。
上述程序实现的基本功能是初始化串口,和蓝牙。并且开启蓝牙的广播功能。 当用户连接或者断开于当前蓝牙的连接的时候会触发上述的回调函数。当用户使用APP发送消息给Sparkfun开发板的时候。开发板将会以串口的方式发送给上位机。同时上位机也可以通过串口的方式通过蓝牙发送消息给APP(用户)
此时我们我们将代码编译并且下载到开发板中
设备未连接蓝牙的时候
cff9e3839450b2e9e8d9254eb0b07656
完整使用手机APP 发送和接收数据演示
6月10日