扫码加入

  • 正文
  • 相关推荐
申请入驻 产业图谱

STM32WB 基于 Custom Template 实现 BLE 私有协议 实操开发指南

03/31 17:43
465
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

物联网智能硬件嵌入式应用中,BLE(蓝牙低功耗)通信因低功耗、低成本的优势被广泛应用。STM32WB 系列双核 MCU(支持 BLE5.x)是开发 BLE 应用的优选方案,但多数开发者面临 “标准例程无法满足非标需求” 的痛点 —— 传统 BLE 例程仅支持固定 GAP 服务,难以自定义 ATT 属性和服务,而实际开发中使用 BLE 私有协议的非标产品占比极高。

ST 官方 LAT1197 应用笔记提供了高效解决方案:借助 STM32CubeMX 的 Custom Template(自定义模板),无需深入理解 BLE 底层协议,即可快速搭建支持 “读 / 写、只写、只读、通知” 四种核心数据访问的通用通信框架,适配绝大多数私有协议场景。本文基于该笔记,以 STM32WB55-Nucleo 开发板为例,从工程搭建、协议配置、代码开发到测试验证,全程拆解实操流程,让开发者快速上手并直接应用于产品。

资料获取:【应用笔记】LAT1197 STM32WB基于Custom Template实现客户定制BLE私有协议

1. 核心开发框架与前期准备

1.1 通信框架设计

本方案构建 “手机 APP-STM32WB” 的 BLE 私有协议通信链路,核心包含 4 种数据访问类型,覆盖绝大多数场景:

  • 读 / 写:手机可读写 STM32WB 的目标数据缓冲区(User_Write_Read_Data [64]);
  • 只写:手机仅能向缓冲区写入数据(User_Write_Data [64]),STM32WB 不返回数据;
  • 只读:手机仅能读取缓冲区数据(User_Read_Data [64]),无法写入;
  • 通知:STM32WB 主动向手机推送数据(User_Notify_Data [64]),无需手机请求。

1.2 前期准备

  • 硬件:STM32WB55-Nucleo 开发板、ST-LINK 调试器、安卓手机(安装 “BLE 调试助手”);
  • 软件:最新版 STM32CubeMX、STM32CubeWB 固件包(建议 V1.13.3 及以上)、Keil MDK(或 IAR)、STM32CubeProgrammer(用于 BLE 协议栈升级)。

2. STM32CubeMX 工程搭建与外设配置

工程搭建核心分 “基础外设配置” 和 “BLE 协议栈配置” 两步,所有操作均为图形化配置,无需手动修改寄存器,步骤可复现。

步骤 1:新建工程与基础外设配置

  1. 打开 STM32CubeMX,点击 “File→New Project”,输入 “STM32WB55RG” 创建工程,配置工程名称、保存路径,选择编译工具(如 Keil MDK),调整堆栈大小(建议栈 1024、堆 2048);
  2. 系统配置:启用调试口(默认 SWD 模式),确保调试正常;
  3. 晶振配置:添加外部高速晶振(HSE)和低速晶振(LSE),HSE 用于系统时钟,LSE 为 RTC 提供时钟源;
  4. 串口配置:将 USART1 引脚重映射到 PB6(TX)/PB7(RX),使能 USART1 的 TX DMA 功能(DMA1 Channel)和全局中断,用于调试信息打印;
  5. BLE 相关外设使能(均由 BLE 栈自动管理,无需额外配置):
    • HSEM:使能 3 个激活通道,用于双核间资源同步;
    • RF:使能外部 PA 传输控制,激活 RF1 引脚,保障 BLE 射频通信;
    • IPCC:使能 RX/TX 中断,用于 MCU 双核(Cortex-M4/Cortex-M0+)间通信;
    • RTC:选择 “Internal WakeUp” 和唤醒中断,用于低功耗场景下的定时唤醒;
  6. 时钟配置:配置系统时钟为 64MHz(或 100MHz,根据实际需求),确保 BLE 通信稳定性;
  7. NVIC 配置:合理分配各中断的抢占优先级,IPCC、USART1 等核心中断优先级建议设为 0-2 级,避免中断冲突。

