深入理解经典蓝牙的channel

本文整理经典蓝牙(BR/EDR)中 "channel" 概念的分层体系与 5 种物理信道,以及跳频、发现/连接机制中容易混淆的要点。

物理层(PHY, Physical Layer)

  • 功能:负责无线射频信号调制、跳频和基带传输。

  • 关键特性:

    • 工作频段:2.4 GHz ISM 频段(79个1 MHz信道)。

    • 调制方式:GFSK(BR)调频、π/4-DQPSK(EDR 2 Mbps)调相、8DPSK(EDR 3 Mbps)调相。

    • FSK:Frequency Shift Keying,频移键控。

    • PSK:Phase Shift Keying,相移键控。

    • 跳频扩频(FHSS):1600跳/秒,抗干扰。

一、先厘清:"Channel" 是一个被复用的词

蓝牙协议栈从底到顶有四层都叫 channel,含义完全不同,这是初学最容易混淆的地方。

📌 记住这条主线:设备在某个 physical channel (跳频序列)上,用 79 个 RF channel (频点)跳频,建立 physical link ,上面跑 logical transport (ACL/SCO),再由 L2CAP channel 分发给各上层协议。

分层结构

层级 "channel" 指什么 数量 / 标识
L2CAP channel 上层协议复用的逻辑数据管道 用 CID 标识,可有多条
Logical transport / link 承载不同流量类型的逻辑通道 ACL / SCO / eSCO / ASB / PSB / LC 等
Physical link 一对设备间的 baseband 连接 ---
Physical channel 跳频序列 + 时序 + access code 定义的射频占用 5 种(本文重点)

另一个易混概念:RF Channel

  • RF channel(射频信道)= 79 个,频率 2402~2480 MHz,间隔 1 MHz。

  • 这是纯粹的物理频点概念,是 physical channel 跳频时"落脚"的那些频率。

  • 注意:经典蓝牙是 79 个 RF 信道(不是 80)。

二、5 种 Physical Channel

物理信道 用途 跳频特征
Basic piconet physical channel 已连接 piconet 的正常通信 79 信道跳频,1600 hops/s
Adapted piconet physical channel 同上,但启用 AFH(自适应跳频) 跳频序列避开受干扰信道(如被 WiFi 占用的)
Page scan physical channel 被连接方等待被 page(寻呼) 32 频子集,守频慢跳
Inquiry scan physical channel 可发现设备等待被 inquiry(查询) 32 频子集,守频慢跳
Synchronization scan physical channel Connectionless Slave Broadcast 的同步扫描 用于无连接广播场景

三、Basic vs Adapted:关键区别不是"跳不跳"

⚠️ 常见误区:以为 Basic channel "不能跳频"。实际上 Basic 和 Adapted 都跳频 ,区别在于跳频时用不用得全 79 个信道

Basic piconet channel Adapted piconet channel
跳频?
用几个信道跳 全部 79 少于 79(剔除坏信道,至少保留 20 个)
跳频序列 标准伪随机序列,覆盖全 79 把受干扰信道从序列里映射掉,只跳干净信道

生命周期:Basic 是起点,Adapted 是升级

复制代码

连接刚建立 │ ▼ Basic piconet channel(全 79 跳频) ← 每条连接必然先用这个 │ │ master/slave 交换 AFH 信息,评估哪些信道被干扰 ▼ 切换到 Adapted piconet channel(AFH,避开坏信道) ← 可选,若双方支持 AFH

  • 每条连接都从 Basic channel 开始------建连时还没做信道评估,只能全 79 跳。

  • 若双方都支持 AFH(现代设备基本都支持),再切到 Adapted。

  • 若有一方不支持 AFH,或环境无明显干扰,就一直停在 Basic

  • 结论:Basic 没被淘汰,它是每条连接的起点与 AFH 的回退基线;稳态通信多数升级到 Adapted。

真正"守着固定频率、不跳频"的是 page scan / inquiry scan 这类扫描信道,不是 Basic piconet channel。

四、发现/连接为什么不慢:不对称跳频 + Train A/B

只用 32 个信道,不遍历 79

  • inquiry / page 阶段只用 79 里的 32 个信道。

  • 这 32 个再分成两个 train:Train A(16 个)+ Train B(16 个)

不对称跳频是关键

角色 跳频速度 行为
发起方(inquirer / pager) ~3200 hops/s(每 slot 2 跳) 疯狂扫频,~10ms 铺满一个 train 的 16 个频率
扫描方(scanner) 每 1.28s 才换一个频率 准静止,守在某一频率上监听扫描窗口

💡 秘诀:不是让扫描方去追频率,而是让发起方在极短时间内把整个 train 铺满。扫描方原地不动就会被"扫过",一个扫描窗口内即命中。

Train A / B 的作用

  • 两端时钟可能有偏差,扫描方守的频率不一定落在 Train A 里。

  • 发起方先反复发 Train A(覆盖时钟接近的情况),再切 Train B(覆盖偏差大的情况),来回轮换。

  • inquiry 和 page 都用 Train A/B 机制

inquiry vs page 的差异

