ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

BLE胎压监测产品通讯协议与低功耗流程方案实战

BLE胎压监测产品通讯协议与低功耗流程方案实战

1. 项目概述与方案选型

做胎压监测产品,最绕不开的一个环节就是通讯协议怎么定、数据流程怎么走。这直接决定了产品的功耗表现、连接稳定性、手机端体验,甚至决定了你能不能过认证。我这次要分享的就是一套完整的 BLE 胎压/压力产品通讯协议与流程方案 v1.0,这套方案是从实际量产项目中沉淀下来的,覆盖了从协议栈设计、GATT 服务定义、连接配对流程,到低功耗策略和异常处理的全链路内容。

先说清楚这套方案解决了什么问题。胎压监测器本质上是一个传感器节点,把气压、温度、电池电量这些数据通过 BLE 传给手机 APP 或者中控屏。它的痛点在于:电池很小(纽扣电池是常态),无线环境复杂(停车场、高速路、雨天),设备数量多(四轮加备胎可能五六个),而且用户对"装好就能用"的期望非常高。BLE 相比 2.4G 私有协议的优势在于手机直连,不需要额外网关;相比 LoRa、NB-IoT 又省掉了通信模组成本和功耗。这套方案就是围绕"低功耗、稳连接、易配对"这三个核心诉求设计的。

适合看这篇文章的人,主要是我这样的嵌入式软件工程师、BLE 协议栈开发人员,以及正在做 TPMS 或者类似压力采集产品的产品经理和技术负责人。内容偏实操,协议帧格式、服务定义、状态机这些都是可以直接拿去用的。如果你只是对 BLE 感兴趣但没做过相关产品,也能从里面了解一套完整的产品级 BLE 应用长什么样,而不只是跑通一个 Peripheral 例程。

1.1 核心需求拆解

一个完整的 BLE 胎压监测产品,功能上其实拆得挺细的。我列一下 v1.0 里必须覆盖的需求清单,因为协议设计是跟着需求走的,后期每加一个功能都可能牵动帧格式或服务定义。

  • 基础数据上报:每个传感器周期性地上报气压、温度、电量。上报周期默认 1 秒一次,但这不是固定的,后面会讲怎么动态调整。
  • 实时查询响应:手机发指令查询当前数据,传感器要能立刻回复,不能因为处于低功耗状态就慢半拍。
  • 报警事件主动推送:气压过高、过低、漏气速率异常、温度过高,这些事件要能做到"变化即上报",延迟越低越好。
  • 传感器绑定的读写存储:每个传感器有唯一 ID,需要绑定到具体轮位(左前、右前、左后、右后)。这个绑定关系要能写入传感器,也要能读出来。
  • 参数配置:报警阈值、胎压单位(kPa/PSI/Bar)、测量周期、唤醒灵敏度等,要支持手机下发配置。
  • 固件升级预留:协议层面要为 OTA 预留通道和服务特征值,即使 v1.0 不放量用,结构上也要留好。

1.2 为什么 BLE 是当前最优解

我在做需求调研阶段也纠结过:用 2.4G 私有协议成本更低,用经典蓝牙兼容性更好,为什么最终定了 BLE?三个理由比较有说服力。

第一是功耗。胎压传感器一个 CR2032 纽扣电池要用两三年,平均电流得控制在微安级别。BLE 的广播和连接间隔都是可配置的,传感器大部分时间可以睡死在最深度的睡眠里,只有测量和数据发送的瞬间醒来。2.4G 私有协议虽然也能做到低功耗,但手机没法直接读数据,用户必须带一个接收器,体验差一截。

第二是连接生态。现在手机 APP 对 BLE 的支持非常成熟,iOS 和安卓都有完整的 API,用户装个 APP 就能看胎压数据。如果走私有协议,还要专门做接收器硬件、写驱动,开发量翻倍。

第三是认证门槛。BLE 的认证流程已经很标准化,认证周期和费用都相对可控。这对产品上市节奏影响很大。