步骤 2:BLE 协议栈核心配置

这是私有协议开发的关键,通过 CubeMX 图形化界面完成 GATT 服务、特征属性、广播参数等配置:

  1. 使能 BLE 协议栈:在 “Connectivity→BLE” 中勾选 “BLE”,启用协议栈;
  2. 选择 Custom Template:禁用默认的 “Custom P2P Server”,勾选 “Custom Template”(自定义 GATT 通用模板);
  3. 新建 GATT 服务:点击 “Add” 创建 GATT 服务,名称设为 “My_Data_Server”,UUID 类型选择 128bits(私有协议常用);
  4. 配置 4 种特征属性(核心步骤):
    • 读 / 写特征:名称设为 “User_Write_Read_Data”,UUID 自定义(如 0000fe41-...),属性勾选 “READ、WRITE NO RESPONSE”,数据长度设为 64 字节;
    • 只写特征:名称设为 “User_Write_Data”,属性仅勾选 “WRITE NO RESPONSE”,数据长度 64 字节;
    • 只读特征:名称设为 “User_Read_Data”,属性仅勾选 “READ”,数据长度 64 字节;
    • 通知特征:名称设为 “User_Notify_Data”,属性勾选 “NOTIFY”,数据长度 64 字节;
  5. 广播参数配置:
    • Advertising Type:选择 “Undirected scannable and connectable”(可扫描、可连接);
    • 设备名称:CFG_GAP_DEVICE_NAME 设为 “MY_STM32WB”,便于手机搜索识别;
    • 广播元素:勾选 “AD_TYPE_COMPLETE_LOCAL_NAME”(广播完整设备名)、“AD_TYPE_TX_POWER_LEVEL”(广播发射功率);
  6. 配对参数配置:默认配置即可(如加密密钥长度 16 字节),若需安全通信可调整配对模式和密钥;
  7. 调试打印配置:启用 BLE 协议栈调试,关联 USART1 作为打印端口,便于查看协议栈运行状态。

3. 工程代码生成与关键修改

点击 CubeMX 的 “GENERATE CODE” 生成工程代码后,需进行 3 处关键修改,确保调试和 BLE 协议栈正常运行:

  1. 取消 USART1 初始化的 static 属性:打开 “main.c”,找到 “MX_USART1_UART_Init (void)”,删除前面的 “static” 关键字,使其可被外部文件调用;
  2. 添加 Debug 初始化代码:打开 “app_entry.c”,在 “MX_APPE_Init (void)” 函数中添加 “APPD_Init ();”,初始化调试打印模块;
  3. 测试基础配置:将代码下载到开发板,打开串口助手(波特率 115200、8N1),若打印 “Hello STM32WB55”“Wireless Firmware version x.x.x”,说明 BLE 协议栈和调试功能正常;此时手机蓝牙可搜索到 “MY_STM32WB” 设备,基础配置验证通过。

4. BLE 应用代码开发:事件驱动 + 数据交互

核心代码开发集中在 “custom_stm.c” 和 “custom_app.c”,分别负责 “BLE 栈层事件驱动” 和 “应用层数据处理”,逻辑清晰,无需修改其他自动生成文件。

4.1 定义用户数据缓存区

打开 “custom_app.c”,在 “/* USER CODE BEGIN PV */” 区域定义 4 个 64 字节数据缓冲区,对应 4 种访问类型:

#define USER_MAX_BUF_SIZE (64)
uint8_t User_Write_Read_Data[USER_MAX_BUF_SIZE];  // 读/写缓冲区
uint8_t User_Write_Data[USER_MAX_BUF_SIZE];       // 只写缓冲区
uint8_t User_Read_Data[USER_MAX_BUF_SIZE];        // 只读缓冲区
uint8_t User_Notify_Data[USER_MAX_BUF_SIZE];      // 通知缓冲区

