STM32 BLE:自定义GATT服务与Web Bluetooth API集成指南
235
0
0
0
在物联网(IoT)和嵌入式系统领域,低功耗蓝牙(BLE)技术扮演着越来越重要的角色。结合Web Bluetooth API,我们可以直接从Web应用与BLE设备进行通信,无需中间应用或驱动程序。本文将深入探讨如何在STM32微控制器上设计和实现一个符合GATT规范的自定义BLE服务,并通过Web Bluetooth API实现Web应用对该服务的轻松访问。
1. BLE和GATT基础
在深入STM32实现之前,让我们回顾一下BLE和GATT的核心概念:
- BLE(Bluetooth Low Energy): 一种低功耗的无线通信技术,广泛应用于各种IoT设备。
- GATT(Generic Attribute Profile): 定义了BLE设备如何通过服务(Services)和特征(Characteristics)暴露数据。每个服务包含多个特征,每个特征包含一个值和一些属性。
- 服务(Service): 一组特征的集合,用于实现特定的功能或提供特定的数据。
- 特征(Characteristic): 包含一个值和一些属性,例如读、写、通知等。Web Bluetooth API允许Web应用读取特征的值或写入新的值。
- UUID(Universally Unique Identifier): 用于唯一标识服务和特征。为了避免冲突,建议为自定义服务和特征生成唯一的UUID。
2. STM32 BLE开发环境搭建
要开始在STM32上进行BLE开发,你需要以下工具和环境:
- STM32开发板: 推荐使用带有BLE功能的STM32 Nucleo或Discovery板,例如STM32WB系列。
- STM32CubeIDE: ST官方提供的集成开发环境,用于编写、编译和调试STM32代码。
- BLE协议栈: ST提供BLE协议栈,例如STM32WB系列使用的STM32WB5x RF协议栈。你需要下载并将其集成到你的项目中。
- J-Link调试器: 用于将代码下载到STM32开发板并进行调试。
3. STM32 BLE自定义GATT服务设计
假设我们要创建一个自定义BLE服务,用于控制LED的亮度。该服务包含一个特征,用于读取和写入LED亮度值(0-100)。
- 服务UUID:
12345678-1234-5678-1234-56789ABCDEF0(示例) - 特征UUID:
87654321-4321-8765-4321-0FEDCBA98765(示例) - 特征属性: 读、写、通知
4. STM32 BLE代码实现
以下代码片段展示了如何在STM32上创建一个自定义GATT服务和特征。这里使用了STM32WB5x RF协议栈的API。
#include "stm32wb5x_hal.h"
#include "ble_nus.h" // 假设你使用 Nordic UART Service 作为参考
#include "ble_advdata.h" // 用于广播数据设置
#include "gatt_db.h" // GATT 数据库定义
#include <stdio.h>
#define LED_BRIGHTNESS_SERVICE_UUID 0x1234
#define LED_BRIGHTNESS_CHAR_UUID 0x5678
static uint8_t led_brightness = 50; // 初始亮度值
// 定义服务 UUID 和特征 UUID
static const ble_uuid_t led_brightness_service_uuid = {
.uuid_type = BLE_UUID_TYPE_VENDOR_BEGIN,
.uuid = LED_BRIGHTNESS_SERVICE_UUID
};
static const ble_uuid_t led_brightness_char_uuid = {
.uuid_type = BLE_UUID_TYPE_VENDOR_BEGIN,
.uuid = LED_BRIGHTNESS_CHAR_UUID
};
// 定义 GATT 服务和特征的属性
GATT_Attribute led_brightness_service_attribute = {
{ATT_UUID_LENGTH, (uint8_t*)PrimaryServiceUUID},
GATT_PERMIT_READ, 0, (uint8_t*)&led_brightness_service_uuid
};
GATT_Attribute led_brightness_char_declaration = {
{ATT_UUID_LENGTH, (uint8_t*)CharacterUUID},
GATT_PERMIT_READ, 0, (uint8_t*)CharPropReadWrite
};
GATT_Attribute led_brightness_char_value = {
{ATT_UUID_LENGTH, (uint8_t*)&led_brightness_char_uuid},
GATT_PERMIT_READ | GATT_PERMIT_WRITE,
0,
(uint8_t*)&led_brightness
};
void update_led_brightness(uint8_t new_brightness) {
led_brightness = new_brightness;
printf("LED Brightness updated: %d\n", led_brightness);
// 在这里添加控制 LED 亮度的代码
// 例如:HAL_GPIO_WritePin(LED_GPIO_Port, LED_GPIO_Pin, (new_brightness > 50) ? GPIO_PIN_SET : GPIO_PIN_RESET);
// 如果使用 PWM 控制亮度,则需要配置 PWM 输出
}
void attribute_modified_callback(uint16_t connection_handle, GATT_Attribute* attribute) {
if (attribute == &led_brightness_char_value) {
// 亮度值被写入
update_led_brightness(*(uint8_t*)attribute->pValue);
}
}
void init_ble() {
// 初始化 BLE 协议栈
// ...
// 添加自定义服务到 GATT 数据库
aci_gatt_add_service(UUID_TYPE_128, (uint8_t*)&led_brightness_service_uuid, 6, &led_brightness_service_handle);
// 添加特征到 GATT 数据库
aci_gatt_add_char(led_brightness_service_handle, UUID_TYPE_128, (uint8_t*)&led_brightness_char_uuid, 8, CHAR_PROP_READ | CHAR_PROP_WRITE, ATTR_PERMISSION_NONE, GATT_MAX_MTU_SIZE, 0, &led_brightness_char_handle);
// 设置广播数据
// ...
}
int main(void) {
HAL_Init();
// 初始化 LED GPIO
// ...
init_ble();
while (1) {
// 处理 BLE 事件
// ...
}
}
代码解释:
- 定义UUID: 为自定义服务和特征定义唯一的UUID。
- 定义GATT属性: 定义 GATT 服务和特征的属性,包括读写权限。
- 初始化BLE协议栈: 初始化BLE协议栈,包括设置广播数据、连接参数等。
- 添加服务和特征: 使用
aci_gatt_add_service和aci_gatt_add_char函数将自定义服务和特征添加到GATT数据库中。 - 处理特征写入事件: 当Web应用写入LED亮度值时,
attribute_modified_callback函数会被调用。在该函数中,我们可以更新LED的亮度。 - 广播数据设置: 配置广播数据,包含设备名称和服务UUID,以便Web应用能够发现该设备。
注意: 这只是一个代码片段,你需要根据你的具体硬件和BLE协议栈进行修改和完善。
5. Web Bluetooth API使用
现在,让我们看看如何使用Web Bluetooth API从Web应用与STM32 BLE设备进行通信。
// 搜索BLE设备
navigator.bluetooth.requestDevice({
filters: [
{
services: ['12345678-1234-5678-1234-56789abcdef0'] // 你的服务UUID
}
]
})
.then(device => {
console.log('Device found:', device.name);
return device.gatt.connect();
})
.then(server => {
console.log('Connected to GATT server');
return server.getPrimaryService('12345678-1234-5678-1234-56789abcdef0'); // 你的服务UUID
})
.then(service => {
console.log('Found service');
return service.getCharacteristic('87654321-4321-8765-4321-0fedcba98765'); // 你的特征UUID
})
.then(characteristic => {
console.log('Found characteristic');
// 读取特征值
characteristic.readValue()
.then(value => {
let brightness = value.getUint8(0);
console.log('Initial brightness:', brightness);
});
// 监听特征值变化
characteristic.startNotifications();
characteristic.addEventListener('characteristicvaluechanged', event => {
let brightness = event.target.value.getUint8(0);
console.log('Brightness changed to:', brightness);
});
// 写入新的特征值
let newBrightness = 80;
let buffer = new Uint8Array([newBrightness]);
return characteristic.writeValue(buffer);
})
.then(() => {
console.log('Brightness updated to 80');
})
.catch(error => {
console.error('Error:', error);
});
代码解释:
- 搜索设备: 使用
navigator.bluetooth.requestDevice函数搜索具有指定服务UUID的BLE设备。 - 连接GATT服务器: 连接到设备的GATT服务器。
- 获取服务和特征: 使用
server.getPrimaryService和service.getCharacteristic函数获取自定义服务和特征。 - 读取特征值: 使用
characteristic.readValue函数读取LED亮度值。 - 监听特征值变化: 使用
characteristic.startNotifications函数监听LED亮度值的变化。当STM32上的亮度值发生变化时,Web应用会收到通知。 - 写入特征值: 使用
characteristic.writeValue函数写入新的LED亮度值。
6. 常见问题和解决方案
- 设备无法被Web应用发现: 确保STM32 BLE设备正在广播,并且广播数据包含正确的服务UUID。检查Web应用的权限设置,确保允许访问蓝牙设备。
- 连接失败: 检查STM32 BLE设备的连接参数设置,确保与Web Bluetooth API兼容。尝试调整连接间隔和超时时间。
- 数据传输错误: 检查GATT特征的属性设置,确保读写权限正确。检查数据格式和长度是否与STM32 BLE设备和Web应用一致。
7. 安全注意事项
- 配对和绑定: 对于需要安全保护的应用,建议使用BLE的配对和绑定功能。配对可以建立一个加密连接,防止未经授权的访问。绑定可以将设备信息存储在本地,以便下次连接时无需重新配对。
- 数据加密: 对于敏感数据,建议在BLE连接上进行加密。可以使用BLE提供的加密功能,也可以使用应用层加密。
- 权限控制: 在Web应用中,应该对用户进行身份验证和授权,以防止未经授权的用户访问BLE设备。
8. 总结
本文详细介绍了如何在STM32微控制器上设计和实现一个符合GATT规范的自定义BLE服务,并通过Web Bluetooth API实现Web应用对该服务的轻松访问。通过本文的指导,你可以快速搭建起基于Web Bluetooth的STM32应用,并将其应用于各种IoT和嵌入式系统项目中。记住,安全永远是第一位的,所以在设计和实现BLE应用时,一定要充分考虑安全因素。