当然 BLE 也有它的短板,最典型的就是数据吞吐量小、连接建立有延迟,但这些对胎压产品来说完全不是问题——它本来就不是一个大数据量、高频交互的产品。方案选型的核心逻辑是匹配需求,不是堆参数。

2. 协议栈与网络拓扑设计

2.1 一主多从的连接拓扑

胎压系统的 BLE 网络拓扑,用一句话概括就是"一个手机 APP 面对多个传感器节点"。这里有个关键的架构决策:传感器之间不互联,每个传感器都是独立的 Peripheral,手机是唯一的 Central。

这个架构有几个好处。第一是传感器固件简单,不需要处理中继转发,出问题的概率低。第二是任何传感器的故障都只影响它自己,不会拖垮整个网络。第三是安装维护灵活,用户换一个传感器只需要重新绑定那一个,不用动其他三个。

代价也很明显:手机要同时维护多个连接。BLE 规范里 Central 同时连接的数量理论上没有硬限制,但实际芯片和系统都有约束,iOS 大概是 7 到 9 个,安卓看厂商和蓝牙协议栈实现,很多手机 4 个连接就开始不稳定了。四个轮位加一个备胎正好五个传感器,压力其实不小。

所以这套 v1.0 方案里做了一个取舍:默认手机同一时刻只和一个传感器保持连接,其他传感器通过"快广播 + 定向连接"的机制来上报数据。具体流程是——

  1. 手机在绑定界面和各传感器依次建立连接,完成绑定和参数配置。
  2. 日常监控模式下,传感器平时处于低功耗广播状态,携带最新的气压温度数据。
  3. 手机 APP 周期性扫描广播包,直接从广播数据里解析各轮位的数据,不需要逐一建立连接。
  4. 只有当传感器发出报警事件、或者用户主动要求查看详细信息时,才建立临时连接。

这个设计有点像门口的对讲机一直处于待机状态,你路过时它能直接喊一嗓子告诉你屋里什么情况,而不需要你推门进去问一遍。广播通道本身就能载荷数据,这是 BLE 非常有价值的能力,很多开发者容易忽略。

2.2 私有服务与特征值规划

GATT 服务定义是整个协议的地基。我用的是标准 16-bit UUID 之外的私有 128-bit UUID 来定义服务,避免和标准服务冲突,同时保留标准 Device Information Service 用于读取设备信息。

服务结构是这样的:

服务 / 特征UUID 后缀属性说明
TPMS ServiceFFF0-私有服务
当前数据特征FFF1Read / Notify包含气压、温度、电量、信号强度
控制特征FFF2Write / Write No Response手机下发查询、配置指令
事件特征FFF3Notify报警与异常事件主动上报
绑定信息特征FFF4Read / Write轮位绑定信息
Device Information Service180ARead厂商名、型号、序列号、固件版本

从属性的选择上能看出设计意图。当前数据特征用了 Read 加 Notify,Read 是为了让手机随时主动拉取,Notify 是传感器主动推送时用的。控制特征用了 Write No Response,因为胎压控制指令很短,不需要等链路层确认,能省掉一次交互延迟。事件特征只有 Notify,它是纯上行的,手机不需要写。绑定信息特征可读可写,因为绑定动作本身就是手机往传感器里写数据。

每个特征我都配了 CCCD(Client Characteristic Configuration Descriptor),这是 Notify 功能的前提。手机端订阅 Notify 时要先把 CCCD 写成 0x0001,这个细节在 iOS 上有 CoreBluetooth 自动处理,安卓上有些机型需要手动写入,Android 11 之后系统对 CCCD 的管理更严格,忘记处理就会收不到通知。

3. 数据帧格式与字段定义

3.1 通用帧结构

协议帧格式我采用了"同步头 + 长度 + 命令 + 载荷 + 校验"的结构,这是物联网协议里比较经典的做法。一个典型的控制指令帧长这样:

| Byte 0 | Byte 1 | Byte 2 | Byte 3 | Byte 4..N-2 | Byte N-1 | | 同步头 0xAA | 版本+标志 | 长度 | 命令字 | 载荷数据 | 校验和 |

同步头固定 0xAA,作用有两个:一是接收方在字节流里找帧起始位置,二是过滤掉空包和噪声数据。版本和标志位放在第二个字节,高 4 位是协议版本号,低 4 位里用到了方向标志位和应答标志位。长度字段表示的是从命令字开始到帧尾的字节数,不含同步头和长度自身。

校验这块,v1.0 用的不是 CRC16,而是简单的累加和校验。原因很直接:胎压指令帧最长不超过 64 字节,场景里也没有恶意攻击或恶劣电磁干扰,累加和已经能覆盖偶发错帧的情况,而且单片机实现起来省 ROM 省 CPU。如果你做的产品要过严格的认证或者有安防需求,可以升级成 CRC16,帧结构里已经预留了接口位置。

3.2 关键指令码表

整套协议里命令字是核心,我整理了 v1.0 的全部指令码,每个都做了编号规划,方便后期扩展。

命令字方向功能说明
0x01下行读取当前数据手机发起实时查询
0x02上行当前数据应答传感器返回气压/温度/电量
0x03上行定时上报数据传感器按周期主动上报
0x04下行写入轮位绑定绑定传感器到指定轮位
0x05上行绑定结果成功或失败状态码
0x06下行写入参数配置阈值、单位、上报周期
0x07上行参数配置确认回读配置项供手机校验
0x08上行报警事件触发事件类型和当前数据
0x09下行触发校零用于传感器零点校准
0x0A上行校零结果返回偏置值

每个指令的载荷字段都有明确的字节布局。拿 0x02 当前数据应答来举例:

偏移字段长度说明
0气压值2 字节有符号整数,单位 0.1 kPa,范围 -4000 ~ 4000
2温度值1 字节有符号整数,单位 ℃,范围 -40 ~ 125
3电量1 字节百分比 0 ~ 100%
4RSSI1 字节有符号整数,单位 dBm
5轮位1 字节0=左前 1=右前 2=左后 3=右后 4=备胎
6传感器状态1 字节bit0=运动检测 bit1=绑定状态 bit2=高压 bit3=低压

气压值用有符号整数是为了能表示胎压为负的场景——虽然正常情况下胎压不可能为负,但在传感器处于未安装、或者校零前的状态下,内部压力差可能显示为负值。单位 0.1 kPa 意味着 250 kPa 的标准胎压在数据里就是 2500,解析时除以 10 就行。PSI 单位在手机端换算,不在传感器端做,这能省掉传感器的浮点运算。

3.3 广播数据包规划

广播包是这套方案里特别重要的一个环节,因为它承担了"免连接状态下的日常数据快照"功能。广播包载荷中 Manufacturer Specific Data 字段是我自定义的:

| Company ID (2) | 设备类型 (1) | 版本 (1) | 轮位 (1) | 气压 (2) | 温度 (1) | 电量 (1) | 报警标志 (1) |

这里有个细节要重点说:BLE 广播包单个报文最大是 31 字节,我上面这个结构占了 12 字节,加上 Flags 和 Complete Local Name 等必带字段,总共在 28 字节以内,卡得刚刚好。设计广播包的时候一定要预留空间,因为很多手机系统会强制要求广播里带设备名称,iOS 有时还会附加自己的字段,超了 31 字节的广播包会被直接丢弃。

广播间隔我设置的是 300ms,这是功耗和时延之间的平衡点。如果广播间隔太短,比如 20ms,手机扫描端确实更快抓到设备,但传感器发射电流会连续拉高,电池撑不住。300ms 意味着手机端最多等 300ms 就能抓到一次广播,对于查看胎压这种低频场景完全够用。