4.2 栈层事件驱动代码(custom_stm.c)

在 “Custom_STM_Event_Handler (void *Event)” 函数中添加事件驱动代码,实现 “栈层数据→应用层” 的传递,4 种特征仅需配置前 3 种(通知特征由 CubeMX 自动生成驱动):

(1)读 / 写特征(User_Write_Read_Data)事件驱动

// 写请求事件
else if(attribute_modified->Attr_Handle == (CustomContext.CustomWrite_Read_Data_BufHdle + CHARACTERISTIC_VALUE_ATTRIBUTE_OFFSET)) {
    return_value = SVCCTL_EvtAckFlowEnable;
    // 通知应用层:收到写请求
    Notification.Custom_Evt_Opcode = CUSTOM_STM_WRITE_READ_DATA_BUF_WRITE_NO_RESP_EVT;
    Notification.DataTransfered.Length = attribute_modified->Attr_Data_Length;
    Notification.DataTransfered.pPayload = attribute_modified->Attr_Data;
    Custom_STM_App_Notification(&Notification);
}

// 读请求事件
case ACI_GATT_READ_PERMIT_REQ_VSEVT_CODE:
    read_req = (aci_gatt_read_permit_req_event_rp0*)blecore_evt->data;
    if(read_req->Attribute_Handle == (CustomContext.CustomWrite_Read_Data_BufHdle + CHARACTERISTIC_VALUE_ATTRIBUTE_OFFSET)) {
        return_value = SVCCTL_EvtAckFlowEnable;
        // 通知应用层:收到读请求
        Notification.Custom_Evt_Opcode = CUSTOM_STM_WRITE_READ_DATA_BUF_READ_EVT;
        Custom_STM_App_Notification(&Notification);
        aci_gatt_allow_read(read_req->Connection_Handle);  // 允许读操作
    }

(2)只写特征(User_Write_Data)事件驱动

else if(attribute_modified->Attr_Handle == (CustomContext.CustomWrite_Data_BufHdle + CHARACTERISTIC_VALUE_ATTRIBUTE_OFFSET)) {
    return_value = SVCCTL_EvtAckFlowEnable;
    // 通知应用层:收到只写请求
    Notification.Custom_Evt_Opcode = CUSTOM_STM_WRITE_DATA_BUF_WRITE_NO_RESP_EVT;
    Notification.DataTransfered.Length = attribute_modified->Attr_Data_Length;
    Notification.DataTransfered.pPayload = attribute_modified->Attr_Data;
    Custom_STM_App_Notification(&Notification);
}

(3)只读特征(User_Read_Data)事件驱动

else if(read_req->Attribute_Handle == (CustomContext.CustomRead_Data_BufHdle + CHARACTERISTIC_VALUE_ATTRIBUTE_OFFSET)) {
    return_value = SVCCTL_EvtAckFlowEnable;
    // 通知应用层:收到只读请求
    Notification.Custom_Evt_Opcode = CUSTOM_STM_READ_DATA_BUF_READ_EVT;
    Custom_STM_App_Notification(&Notification);
    aci_gatt_allow_read(read_req->Connection_Handle);  // 允许读操作
}

4.3 应用层数据处理代码(custom_app.c)

在 “Custom_STM_App_Notification (Custom_STM_App_Notification_evt_t *pNotification)” 函数中,处理应用层数据交互逻辑,实现 “手机 - STM32WB” 的数据读写与通知:

