上个月帮一个做工业数据采集的朋友看问题。他们的系统里一个主控设备通过低功耗无线链路轮询十几个从机节点每个从机上报一次传感器数据。功能本身不复杂但现场反馈说从机响应时快时慢快的时候几十毫秒就回来了慢的时候要等两三秒而且越到后面越明显。他们一开始怀疑是射频干扰换了信道、加了重传没用。又怀疑从机固件跑飞了加了看门狗也没用。我让他们把主控侧的时间戳日志导出来一看就明白了——从机回复的时间点几乎都卡在连接事件的边界上。有些从机明明有数据要发但就是不在当前连接事件里回非要等到下一个甚至下下个连接事件。而连接间隔设的是几十毫秒从机延迟设了一个不小的值。这两个参数配合出了问题。这个坑很典型但公开资料里很少把这两者的互动关系讲透。大多数文档只告诉你“从机延迟可以省电”或者“连接间隔影响吞吐量”但真正在项目里这两个参数是耦合的单独调任何一个都可能掉进沟里。先还原一下当时的参数配置主控和从机建链时连接间隔设的是 40ms。从机延迟设的是 6。监督超时是 4 秒。从机侧开了低功耗模式主控轮询的周期是 200ms 一次。从机的逻辑是有数据就等着下一个连接事件发没数据就跳过。但固件里有个细节——从机在跳过连接事件时会进入深度睡眠唤醒需要一定时间。这个唤醒时间没有算进连接事件的处理窗口里。结果就是当从机连续跳过了 6 个连接事件也就是 6 × 40ms 240ms之后它必须强制醒来参加下一个连接事件。但醒来的时候连接事件的锚点已经过了它错过了接收窗口只能等再下一个。而主控这边轮询请求发出去之后如果从机没在当次连接事件里回主控就认为这次轮询失败等下一个轮询周期再发。两个周期叠加响应就拖到了几百毫秒甚至更久。更麻烦的是从机延迟设得越大从机睡的时间越长唤醒后错过连接事件锚点的概率就越高。而连接间隔越大每个连接事件之间的空隙就越大一旦错过等待的绝对时间就越长。这两个参数一起放大就出现了现场看到的“越到后面越慢”。从机延迟到底在延迟什么很多刚接触低功耗无线的人会以为“从机延迟”是从机可以晚一点回复。不完全是。从机延迟的准确含义是从机可以跳过多少个连续的连接事件而不必监听主控。注意是“不必监听”不是“可以晚回复”。这意味着如果从机设置了延迟 6它可以在 6 个连接事件里完全不开接收机。主控在这 6 个连接事件里发给它的任何数据它都收不到。主控如果在这期间有数据要下发要么等从机下一次强制醒来要么就得靠主控侧缓存等从机醒来后再发。这里有个隐形陷阱从机延迟的生效前提是从机在上一次参与连接事件时没有收到主控发给它的数据也没有自己的数据要发。只要从机有数据要发或者主控有数据给它从机就必须在下一个连接事件里出现延迟计数清零。但问题在于很多从机固件的实现是只要应用层没有新数据就无条件跳过连接事件不管主控是不是在寻呼它。这就导致主控的下行数据被硬生生拖到从机下一次强制醒来。连接间隔不是越小越好有人会说那把连接间隔调到最小不就行了比如 7.5ms。这样从机就算跳过几个连接事件绝对时间也不长。但连接间隔调小带来的代价是主控和从机的射频收发次数成倍增加功耗直线上升。对于从机是电池供电的场景连接间隔 7.5ms 意味着从机就算什么都不干也要每 7.5ms 醒一次来监听。从机延迟这时候基本失效因为连接事件太密集从机还没来得及睡就被叫醒了。而且连接间隔太小留给应用层处理数据的时间窗口就窄。如果从机在连接事件里要完成接收、处理、准备回复时间不够就会导致回复失败反而增加重传。所以连接间隔的选择是在“响应延迟”和“功耗”之间找平衡。但这个平衡点不是固定的它取决于从机延迟怎么设。这两个参数必须一起算我后来给他们的建议是先确定从机侧应用层能容忍的最大下行延迟。比如主控轮询周期是 200ms那从机最晚必须在 200ms 内回复。然后反推连接间隔和从机延迟的组合。具体做法是设连接间隔为 CI从机延迟为 SL监督超时为 TO。从机最坏情况下会连续跳过 SL 个连接事件然后在第 SL1 个连接事件必须醒来。但从机醒来后如果错过了锚点还要再等一个连接事件。所以从机最坏响应时间大约是T_wor半导体厂商 (SL 2) × CI这个时间必须小于应用层能容忍的最大延迟。同时从机平均功耗大致与 CI / (SL 1) 成正比这个值越大越省电。以他们的场景为例轮询周期 200ms要求从机最坏响应不超过 200ms。如果 CI 取 30msSL 取 4那么 T_wor半导体厂商 (42) × 30 180ms勉强满足。但实际还要留余量给射频处理和重传所以 SL 要再降一点取 3T_wor半导体厂商 150ms余量够了。但这里还有个关键点从机固件必须保证在它参与连接事件的那个周期里如果主控有下行数据它必须能及时处理并回复。如果从机唤醒后需要较长时间才能准备好射频那连接间隔还要再放大或者把从机延迟再调小让从机醒得更频繁一些。现场怎么观察和判断如果你在现场遇到类似的响应时快时慢可以按下面几步排查。第一步抓主控侧的收发时间戳。看从机回复的时间点是不是总是落在连接事件边界附近。如果是基本可以确定是连接参数配合问题。第二步确认从机侧的实际从机延迟值。有些从机固件会在运行中动态调整这个值或者主控在连接建立后通过连接参数更新请求改了值。要确认最终生效的是多少。第三步检查从机在跳过连接事件时的唤醒时序。用示波器或者从机侧的调试引脚看从机从睡眠唤醒到射频准备好需要多长时间。如果这个时间接近或超过连接间隔那从机醒来后大概率会错过锚点。第四步临时把从机延迟设为 0看响应是否变稳定。如果设为 0 之后响应立刻正常那就确认是延迟和连接间隔的配合问题。然后再逐步增加延迟观察响应时间的劣化曲线找到可接受的临界点。第五步如果从机侧有日志看每次跳过连接事件后下一次参与连接事件时是否成功收到主控的寻呼。如果连续多次错过说明唤醒时序需要调整或者连接间隔需要放大。一个容易被忽略的细节连接参数更新请求主控和从机建链后从机可以主动发起连接参数更新请求主控也可以发起。但很多协议栈默认只允许从机发起一次或者主控会拒绝某些参数组合。我在另一个项目里见过从机请求把连接间隔从 40ms 改成 20ms从机延迟从 6 改成 2。主控协议栈接受了但实际生效的时间比预期晚了十几秒。在这十几秒里从机还是按旧参数跑响应时快时慢。后来查出来是主控侧的协议栈在收到请求后要等当前连接事件结束才应用新参数而如果从机在这期间一直在跳过连接事件主控就找不到合适的时机下发更新。所以如果你在调试中改了连接参数一定要确认新参数是什么时候真正生效的。最好在从机侧打印每次连接事件的实际间隔和延迟计数跟主控侧的日志对一下。取舍省电和响应速度不可兼得最后说取舍。从机延迟和连接间隔的配合本质上是在省电和响应速度之间做选择。从机延迟越大从机睡的时间越长越省电但下行响应越慢。连接间隔越大射频活动越少也越省电但一旦错过连接事件等待的绝对时间越长。没有一组参数能同时满足“最省电”和“最快响应”。工程上要做的是先确定应用层能容忍的最坏响应时间然后在这个约束下尽量把从机延迟和连接间隔往省电的方向调。调完之后一定要在真实场景里跑长时间测试因为从机延迟的跳过行为是动态的跟数据到达的随机性有关短时间测试不一定能暴露问题。如果应用层对下行响应要求很高比如主控需要频繁下发控制指令那从机延迟最好设小甚至设 0连接间隔也不要太大。如果从机主要是上行上报下行很少那从机延迟可以设大一些连接间隔也可以放宽省电效果会很明显。最怕的就是像开头那个项目一样从机延迟设了一个不小的值连接间隔也设得偏大两个参数各自看都合理合在一起就出问题。而且这种问题不是必现跟数据到达的时机有关调试的时候很容易被误导到射频干扰或者固件稳定性上去。把这两个参数放在一起算把最坏响应时间算清楚再留够余量基本就能避开这个坑。