2. 连接建立流程:广播、扫描、发起连接、连接参数协商
大家好,我是你们的老朋友。今天我们来聊聊蓝牙GATT连接是怎么建立起来的。很多刚入行的工程师,遇到连接断开的Bug,第一反应就是查信号、查天线。但说实话,连接建立阶段的参数协商,才是很多诡异断连问题的根源。
我个人习惯把连接建立拆成四个阶段:广播 → 扫描 → 发起连接 → 参数协商。咱们一个一个来过。
核心观点:连接参数协商是GATT连接的“合同签署”环节。合同签得不好,后面执行起来全是坑。
2.1 广播阶段 —— 设备在喊“我在这里”
广播,说白了就是外设(Peripheral)在不停地喊:“我在这儿,我能连,我的名字是XXX,我支持这些服务……”
广播包分两种:
- 广播包(Advertising Packet):必发,包含设备地址、广播类型、部分数据。
- 扫描响应包(Scan Response Packet):可选,当主机扫描时,外设可以回复更多信息。
我记得有一次调试一个手环项目,设备死活连不上手机。抓空包一看,广播间隔设成了20ms,但广播信道太拥挤,导致手机收不到完整的广播包。后来我把广播间隔调到100ms,问题就解决了。嗯,这里要注意:广播间隔太短,功耗高且容易丢包;太长,连接响应慢。
| 参数 | 典型值 | 说明 |
|---|---|---|
| 广播间隔 | 20ms ~ 10.24s | 步进0.625ms,实际项目中常用100ms~1s |
| 广播信道 | 37/38/39 | 三个专用信道,避免与Wi-Fi冲突 |
| 广播类型 | 可连接/不可连接/可扫描 | 决定设备能否被连接 |
实战技巧:如果你在做低功耗产品,广播间隔建议设在200ms以上。我曾经见过一个项目,为了追求“秒连”,把广播间隔压到30ms,结果电池两天就耗光了。
2.2 扫描阶段 —— 主机在“听”
主机(Central)这边,会定期打开接收窗口,监听广播信道。扫描也分两种模式:
- 被动扫描:只听,不发请求。省电,但信息有限。
- 主动扫描:听到广播后,发送扫描请求,获取扫描响应包。信息更全,但功耗高。
你想想看,如果主机扫描窗口太小,或者扫描间隔太长,就可能漏掉外设的广播包。这就是为什么有时候手机靠近设备,却搜不到——不是设备没广播,而是手机没在听。
避坑指南:我曾经遇到一个案例,外设广播间隔100ms,主机扫描间隔1.28s,扫描窗口只有11.25ms。结果主机平均要等3~5个广播周期才能抓到一次。这种配置下,连接建立延迟高达数秒,用户体验极差。
2.3 发起连接 —— 握手瞬间
当主机扫描到目标外设后,会发送一个连接请求(CONNECT_REQ)。这个请求里,包含了主机希望使用的连接参数。
连接请求包含的关键信息:
- 发起者的物理地址
- 接收者的物理地址
- 连接参数(我们下一节细讲)
- 信道映射
- 跳频算法增量
外设收到连接请求后,如果接受,就会回复一个空包(Empty PDU)。至此,连接建立成功。但注意,此时连接参数还是主机单方面提出的,外设可以后续要求修改。
2.4 连接参数协商 —— 真正的“谈判桌”
连接建立后,外设可以通过连接参数更新请求(Connection Parameter Update Request),向主机提出新的参数。主机可以选择接受、拒绝或提出折中方案。
这里涉及三个核心参数:
| 参数 | 单位 | 范围 | 说明 |
|---|---|---|---|
| Connection Interval | 1.25ms | 6 ~ 3200 | 两次连接事件之间的时间间隔。值越小,延迟越低,功耗越高。 |
| Slave Latency | 次数 | 0 ~ 499 | 从设备可以跳过多少个连接事件而不响应。值越大,从设备越省电。 |
| Supervision Timeout | 10ms | 10 ~ 3200 | 如果在这个时间内没有收到任何包,连接被视为断开。 |
这三个参数之间有一个硬约束:
Supervision Timeout > (1 + Slave Latency) × Connection Interval × 2
为什么?因为从设备最多可以跳过Slave Latency个连接事件,再加上当前事件,最坏情况下要等 (1 + Slave Latency) × Connection Interval 的时间才能收到一个包。Supervision Timeout必须大于这个值的两倍,否则连接会被误判为断开。
我在项目中遇到过最典型的案例:一个传感器节点,为了省电把Slave Latency设成100,Connection Interval设成100ms,但Supervision Timeout只设了5秒。算一下:(1+100)×100ms×2 = 20.2秒,远超5秒。结果设备每隔几分钟就断连一次。查了三天才找到原因。
黄金法则:Supervision Timeout 至少是 (1 + Slave Latency) × Connection Interval × 3,留出余量。
2.5 连接参数协商的完整流程
下面这张图,是我自己画的一个流程总结。你可以把它当作调试时的参考地图。
2.6 参数选择的实际考量
讲完流程,咱们聊聊实际项目中怎么选参数。我总结了一个简单的对照表:
| 应用场景 | Connection Interval | Slave Latency | Supervision Timeout |
|---|---|---|---|
| 高实时性(如鼠标、键盘) | 7.5ms ~ 15ms | 0 | 100ms ~ 500ms |
| 中等实时性(如手环通知) | 30ms ~ 50ms | 2 ~ 5 | 1s ~ 3s |
| 低功耗传感器(如温湿度计) | 100ms ~ 500ms | 10 ~ 100 | 5s ~ 20s |
个人经验:如果你不确定怎么配,先从保守值开始:Connection Interval 50ms,Slave Latency 0,Supervision Timeout 2s。等产品稳定了,再逐步优化。我曾经在一个医疗项目中,因为一开始就追求极致功耗,结果参数配得太激进,导致连接频繁断开,差点延误了项目进度。
2.7 常见问题与排查思路
最后,我列几个我在项目中遇到过的典型问题,供你参考:
- 问题1:连接建立慢 → 检查广播间隔和扫描窗口是否匹配。广播间隔100ms,扫描窗口至少11.25ms,扫描间隔不超过1s。
- 问题2:连接频繁断开 → 先算 Supervision Timeout 是否满足约束。90%的断连问题出在这里。
- 问题3:数据延迟高 → 检查 Connection Interval 是否太大。如果对实时性有要求,建议不超过30ms。
- 问题4:功耗异常高 → 检查 Slave Latency 是否设为0。适当增加 Slave Latency 可以显著降低从设备功耗。
重要提醒:连接参数协商不是一次性的。外设可以在任何时候发起参数更新请求。但注意,频繁发起参数更新会导致连接不稳定。我建议只在必要时发起,比如设备状态发生重大变化时(从充电状态切换到工作状态)。
好了,关于连接建立流程和参数协商,今天就聊到这里。这些内容看起来简单,但实际调试中,每一个参数都可能成为坑。希望你能把这些知识用到实际项目中,少走一些弯路。