switch(pNotification->Custom_Evt_Opcode) {
    // 读/写特征-读请求:返回指定数据
    case CUSTOM_STM_WRITE_READ_DATA_BUF_READ_EVT:
        strcpy((char*)User_Write_Read_Data, "User_Write_Read_Data[]--STM32WB");
        Custom_STM_App_Update_Char(CUSTOM_STM_WRITE_READ_DATA_BUF, (uint8_t*)&User_Write_Read_Data[0]);
        APP_DBG_MSG("** 手机读取读/写缓冲区数据...\n");
        break;
    
    // 读/写特征-写请求:接收手机数据
    case CUSTOM_STM_WRITE_READ_DATA_BUF_WRITE_NO_RESP_EVT:
        memset(User_Write_Read_Data, 0, sizeof(User_Write_Read_Data));
        memcpy(User_Write_Read_Data, pNotification->DataTransfered.pPayload, pNotification->DataTransfered.Length);
        APP_DBG_MSG("** 手机写入数据到读/写缓冲区,长度=%d:%s\n", pNotification->DataTransfered.Length, User_Write_Read_Data);
        break;
    
    // 只写特征-写请求:接收手机数据
    case CUSTOM_STM_WRITE_DATA_BUF_WRITE_NO_RESP_EVT:
        memcpy(User_Write_Data, pNotification->DataTransfered.pPayload, pNotification->DataTransfered.Length);
        APP_DBG_MSG("** 手机写入数据到只写缓冲区,长度=%d:%s\n", pNotification->DataTransfered.Length, User_Write_Data);
        break;
    
    // 只读特征-读请求:返回指定数据
    case CUSTOM_STM_READ_DATA_BUF_READ_EVT:
        strcpy((char*)User_Read_Data, "User_Read_Data[]--hello STM32WB");
        Custom_STM_App_Update_Char(CUSTOM_STM_READ_DATA_BUF, (uint8_t*)&User_Read_Data[0]);
        APP_DBG_MSG("** 手机读取只读缓冲区数据,长度=%d\n", strlen((char*)User_Read_Data));
        break;
    
    // 通知特征-使能:推送初始数据
    case CUSTOM_STM_NOTIFY_DATA_BUF_NOTIFY_ENABLED_EVT:
        strcpy((char*)User_Notify_Data, "User_Notify_Data[]--hello STM32WB");
        Custom_STM_App_Update_Char(CUSTOM_STM_NOTIFY_DATA_BUF, (uint8_t*)&User_Notify_Data[0]);
        APP_DBG_MSG("** 通知功能使能,推送初始数据,长度=%d\n", strlen((char*)User_Notify_Data));
        break;
    
    // 通知特征-禁用
    case CUSTOM_STM_NOTIFY_DATA_BUF_NOTIFY_DISABLED_EVT:
        APP_DBG_MSG("** 通知功能禁用\n");
        Custom_App_Context.Notify_data_buf_Notification_Status = 0;
        break;
    
    default:
        break;
}

4.4 扩展:修改 BLE 最大数据包长度

默认情况下,BLE 单包传输长度仅 23 字节,需修改配置支持最大 512 字节,适配大数据传输

  1. 打开 “app_conf.h”,修改CFG_BLE_MAX_ATT_MTU为 512:
    #define CFG_BLE_MAX_ATT_MTU (512)
    
  2. 打开 “app_ble.c”,在SVCCTL_App_Notification(void *pckt)函数的HCI_LE_CONNECTION_COMPLETE_SUBEVT_CODEcase 中,添加 MTU 和数据长度配置:
    aci_gatt_exchange_config(BleApplicationContext.BleApplicationContext_legacy.connectionHandle);
    hci_le_set_data_length(handleNotification.ConnectionHandle, 251, 265*8);
    

5. BLE 协议栈升级:关键前置步骤

