把蓝牙接口与应用协议逐层对上
最后把两种“协议”放在各自的位置:蓝牙库负责连接和特征访问,应用协议说明这些字节代表什么。用一份实际电量消息,从主控一直追踪到手机显示。
1 · 两层约定分别回答什么问题
| 层次 | 回答的问题 | 本项目约定 |
|---|---|---|
| 蓝牙访问接口 | 连谁、写哪里、从哪里收 | SmartWatch、FFE0、FFE2、FFE3、通知订阅 |
| 应用消息格式 | 字节的含义和边界是什么 | 0xAA 帧头、长度、命令、数据、校验 |
| 业务处理 | 收到有效消息后做什么 | 显示电量、更新设置、传输原型等 |
蓝牙服务不会因为某字节是 0xAA 就识别为电量。相反,即使消息校验规则完全一致,手机写错了特征,也到不了对应业务处理。调试时必须明确自己在检查哪一层。
2 · 从一条七字节电量帧开始
协议中的示例帧 · 所有字节为十六进制
AA 06 03 A0 0F 3C 62这里消息类型为 06,载荷长度为 03;数据中的 A0 0F 按低字节在前表示 0x0FA0,即 4000 毫伏,3C 表示 60。AA、06、03、A0、0F、3C 相加为 0x19E;取负数后保留低八位,得到校验 62。把校验也加进去,低八位应为零。精确格式以 协议规范 为准。
STM32 生成这组字节,从串口发出;CH 接收、排队、通知;App 解析以后才把它变成“4000 mV”。CH 桥接代码无需认识毫伏或电池百分比。
3 · 同一组字节可以分几次到达
假设手机两次收到 AA 06 03 和 A0 0F 3C 62。第一次只有帧的一部分,解析器应保存它;第二次补齐后再校验和输出消息。若下一条帧紧跟在后面,也应该继续从剩余字节解析。
这解释了为何本支线不在 CH 中按通知长度补帧头,也不因为串口出现接收超时就判断一帧结束。传输分块与业务分帧各自解决一个问题。主线已写过解析器,App 支线会把相同规则接到通知流。
4 · 三端逐项核对,避免只看最终界面
| 看到的现象 | 先检查什么 |
|---|---|
| 手机扫描不到 | CH 是否启动、广播和扫描响应 |
| 能连接但没有写入入口 | 服务发现结果、UUID、写属性 |
| 手机写后 STM32 收不到 | FFE2 回调、队列拒绝、UART1 配置和交叉接线 |
| STM32 发了但手机无通知 | 串口接收、事件处理、FFE3 订阅、连接状态 |
| 有通知但数值不对 | 字节流组帧、长度、校验、字段单位和端序 |
每次只推进一个观测点,例如先确认 STM32 接收字节正确,再处理命令响应。不要同时改 UUID、串口参数和消息格式,导致无法判断哪一步产生效果。
5 · 完成这一支线以后怎样继续
现在能够说明每个方向的函数调用、数据存储与接收条件。继续进入支线三,使用 Dart 与 Flutter 把服务发现、订阅、帧解析和界面状态连起来。AI 和个性化支线随后使用这条已有通道传业务内容。
参考 CH 模块说明、三端协议 与 App 蓝牙实现 做对照。生产代码本次不作改写。
完成一次双向联调记录:发了哪组字节、经过哪些函数、手机是否订阅、实际 MTU、是否收到应用响应。再检查低 MTU、队列积压与断开重连;没有设备时只记录源码核对结果,不写成真机通过。