2. 连接断开现象分类:瞬时断开、周期性断开、永久性断开
做蓝牙Mesh调试这些年,我见过最头疼的问题不是连不上,而是连上了又莫名其妙断开。你想想看,一个智能照明系统,灯泡忽明忽暗,用户第一反应就是“这破玩意儿坏了”。其实很多时候,问题出在连接断开上。
我个人习惯,拿到一个断连问题,先不急着抓空包。先问一句:这个断开是偶发的,还是有规律的,还是一断就再也回不来了? 这三种情况,根因完全不同。
核心观点: 断连现象的分类,决定了你的排查方向。方向错了,抓三天空包也找不到原因。
2.1 瞬时断开
瞬时断开,说白了就是“闪断”。连接刚断,下一秒又自动回来了。应用层可能都没反应过来,或者只丢了一两个包。
表现特征:
- 断开持续时间极短,通常在几十毫秒到几百毫秒之间
- 断开后节点会自动发起重连,不需要用户干预
- 应用层可能表现为“卡了一下”或者“丢了一个控制指令”
- 抓空包时,能看到
LL_TERMINATE_IND后紧跟着CONNECT_REQ
我记得有一次,客户反馈说他们的智能灯偶尔会“闪一下”。我一开始以为是电源问题,后来抓空包才发现,是蓝牙连接在毫秒级断开又重连了。灯控芯片的PWM刚好在断连瞬间被重置,导致灯光闪烁。
排查技巧: 瞬时断开最难抓。我建议你在抓空包时,把时间戳精度调到微秒级,同时关注 Connection Interval 附近的异常跳变。
2.2 周期性断开
周期性断开,是有规律的。每隔几秒、几分钟或者几十分钟,连接准时断一次。这种问题最好排查,因为可以复现。
表现特征:
- 断开间隔基本固定,误差在可接受范围内
- 断开后通常能自动重连,但重连过程可能造成业务中断
- 常见于低功耗节点(LPN)与Friend节点的交互场景
- 与心跳包超时、扫描窗口关闭、睡眠唤醒周期强相关
为什么会这样?我举个例子。低功耗节点为了省电,会定期休眠。如果它的 Scan Duty Cycle 设置得太低,或者 Heartbeat Period 与 Connection Supervision Timeout 不匹配,节点在休眠期间收不到心跳,就会被对端判定为超时断开。
避坑指南: 我曾经在一个项目中,把LPN的扫描间隔设成了2秒,但Supervision Timeout只设了3秒。结果节点每次休眠超过3秒就被断开。嗯,这个坑我踩过,后来把Timeout改到6秒就解决了。
周期性断开还有一个常见原因——扫描窗口与广播窗口错位。两个节点如果时钟漂移太大,或者扫描窗口太窄,就会周期性“错过”对方的广播包,导致连接断开。
| 参数 | 推荐值 | 说明 |
|---|---|---|
| Connection Supervision Timeout | ≥ 6 × Connection Interval | 给重传留足余量 |
| Heartbeat Period | ≤ Supervision Timeout / 3 | 确保心跳在超时前到达 |
| Scan Window | ≥ 2 × Advertising Interval | 避免扫描窗口过窄 |
2.3 永久性断开
永久性断开,是最严重的情况。连接断了,就再也回不来了。用户必须手动重启设备,或者重新上电,甚至需要重新配网。
表现特征:
- 断开后节点不发起重连,或者重连失败后放弃
- 应用层长时间收不到数据,业务完全中断
- 通常伴随硬件复位、协议栈崩溃或配置丢失
- 抓空包时,能看到
LL_TERMINATE_IND后没有任何重连请求
永久性断开的根因,我总结下来主要有三类:
- 硬件故障: 晶振停振、射频前端损坏、电源纹波过大导致芯片复位。我在项目中遇到过一颗晶振,温度一超过60°C就停振,连接直接永久断开。
- 协议栈崩溃: 内存泄漏、死锁、或者未处理的异常导致协议栈挂死。这种情况在低端MCU上尤其常见。
- 配置丢失: 节点的配网信息(Network Key、App Key、IV Index)被意外擦除,导致节点无法加入原有网络。
重要提示: 永久性断开,我建议你第一时间检查硬件复位引脚和电源波形。很多时候,问题不在蓝牙协议栈,而在硬件层面。
2.4 三种断连的快速对比
为了方便你快速定位,我把三种断连的关键差异整理成了一张表。你拿着这张表去对现场现象,基本能判断个八九不离十。
| 对比维度 | 瞬时断开 | 周期性断开 | 永久性断开 |
|---|---|---|---|
| 持续时间 | 毫秒级 | 秒级到分钟级 | 无限期 |
| 规律性 | 无规律 | 有固定周期 | 一次性 |
| 自动重连 | 立即重连 | 通常能重连 | 不重连 |
| 常见根因 | 射频干扰、链路层异常 | 心跳超时、扫描窗口错位 | 硬件故障、协议栈崩溃 |
| 排查难度 | 高(偶发难抓) | 低(可复现) | 中(需检查硬件) |
我的习惯: 拿到一个断连问题,先看日志里有没有 LL_TERMINATE_IND 的原因码。如果是 0x08(Supervision Timeout),大概率是周期性断开;如果是 0x13(Unsupported Remote Feature),那就要检查协议栈版本兼容性了。