广播模式上我用了非连接广播(不可连接)和可连接广播的切换。日常监控时用的是非连接广播,只往外丢数据,不允许手机连进来,这样功耗最低,也避免手机在后台频繁连接传感器。当用户主动在 APP 里点"连接设备"时,传感器通过命令切换到可连接广播模式,然后手机才能建立连接。这个机制用下来最稳,直接避免了安卓后台频繁扫描连接耗电的问题。

4. 核心流程设计

4.1 设备绑定流程

绑定流程是所有用户交互里最容易出问题的环节,设计时我把它拆成了六个步骤,每步都有超时和异常处理。

第一步是传感器进入绑定模式。用户长按传感器按键(或者用磁铁触发感应)让传感器进入可连接广播。第二步是手机扫描并识别设备,通过广播包里的设备类型字段过滤出胎压传感器,而不是把周围的蓝牙耳机、手环全部列出来。第三步是建立 GATT 连接,第四步是手机读取传感器序列号并回传轮位信息,第五步是传感器保存绑定关系并回发确认帧,第六步是手机验证绑定结果并断开连接。

这里最容易踩的坑是绑定过程中用户把手机锁屏了。锁屏以后很多安卓手机会在几秒内断开 BLE 连接,导致绑定写到一半失败。我们的处理是绑定过程中传感器有一个 60 秒的绑定窗口,超时自动退出,手机端在用户锁屏前会弹提醒,同时传感器端支持断点续绑——即使连接断了,只要传感器还处于绑定模式,重新连接后可以继续完成绑定。

绑定信息我存在传感器内部 Flash 的一个独立扇区,包含轮位号、绑定时的时间戳、手机端下发的标识序列。这样设计的好处是:用户换手机以后,不需要重新把传感器拆下来重新绑定,只要在新手机上输入配对标识,就能直接读取传感器里的绑定信息。

4.2 数据上报与动态周期策略

数据上报是本产品运行频率最高的流程,功耗优化主要靠的就是这部分。v1.0 采用了动态上报周期机制,传感器根据车辆的运动状态自动切换上报频率。

静止状态(传感器每 5 分钟检测一次加速度,未检测到持续运动)上报周期设为 30 秒。运动状态上报周期设为 1 秒。报警状态,不管静止还是运动,一旦触发立即上报,并且连续上报 10 次,间隔 200ms,确保手机能收到。

这个设计参考了车辆 ECU 对胎压数据的实时性要求——行驶中胎压变化速度可能很快,漏气场景下几分钟内胎压就能降到危险值,1 秒的上报频率是必须的;而停车时胎压变化极慢,30 秒一次就够了。我实测过,这套策略下传感器平均电流大概能压到 15 微安以内,一颗 240mAh 的 CR2032 电池理论寿命可以到 3 年以上。

运动状态的检测用的传感器内部集成的加速度计,阈值设得比较保守,连续 30 秒检测到超过 0.1g 的加速度才判为运动。这个阈值不能设太低,否则把传感器拿在手里晃一晃也会被判定为运动,导致停车状态下也保持 1 秒上报周期。也不能设太高,否则车辆已经起动 1 分钟了,传感器还以为是静止,胎压数据更新太慢。

4.3 实时查询与命令响应流程

用户打开 APP、点击"刷新"按钮时,手机下发 0x01 读取指令。这里有个时序问题要处理干净:传感器可能正处于深度睡眠状态,收不到指令。

我的处理方案是:传感器每 100ms 监听一次射频事件,如果监听到的是连接事件或者写请求事件,立即唤醒主控处理。对于 APP 点击刷新的场景,传感器从收到指令到回发数据,实测延迟在 50ms 以内,用户感知不到延迟。

还有更硬核一点的做法:如果传感器当前处于非连接广播模式(日常监控状态),手机直接通过广播包就能拿到最新数据,其实不需要连接。所以我做了两层逻辑:APP 端如果只是看当前胎压,直接从广播数据里解析,用户看到数据的时间就是扫描周期,大约 300ms 以内;只有当 APP 需要写配置或者做绑定时才真正发起连接。这基本满足了"刷新要快"的体验需求。

