目录
CH32 BLE 协议栈应用参考笔记
适用于 CH32 BLE MCU + WCH BLE/TMOS 协议栈的应用开发。 核心思路:Attribute Table → Handle → Callback → Value → 手机
1. BLE 软件层次
|
|
常用概念
| 概念 | 作用 |
|---|---|
| GAP | 广播、连接、角色、连接参数 |
| GATT | Service / Characteristic 的组织 |
| ATT | Attribute 的读写、发现、Notify |
| Service | 一组相关功能 |
| Characteristic | 真正承载业务数据 |
| UUID | 标识“这是什么” |
| Handle | 标识“操作哪个 Attribute” |
| Value | 实际数据 |
| CCCD | Notify/Indicate 的订阅配置 |
2. 最重要:Attribute Table
一个 Characteristic 通常至少有两个 Attribute:
|
|
例如:
|
|
3. gattAttribute_t 怎么看
|
|
理解成:
|
|
Handle 为什么初始化为 0?
|
|
只是表示:
当前还没有分配最终 ATT Handle。
Service 注册到协议栈后,由协议栈分配真正 Handle。
因此:
|
|
运行时才是实际可以用于 ATT 操作的 Handle。
4. UUID
16-bit UUID 例如:
|
|
定义数组:
|
|
结果:
|
|
原因:
BLE 使用 Little Endian 的字节顺序。
重新组合:
|
|
等价于:
|
|
5. UUID、Handle、Value 的关系
牢记:
|
|
例如:
|
|
6. 手机如何找到 Characteristic?
手机第一次连接后,会进行 GATT Discovery。
大致过程:
|
|
例如:
|
|
之后手机操作时主要使用:
|
|
而不是每次重新发送 UUID。
7. Write:手机 → MCU
手机:
|
|
本质上类似:
|
|
BLE Stack:
|
|
Write Callback 中:
|
|
例如:
|
|
数据流:
|
|
8. Write Callback 的核心判断
如果一个 Callback 负责多个 Characteristic:
|
|
这里:
|
|
来自本地 Attribute Table。
而:
|
|
来自手机发送的数据。
9. Read:MCU → 手机
手机:
|
|
本质:
|
|
BLE Stack 根据 Handle 找到:
|
|
然后调用 Read Callback。
本地数据:
|
|
通常:
|
|
Read Callback:
|
|
数据流:
|
|
注意三个东西
|
|
不要混淆。
10. 为什么 Read 不能直接给指针?
错误思路:
|
|
这是:
修改指针地址。
正确:
|
|
这是:
复制数据。
简单记:
|
|
11. Notify
Notify 与 Read 最大的区别:
|
|
例如 Battery:
|
|
以后:
|
|
MCU 可以主动:
|
|
不需要手机不断 Read。
12. CCCD
CCCD:
|
|
标准 UUID:
|
|
它不是 Battery 数据。
它是:
客户端对 Notify / Indicate 的配置。
例如:
|
|
13. GATTServApp_ProcessCCCWriteReq
这个函数可以理解为:
处理手机对 CCCD 的 Write 请求。
流程:
|
|
所以它解决的是:
“手机有没有订阅 Notify?”
而不是:
“手机发送了多少电量数据?”
14. GATTServApp_ReadCharCfg
|
|
作用:
查询当前连接是否开启了 Notify。
通常:
|
|
意思:
|
|
15. GATT_Notification
真正发送 Notify:
|
|
数据流:
|
|
16. Notify 完整流程
|
|
17. Service / Characteristic / Value 的关系
例如夜灯:
|
|
18. 广播
典型:
|
|
作用:
|
|
扫描响应:
|
|
作用:
|
|
19. GAP 与 GATT 初始化
典型流程:
|
|
理解:
|
|
20. Connection Parameter
例如:
|
|
BLE Connection Interval 单位:
|
|
因此:
|
|
这是:
期望的连接参数范围。
不是保证实际一定使用这个值。
21. Callback 的职责
常见:
|
|
负责:
|
|
|
|
负责:
|
|
|
|
负责:
|
|
|
|
负责:
|
|
它不是 Tick 主动调用,而是协议栈发生参数更新后回调。
22. TMOS Task
典型:
|
|
然后:
|
|
周期任务:
|
|
可以理解成:
|
|
BSP_Ble_ProcessEvent() 就是这个 Task 的事件分发器。
23. ISR 与 Stack
CH32 的 ISR 和普通函数共用 CPU Stack。
如果:
|
|
那么 ISR 中应该避免:
|
|
以及:
|
|
和过深的函数调用。
适合:
|
|
static 局部变量不占用运行时 Stack:
|
|
24. BLE 开发排错顺序
当手机无法控制设备时,按这个顺序查:
|
|
Notify 问题:
|
|
25. 一张图总结整个 BLE 数据流
|
|
26. 最终记忆口诀
|
|
BLE 应用开发最核心的不是记 API,而是搞清楚:
手机的 Handle → 协议栈找到本地 pAttr → Callback → 根据操作类型处理 pValue / pAttr->pValue。
27. CH32 BLE 应用开发代码骨架
27.1 文件结构
|
|
27.2 Service Header
|
|
27.3 UUID 定义
|
|
27.4 Characteristic Value
|
|
|
|
27.5 Characteristic Properties
|
|
27.6 CCCD
|
|
作用:
|
|
27.7 Attribute Table
|
|
27.8 Attribute Index
避免直接使用魔法数字:
|
|
27.9 Write Callback
|
|
核心:
|
|
27.10 Read Callback
|
|
注意:
|
|
27.11 Service Callback
|
|
具体结构体字段顺序以当前 SDK 定义为准。
27.12 注册 Service
|
|
注册后:
|
|
27.13 Battery Notify
|
|
流程:
|
|
27.14 TMOS Task
|
|
|
|
27.15 BLE 初始化
|
|
27.16 Main
|
|
27.17 三条核心数据流
Write
|
|
Read
|
|
Notify
|
|
27.18 开发时最重要的对应关系
|
|
注意:上述函数名、结构体字段、错误码和注册函数原型可能因 CH32/CH59x SDK 版本不同而略有差异;实际工程以当前 SDK 的头文件定义为准。