STM32WB 的 BLE 协议栈需单独安装 / 升级,否则无法正常运行,需通过 STM32CubeProgrammer 操作:

  1. 升级 ST-LINK 固件:确保 ST-LINK 与 STM32CubeProgrammer 驱动匹配;
  2. 升级 FUS(固件升级服务):
    • 连接开发板,打开 STM32CubeProgrammer,选择 ST-LINK 连接;
    • 读取当前 FUS 版本:若为 0.5.3,选择固件 “stm32wb5x_FUS_fw_for_fus_0_5_3.bin”;否则选择 “stm32wb5x_FUS_fw.bin”;
    • 选择对应 MCU 型号的下载地址(如 STM32WB55RG 为 0x080EC000),点击 “Start Programming” 完成升级;
  3. 安装 BLE 协议栈:
    • 选择 BLE 协议栈固件(如完整功能栈 “stm32wb5x_BLE_Stack_full_extended_fw.bin”);
    • 选择对应 MCU 的下载地址(STM32WB55RG 为 0x080D0000),点击 “Start Programming”,完成后勾选 “Start stack after upgrade”。

6. 测试验证:手机 APP 与 STM32WB 通信

使用安卓手机的 “BLE 调试助手” 验证 4 种数据访问功能,步骤如下:

  1. 打开 “BLE 调试助手”,下滑扫描 BLE 设备,找到 “MY_STM32WB”,点击 “CONNECT” 连接;
  2. 修改 MTU:在 APP 中找到 “修改 MTU” 选项,设置为 256 字节(避免分包传输);
  3. 功能测试:
    • 读 / 写测试:找到 “READ WRITE NO RESPONSE” 特征,点击 “写入” 输入数据(如 “test123”),串口助手打印接收信息;再点击 “读取”,APP 接收返回数据 “User_Write_Read_Data []--STM32WB”;
    • 只写测试:找到 “WRITE NO RESPONSE” 特征,写入数据,串口助手打印接收信息,APP 无返回;
    • 只读测试:找到 “READ” 特征,点击 “读取”,APP 接收 “User_Read_Data []--hello STM32WB”;
    • 通知测试:找到 “NOTIFY” 特征,点击 “启用通知”,APP 接收初始推送数据 “User_Notify_Data []--hello STM32WB”,串口助手打印通知使能信息。

7. 开发总结与灵活拓展

7.1 核心优势

本方案基于 STM32CubeMX 的 Custom Template,无需深入理解 BLE 底层 ATT/GATT 协议,即可快速搭建通用私有协议框架,具有三大核心优势:

  • 高效开发:图形化配置 + 极简代码,新手也能快速上手;
  • 通用性强:4 种数据访问类型覆盖绝大多数场景,可直接迁移到不同产品;
  • 稳定可靠:基于 ST 官方协议栈和模板,兼容性和稳定性有保障。

7.2 灵活拓展场景

  • 增加更多特征:在 CubeMX 中新增 GATT 特征,重复 “事件驱动 + 应用处理” 代码,即可实现多特征多数据通道;
  • 自定义数据格式:修改缓冲区数据的解析逻辑,适配 JSON、二进制等私有协议格式;
  • 加密通信:在 CubeMX 中配置 BLE 配对加密参数(如 AES-128),保障数据传输安全;
  • 低功耗优化:结合 RTC 唤醒和 BLE 休眠配置,降低设备功耗,适配电池供电场景。

7.3 注意事项

  • 协议栈版本:确保 STM32CubeWB 固件包与 BLE 协议栈版本匹配,避免兼容性问题;
  • 中断优先级:IPCC、BLE 相关中断优先级需高于普通外设,避免中断阻塞导致数据丢失;
  • 缓冲区大小:根据实际需求调整USER_MAX_BUF_SIZE,避免内存浪费或数据溢出。

STM32WB 的 Custom Template 为 BLE 私有协议开发提供了 “降门槛、提效率” 的最优解,借助 STM32Cube 生态的图形化配置和完善固件包,开发者可聚焦应用逻辑,无需纠结底层协议细节,快速实现产品落地。无论是智能穿戴、智能家居还是工业传感器,该框架都能提供稳定可靠的 BLE 通信支撑。

相关推荐