4.4 报警事件流程

报警事件强调"变化即上报"。传感器内部每秒都会做一次阈值判断逻辑:高压、低压、高温、急漏气、传感器异常五类事件。判断逻辑是在每个上报周期内比较当前气压值和阈值,急漏气还需要额外判定气压下降速率,v1.0 里定义的是 5 秒内气压下降超过 30kPa 就触发。

报警帧会包含事件类型和当前完整数据,并且连续发送。这里有个经验值:连续发送帧数定在 10 次,间隔 200ms。如果只发一次,刚好遇上手机扫描窗口处于睡眠期就丢了;连续发 10 次,1 个唤醒扫描周期(大约 1 秒)内手机大概率能抓到。报警标志还会写到广播包里,这样即使传感器后来重回非连接广播模式,广播包里也一直带着报警状态,直到用户确认或者状态恢复。

手机收到报警通知后的处理也做了设计。APP 弹出报警界面,自动切换到对应轮位,并且提示用户是否需要查看历史趋势。报警清除条件是气压恢复到正常范围且持续 30 秒,防止频繁的"高压-正常-高压"抖动导致用户被反复骚扰。

5. 低功耗策略与实测数据

5.1 传感器端功耗模型

BLE 胎压传感器的电池寿命全在功耗设计上,这部分我从硬件和软件两个维度展开。

硬件层面,传感器选型要关注三块功耗:传感器本身的测量功耗(气压计的采样电流)、BLE SoC 的射频功耗(广播时的峰值电流)、深度睡眠功耗(几乎决定待机底电流)。v1.0 用的方案里,深度睡眠模式下整体电流实测在 3 微安左右,这主要靠 SoC 的 retention 模式——保留 RAM 内容但不跑时钟。

软件层面,功耗体现在的核心是"该睡的时候就彻底睡"。我做了事件驱动的架构,没有用定时器中断周期性地唤醒。唯一定时器是出厂前校准用的内部低速时钟,每秒唤醒一次看有没有待处理事件。这个唤醒对功耗的影响大概在 0.5 微安级别,可以接受。

广播事件分开看。一次完整广播事件,从主控被射频事件唤醒、组成广播包、到射频发射结束重新入睡,实测整段电流曲线是这样的:

  • 唤醒和处理时间约 2ms,平均电流 3mA
  • 广播发射时间约 3ms,峰值电流 18mA
  • 回到睡眠时间约 1ms,电流回到 5 微安以下

一次广播的总电荷消耗大约是 60 纳安时。按 300ms 广播间隔折算,广播部分平均电流约 0.72 微安。加上每 30 秒一次的气压采样(一次采样 20ms,电流 4mA,平均下来约 0.09 微安),再加上底电流 3 微安,整体平均电流就在 4 微安左右。这个数字意味着用 CR2032 电池,在纯广播待机场景下寿命能有惊人的 6 年以上。当然实际使用中有运动检测后的高频上报,电流会上升,但 3 年寿命是完全做得到的。

5.2 手机端功耗优化

手机端 APP 的蓝牙功耗主要浪费在后台扫描上。我见过不少同类产品,APP 在后台每 1 秒扫一次广播包,一晚上能把手机电量耗掉 20%。v1.0 方案里,APP 进入后台 5 分钟后自动停止扫描,只保留系统的低功耗定位通知。用户回到 APP 时恢复扫描,并在一秒内刷新数据。

这个策略会牺牲一点点"后台实时性",但考虑到胎压数据不是聊天消息,5 分钟延迟完全可接受。更核心的是,iOS 对后台 BLE 扫描有严格限制,不处理的话 APP 很容易被系统挂起,反而什么都收不到。所以从体验上说,主动停止扫描比硬撑后台要稳定得多。

