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 方案里做了一个取舍默认手机同一时刻只和一个传感器保持连接其他传感器通过快广播 定向连接的机制来上报数据。具体流程是——手机在绑定界面和各传感器依次建立连接完成绑定和参数配置。日常监控模式下传感器平时处于低功耗广播状态携带最新的气压温度数据。手机 APP 周期性扫描广播包直接从广播数据里解析各轮位的数据不需要逐一建立连接。只有当传感器发出报警事件、或者用户主动要求查看详细信息时才建立临时连接。这个设计有点像门口的对讲机一直处于待机状态你路过时它能直接喊一嗓子告诉你屋里什么情况而不需要你推门进去问一遍。广播通道本身就能载荷数据这是 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 加 NotifyRead 是为了让手机随时主动拉取Notify 是传感器主动推送时用的。控制特征用了 Write No Response因为胎压控制指令很短不需要等链路层确认能省掉一次交互延迟。事件特征只有 Notify它是纯上行的手机不需要写。绑定信息特征可读可写因为绑定动作本身就是手机往传感器里写数据。每个特征我都配了 CCCDClient 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 ~ 40002温度值1 字节有符号整数单位 ℃范围 -40 ~ 1253电量1 字节百分比 0 ~ 100%4RSSI1 字节有符号整数单位 dBm5轮位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、带新人、还是对接外部团队联调这份文档都会帮你节约大量沟通成本。工程师的时间应该花在解决新问题上而不是每次都要重新回忆协议当初是怎么定的。