Page Inquiry
跳频序列种子 目标设备 BD_ADDR GIAC(0x9E8B33)
发起方知道对方相位 大致知道 完全不知道
典型耗时 ~1.28s 内(最坏 ~2.56s) 通常跑满 ~10.24s 收全设备
响应处理 一对一,直接建连 一对多,持续发现更多设备
退避机制 随机 backoff,避免多设备同时响应撞车

Inquiry Scan 的退避(Random Backoff)机制

⚠️ 强调:被退避(延迟发送)的是 FHS 响应包,不是 inquiry 请求本身。

解决的问题:多台设备可能在同一时刻收到同一个 inquiry 消息,如果它们立刻同时回 FHS 响应,就会在射频上撞车,发起方一个都收不到。Backoff 用随机延迟把这些 FHS 响应在时间上打散。

生效流程:

  • 扫描方在 INQUIRY SCAN 守频监听,收到第 1 个匹配 IAC(GIAC/DIAC)的 inquiry ID 包时,不立即回 FHS

  • 生成随机数 Nrand ∈ 0, 1023,退避 Nrand 个 slot(1 slot = 625µs,最长 ≈ 639.375ms)。

  • 退避结束后重新进入 INQUIRY SCAN,直到再次收到 inquiry ID 包,这时才发送 FHS 响应包(携带自己的 BD_ADDR、时钟等;若支持 EIR,紧跟一个扩展响应包)。

为什么能防撞车:

  • 随机 Nrand:每台设备退避时长不同,FHS 发送时刻被错开,避免同时 fire。

  • 退避后"下一次"收到 inquiry 才发 FHS:发起方一直在疯狂扫频(~3200 hops/s,Train A/B 轮换),下一次命中时频点已变,即使两台设备凑巧同时醒来,各自命中的时刻/频率也不同,天然带频率分集,进一步降低碰撞。

  • 每台设备一轮只响应一次:响应完退出,不反复占信道。

对比 page 为何无退避:page 是一对一(种子为目标 BD_ADDR,被叫唯一),不存在多设备抢答;inquiry 是一对多,周围所有设备都可能应答,必须靠随机退避错峰。这也是 inquiry 通常要跑满 ~10.24s 收全设备的原因之一------要给多台设备的退避 + 错峰响应留够时间窗口。

深入:Inquiry 的扫描时序与 backoff 的真实代价

① inquiry 的 Train A/B 不是"猜时钟",与 page 含义不同

  • inquiry 的 32 个频点序列种子是 GIAC(0x9E8B33) ,不是任何一方的地址。所有设备用同一张频点表,各自在表里的相位由自己的时钟决定,双方相位无关、也无需对齐。

  • 因此 inquiry 是彻底的 clock-agnostic 暴力覆盖:发起方不知道也不需要知道对方时钟,只是把频点表反复全扫,扫描方迟早被扫过。

  • A/B 的划分是时钟比特进位结构的自然产物:一趟 ~10ms 快速 sweep 由低位时钟比特驱动,只能铺满 16 个(= 一个 train);要够到另外 16 个,得等高位比特推进,所以硬件上一次只出得来一个 train,只能分时打。

  • 对比 page:pager 有对方时钟的估计值 CLKE,可以把 train 对准估计的醒频------估得准落 A、飘了落 B,这里"时钟接近/偏差大"才是真实语义。page 是"对准 + 兜底",inquiry 是"没得对准,索性两半都扫穿"。

② inquirer 扫描的时间尺度

时间尺度 发生什么
312.5µs 换一个频点(发或听)
625µs(1 slot) 发 2 个频点 / 听 2 个频点对应的响应频率
10ms(16 slot) 把一个 train 的 16 个频点扫完一趟(one pass)
2.56s(≈256 趟) 同一个 train 猛重复,罩住扫描方 1.28s 守频窗口(覆盖 2×1.28s 确保对齐无关)
A↔B 交替 覆盖被时钟比特切成两半的全部 32 个频点
~10.24s 整个 inquiry 收全周围设备

10ms 只是"扫了一趟",远远不够。扫描方准静止、每 ≤1.28s 才开一次很短的扫描窗口,一趟命中概率极低,所以要把同一个 train 死命重复约 2.56s,再换另一半,A/B 来回轮换。

③ backoff 不会放大 inquirer 的接收窗口(重点澄清)

常见误区:以为 FHS 被 backoff 了,发起方就得开一个几百 ms 的大窗口干等。实际不需要------窗口永远是标准 RX slot(625µs)。

  • scanner 收到第 1 个 inquiry ID 包时不回 ,退避 Nrand 个 slot;退避结束后重新守听,直到收到下一个 ID 包,才在其后 625µs 发 FHS。

  • FHS 的发送时刻锁定在**"触发它的那个 ID 包"后 625µs**,而那个 ID 包是发起方刚发出的 → FHS 恰好落进发起方紧跟的标准 RX slot。

  • 所以 backoff 让 scanner"改天再回"(响应未来某一轮 inquiry),而不是让 inquirer"一直等着这次"。代价从"空间(窗口宽度)"转移到"时间(发起方要多扫很多轮、总时长更长)",这也是 inquiry 要跑满 ~10.24s、train 重复上百次的原因之一。

  • 别混淆两个窗口:scanner 侧的 inquiry scan window(Tw_inquiry_scan,通常 ≥11.25ms) 要够宽,是为了完整接住至少一整趟 train 的 ID 包,与 backoff 无关;inquirer 侧的 **RX slot(625µs)**是标准大小,永不变。