连接状态下,手机和传感器之间的连接参数也有讲究。连接间隔设的是 30ms,从机延迟设 3,超时时间设 10 秒。这个组合的意思是:手机每 30ms 尝试和传感器通信一次,传感器最多可以连续跳过 3 次(即 90ms),但只要 10 秒内没有通信成功就判定连接断开。从机延迟给了传感器睡懒觉的空间,连接又不至于太迟钝。

6. 常见问题与排查技巧实录

6.1 连接不稳定:先查扫描参数和广播间隔

我调试过程中遇到最多的问题是用户反馈"手机经常搜不到传感器"。排查下来有两个主要原因:一是广播间隔太长,其次手机扫描占空比太低。安卓上如果扫描窗口设置成 100ms、间隔 500ms,那广播间隔 300ms 的信号,手机要扫好几轮才能抓到一次,用户体感就是"搜不到"。

解决办法分两端。传感器端把广播间隔从 300ms 降到 250ms,缩短手机漏扫窗口。手机端把扫描窗口调大到 200ms,间隔 400ms。这样配合下来,实测从打开 APP 到出现数据的平均时间缩短到 800ms 以内。

还有一个隐藏坑:安卓 8.0 以后,如果 APP 没有位置权限,系统直接不给蓝牙扫描结果。很多开发者把权限申请放到后面才做,导致用户第一次打开 APP 时根本扫不到设备。这个问题不是协议问题,但对体验影响极大,我把它列为新手上路第一坑。

6.2 数据丢包:理解 Notify 的不可靠性

BLE 的 Notify 本质上是不可靠传输,链路层虽然有 CRC 和重传机制,但这个重传只保证数据包有没有到达对端的协议栈,不保证 APP 层一定处理了。安卓手机上,如果 APP 主线程被 UI 操作卡住,蓝牙回调的线程也可能被推迟,表现为用户看到的数据偶尔跳动。

我的处理方案是 APP 端对收到的数据做序列号校验。每个上行数据帧载荷第 0 字节高 4 位放了帧计数器,从 0 到 15 循环。APP 检查计数器是否连续,不连续说明中间丢了包,此时触发一次主动查询来补拉数据。这个机制很简单但非常有效,补拉一次就能让界面恢复连贯。

如果传感器端主动上报频率很高(比如报警场景连续 10 帧),而手机正在处理绑定等事务,部分 Notify 包确实可能被协议栈丢弃。所以我在 APP 端专门写了一个轻量级的环形缓冲,先收包缓存,再逐个解析,不让 UI 线程直接处理蓝牙回调的数据。

6.3 功耗异常:用电流曲线说话

功耗异常的排查必须靠示波器或者电流分析仪,用万用表测平均电流是查不出问题的。我调试时用的方案是串联一个 10 欧姆采样电阻,用示波器抓电阻两端电压,就能还原完整的电流脉冲波形。

有一次功耗异常,平均电流比预期高了 20 倍。抓波形发现传感器每隔 1 秒就有一次额外的唤醒,看事件日志发现是外部中断引脚由于没有配置内部上拉,在睡眠状态下处于浮空状态,噪声触发了一连串虚假事件。把引脚配置成内部上拉,问题立刻解决。这个坑在量产板上特别容易出现,PCB 布线时引脚周围如果走过高速信号线,耦合噪声就可能触发浮空引脚。

如果是射频部分的功耗异常,最优先检查天线匹配。天线失配会导致发射时驻波反射,射频前端实际发射效率降低,为了达到相同的辐射功率,芯片会自动加大发射功率,平均电流自然上去。排查方法是在暗室环境下测发射功率和电流的对应关系,如果功率没上来但电流已经很高,十有八九是天线匹配的问题。

6.4 兼容性:iOS 和安卓的行为差异

跨平台兼容性是 BLE 产品避不开的坎。我在开发中发现 iOS 和安卓对 BLE 行为的管理逻辑有本质差异,我总结了四个最容易踩的点。

第一,iOS 对后台扫描限制极严。APP 退到后台后需要声明 bluetooth-central 后台模式,否则扫描会立刻停止,而且即使在后台模式,系统也会周期性暂停扫描以省电。安卓这边宽松得多,但反过来容易让开发者误以为后台扫描可以一直开。

第二,安卓部分机型在系统设置里关闭了"附近设备"权限后,即使 APP 里有位置权限也扫不到设备。排查这类问题时,除了看 APP 权限,还得确认系统级的扫描开关。

第三,iOS 的 CoreBluetooth 对连接设备数量做了隐式限制,实测同时连接超过 4 个传感器时就可能出现连接失败,即使没有报错。安卓这边不同厂商差异更大,有些中低端机同时连 3 个就已经开始掉链子。所以方案上尽可能用广播数据代替连接,非常有必要。

第四,iOS 对 CCCD 的写入操作是自动完成的,安卓则暴露在应用层。如果安卓 APP 在订阅通知前没有正确写 CCCD,会一直收不到传感器主动上报的数据。我在 APP 里加了统一封装,订阅时先检查 CCCD 状态再写入,规避各种机型差异。

6.5 绑定信息丢失:Flash 写入的掉电保护

传感器绑定信息和参数配置存在内部 Flash 里,量产测试时发现偶尔有绑定信息丢失的 bug。排查后定位到问题根源:Flash 写入过程中如果断电,扇区可能处于半擦除状态,重新上电后读出来的是无效数据。

解决方法是写 Flash 前先做双备份,一块存主数据,一块存备份,写入时先擦备份区,再写备份区,最后更新主区。上电启动时先校验主区,如果主区数据校验失败就尝试加载备份区,这样即使写入中途断电,至少有一个完整副本可用。

另外我在参数配置指令的处理里加了回读机制,传感器收到配置后会把完整的配置内容回发给手机,APP 比对后确认配置生效。这个回读机制能有效防止"配置写了一半"的问题,比如手机下发了 5 个参数,传感器只收到了 3 个,如果没有回读,用户以为配置成功了但实际上没有。回读之后 APP 发现不一致,会重新下发剩余参数。

7. 验收测试与协议健壮性验证

7.1 功能测试矩阵

v1.0 定稿后,我需要一套可执行的验收测试矩阵,覆盖所有协议交互路径。整理下来主要包括:

  • 绑定:手机与传感器绑定成功、绑定写入后断电重启、重复绑定同一轮位、绑定过程中手机锁屏、传感器达到绑定窗口超时。
  • 数据查询:手机下发读取指令收到正常应答、传感器在睡眠状态下收到指令能及时唤醒、连续查询 1000 次无遗漏。
  • 数据上报:正常上报周期内数据帧格式正确、启动后首帧数据延迟、运动/静止状态切换时上报周期变化正确。
  • 报警:五类报警事件逐一触发验证、报警连续上报次数符合预期、报警清除后广播包标志位恢复。

每个用例都配了通过标准和记录表,格式化的协议解析工具会统一抓包验证,同时还检查了帧格式里的保留位是否被意外写入。

7.2 压力测试与边界条件

协议健壮性不是功能能用就行,还要扛住异常场景。我做了几个压力测试:

  • 高密度广播场景:在测试环境中部署 20 个传感器同时广播,验证手机能否正确识别并解析目标传感器。结果发现广播信道拥挤时,个别传感器在特定时隙会出现连续的碰撞丢包,但整体扫描成功率达到 98% 以上。
  • 低电量场景:把电池电压放到 1.8V 临界值,验证传感器还能否正常广播和响应指令。BLE SoC 在低压下的射频性能会下降,实测广播功率会降低 3dB 左右,但基本功能还能维持。
  • 连续开关机:传感器在 1 秒内反复上电断电 500 次,验证 Flash 数据不损坏。这主要是测试启动代码在电源不稳时是否会有异常路径。

7.3 自动化抓包与协议验证