这 32 个信道是什么?从哪来?固不固定?

结论:这 32 个不是硬编码的某几个固定频率,而是从 79 个 RF 信道里、由 access code(地址)经跳频选择算法算出的子集。"固不固定"要分两个维度:集合固定,但当前落点和 A/B 划分随时钟滚动。

① 由"地址 + 时钟"两类输入算出

跳频选择算法(hop selection kernel)吃两类输入:

  • 地址比特 (access code 里的 LAP/UAP)→ 决定挑哪 32 个频点及其排列

  • 时钟比特 (CLKN)→ 决定此刻走到序列的哪个位置

所以这 32 个频点散布在 2402~2480 MHz 里、彼此散开(为频率分集),不是连续一段,也不是写死的 MHz。

② 按场景看集合是否固定

场景 种子(决定 32 个) 集合是否固定
General Inquiry GIAC = 0x9E8B33(全球唯一固定) 固定,全世界所有设备用同一组 ← 陌生设备能互认的原因
Limited Inquiry LIAC = 0x9E8B00 另一组固定的 32 个(与 GIAC 组不同)
Page(寻呼) 被叫设备 BD_ADDR(LAP) 每个目标一组,各不相同
  • Inquiry 的 32 个是"公共频道":种子是固定的 GIAC,这组 32 个公开、固定、人人相同,所以互不相识的设备也能碰上。

  • Page 的 32 个是"专属频道":种子是被叫设备地址,因目标而异,只有知道对方地址才算得出去哪找它。

③ 集合固定 ≠ 位置固定

对同一个 access code:

  • 哪 32 个频点、整体排列 → 由地址定死,不随时钟变

  • 此刻落在哪一个、Train A/B 如何切分 → 由时钟比特(经典蓝牙 CLKN16--12) 决定,随时间滚动

比喻:32 个频点像一圈固定的座位(座位表由地址定死),时钟决定"此刻指针转到哪个座位"。座位没变,指针在动。Train A(16)/ B(16)就是把这一圈切成前后两半,切点与当前指向由时钟决定。

④ 现代设备可能少于 32

基线是 32,但:早期某些国家用过 23-hop 缩减系统(现已基本淘汰);现代规范给 inquiry/page 也引入 AFH 自适应,可把受干扰的 wake-up 频点从这 32 个里剔除或重映射------实际跳的可能少于 32 或换了成员,但"以 32 为基准子集"的框架不变。

五、Access Code 与 Inquiry 补充要点

  • 三种 access code:CAC(piconet 内通信,种子=master LAP)、DAC(paging,种子=被叫 LAP)、IAC(inquiry)。

  • GIAC = 0x9E8B33 ,唯一且固定,通用发现,绝大多数场景只用它

  • DIAC 取值范围 0x9E8B00~0x9E8B3F,常用的是 LIAC = 0x9E8B00(有限发现,用于主动配对)。

  • DIAC 与 Class of Device(CoD)无对应关系:DIAC 是链路层"暗号"决定响应与否(无类型语义);设备类型过滤靠上层解析响应里的 CoD 字段实现。

六、一句话总结

  • Physical channel 有 5 种(basic / adapted piconet, page scan, inquiry scan, synchronization scan)。

  • 别把它和 RF channel(79 个频点)、logical transport(ACL/SCO)、L2CAP channel(CID) 混为一谈。

  • Basic 与 Adapted 都跳频,区别是用不用全 79 个信道;Basic 是起点,Adapted 是 AFH 抗干扰升级。

  • 发现/连接不慢,靠的是不对称跳频 + Train A/B 轮换,只用 32 个信道而非全部。

相关推荐
朝发如雪1 小时前
快速掌握Linux(1)(Linux文件操作)(标准IO)
linux·运维·服务器
额额额对了1 小时前
Linux 进程管理详解:从概念到实战
java·服务器·前端
一直C1 小时前
【Linux应用编程】深入理解Linux多任务机制:进程原理、状态转换与进程控制实战
linux·开发语言·算法·ubuntu·vim·visual studio code
影寂ldy1 小时前
C# WinForm TCP-Socket
网络·tcp/ip·c#
桌面运维家1 小时前
信创机房批量换国产终端,服务器IO通道配置实测体验
运维·服务器
IT小白杨1 小时前
多账号运营为什么需要独立浏览器环境:原理、机制与自测方法
服务器·chrome·经验分享·安全架构·指纹浏览器
前端炒粉1 小时前
fetch+readablestream(Streamable)流式输出
java·服务器·前端
FORCECON11 小时前
力控SCADA工程升级:信创跨平台迁移方案,快速搭建安全自主的工业监控系统
linux·windows·自动化·信创·scada·监控组态软件
小义_2 小时前
Linux 性能排查实战
linux·服务器·php