协议调试过程中,好的工具能省一半的力。抓 BLE 包我用的是支持 BLE Sniffer 的硬件工具配合协议分析软件,能直接看到空中的链路层报文。这样可以验证广播包是否按预期发出、连接交互是否正确、各个 ATT 层的读写请求是否匹配设计。

用 Sniffer 抓包有个非常大的好处:你能看到手机实际发出的操作序列。比如有一次手机上明明点了"写入配置",但传感器没反应,抓包一看发现手机的 Write Request 报文根本没发出来——问题其实在手机端的业务逻辑,而不是传感器。这类排查经验说明,协议联调时任何一端都不能只靠自己的日志来判断,必须从空中报文找真相。

8. 版本迭代方向

8.1 考虑加入连接更新与多连接模式

v1.0 以广播为主、连接为辅的思路,功耗和兼容性体验都不错。v1.1 我想尝试一个进化方案:支持传感器在多连接模式下的协同工作。比如手机同时连接四个传感器,利用连接事件时间片轮询各传感器数据,这样能获得真正的实时四轮数据,而不是依赖广播扫描。

多连接模式的代价是手机功耗增加、配置复杂度上升、个别机型连接数限制导致体验不稳定。所以 v1.1 的方向应该是提供一个可配置的开关,默认保持广播模式,只有专业用户开启强制实时多连接。

8.2 OTA 固件升级预留

v1.0 协议层预留了 OTA 服务,但功能没做完。v1.1 需要把固件升级流程补全,包括固件包分段下发、校验、断电续传。胎压传感器通常安装在轮胎里,拆装一次的成本很高,OTA 几乎是刚需。

OTA 的协议设计核心是外部的固件包可能几百 KB,而单次 BLE 写通知的载荷只有 20 字节左右(MTU 15 字节长度限制下),就算协商 MTU 到 247 字节,也要几千个包。这个过程中任何一包丢失都可能导致固件损坏,所以必须做分段校验、断点续传和升级失败回滚。

我在 v1.0 预留 OTA 服务的时候已经定义了三个特征值:固件控制、固件数据、固件版本。v1.1 只需要具体实现协议逻辑,不需要再动服务结构。

8.3 数据应用层扩展

胎压数据本身的价值还可以向外延伸。传感器采集到的气压、温度数据如果能结合车辆行驶里程、时间维度做趋势分析,可以给用户提供"轮胎慢漏气预警",这比单纯报一个低压报警更有价值。方案上可以在手机端建立历史数据库,记录每次上报的数据点并生成趋势曲线,通过算法识别出缓慢下降的数据模式。

这套扩展不涉及传感器端协议改动,只是手机端的数据应用,但对产品差异化帮助很大。它让胎压监测从"报警工具"升级成"轮胎健康管理助手"。

9. 写在最后

这套 v1.0 方案从协议设计到量产验证,前后迭代了好几轮。我最大的体会是:BLE 胎压产品的协议设计不是一个纯技术活,而是功耗、时延、兼容性、体验之间的平衡艺术。广播模式的巧妙使用、动态上报周期、双备份 Flash 写入、CCCd 兼容处理,这些细节单独拿出来都不难,但组合在一起,决定了产品是"能跑"还是"好用"。

如果你正在设计类似的 BLE 传感器产品,我建议先把广播通道利用起来,它能帮你省掉很多连接管理的麻烦;同时把功耗模型尽早建立起来,从硬件选型阶段就带着电流预算做设计,后期就不用为了省电大改协议。最后,所有协议交互都要过一遍抓包工具验证,不要只依赖两端各自的日志,这是排查联调问题的基本底线。

再分享一个小技巧:给每个协议版本做一张清晰的指令表和帧格式图,放在项目文档首页。后面不管是自己查 bug、带新人、还是对接外部团队联调,这份文档都会帮你节约大量沟通成本。工程师的时间应该花在解决新问题上,而不是每次都要重新回忆协议当初是怎么定的。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进