UWB与BLE协同模组开发及联调 - 第2节

BLE协议栈架构:从Controller到Application

BLE协议栈,说白了就是一套分层软件。我刚开始接触时也觉得层数太多,但后来发现,这种分层设计恰恰是BLE灵活性的根源。

整个协议栈分三层:Controller、Host、Application。每一层各司其职,层与层之间通过标准接口通信。嗯,这里要注意,不同芯片厂商的实现可能不一样,但逻辑分层是统一的。

Controller层:硬件的管家

Controller层负责最底层的射频操作。它直接跟硬件打交道,处理收包、发包、时序这些脏活累活。

  • 物理层(PHY):调制解调、频率选择。BLE在2.4GHz频段工作,有40个信道。
  • 链路层(LL):状态机管理。控制设备在五种状态间切换:Standby、Advertising、Scanning、Initiating、Connected。
  • 直接测试模式:用于产测和认证,我一般用这个来快速验证射频性能。
我的习惯:调试Controller层问题时,我通常先看LL状态机是否正常跳转。有一次设备连不上,查了半天发现是LL层卡在Scanning状态,根本没进入Initiating——这种问题用逻辑分析仪一看就明白。

Host层:协议的大脑

Host层跑在CPU上,处理更高层的逻辑。它跟Controller之间通过HCI(Host Controller Interface)通信。HCI可以是UART、USB或者SDIO,我项目里用得最多的是UART。

Host层包含这些关键组件:

  • L2CAP:数据打包与分段重组。把上层大包切成小片,方便LL层传输。
  • SM(安全管理层):配对、绑定、加密。我踩过坑——配对失败往往不是SM的问题,而是LL层连接参数没协商好。
  • ATT:属性协议。定义了客户端-服务器模型,用来读写小数据。
  • GATT:基于ATT,定义了Profile和Service的结构。说白了,就是告诉别人「我这个设备能干什么」。
  • GAP:通用访问规范。管广播、扫描、连接这些事。

Application层:你的业务代码

这一层就是开发者写代码的地方。你定义Service、Characteristic,实现具体的业务逻辑。比如一个温度计,Application层就负责读传感器、更新温度值、通知手机。

关键认知:Application层不直接操作射频。它通过GATT/GAP接口跟Host层交互,Host再通过HCI告诉Controller干活。这种隔离让应用开发变得简单——你不需要懂射频时序,也能做出好用的BLE产品。

BLE角色:四种身份,各司其职

BLE定义了四种角色。我经常被问到:「我的设备该用哪种角色?」答案取决于你的应用场景。

角色 方向 典型设备 核心行为
Broadcaster 只发不收 信标、ibeacon 周期性广播数据,不连接
Observer 只收不发 扫描器、网关 监听广播包,不连接
Peripheral 可被连接 手环、传感器 广播并接受连接请求
Central 主动连接 手机、平板 扫描并发起连接

你想想看,一个UWB定位标签,它应该是什么角色?如果它只需要上报位置,那Broadcaster就够了。但如果它需要接收配置参数,那就得是Peripheral,等手机来连。

我曾经踩过的坑:一个项目里把标签设成了Broadcaster,后来客户要求远程改配置,结果发现Broadcaster根本不支持连接。只能改固件,重新过认证。所以,设计初期就要想清楚:你的设备需不需要双向通信?

BLE通信流程:从广播到数据传输

BLE的通信流程,我习惯把它拆成四个阶段。每个阶段都有它的技术细节和坑点。

第一阶段:广播

Peripheral(或Broadcaster)在三个广播信道(37/38/39)上发广播包。广播包分两种:

  • 可连接广播:告诉别人「我可以被连」
  • 不可连接广播:只发数据,不接受连接

广播间隔是个关键参数。间隔越短,被发现越快,但功耗越高。我一般设100ms到1s之间,看应用场景。

第二阶段:扫描

Central(或Observer)在广播信道上监听。扫描分两种模式:

  • 被动扫描:只听,不发
  • 主动扫描:听到广播后,发扫描请求,获取更多数据

嗯,这里要注意:主动扫描会多耗电,但能拿到设备名、服务UUID这些信息。

第三阶段:连接

Central发连接请求,Peripheral接受。连接建立后,双方在数据信道上通信。连接参数包括:

  • 连接间隔:7.5ms到4s,决定了通信频率
  • 延迟:允许Peripheral跳过几个连接事件来省电
  • 超时时间:多久没收到包就断开
我的建议:连接参数要在连接建立后协商,不要硬编码。不同手机对连接间隔的容忍度不一样,我遇到过某款手机只能接受30ms以上的间隔,设短了直接断连。

第四阶段:数据传输

连接建立后,通过GATT的Service和Characteristic来读写数据。常用操作:

  • Read:Central读Peripheral的属性值
  • Write:Central写数据到Peripheral
  • Notify:Peripheral主动推数据给Central(不需要Central确认)
  • Indicate:Peripheral主动推数据,Central必须确认

我项目中90%的场景用Notify就够了。Indicate虽然可靠,但吞吐量低一半,因为每次都要等确认。

BLE协议栈架构图

下面这张图是我自己画的,把协议栈分层和角色关系串在一起。你看完应该能对整个体系有个直观印象。

BLE协议栈架构与角色关系 Application 层 你的业务代码、Profile、Service Host 层 GAP | GATT | ATT | SM | L2CAP 协议逻辑、安全管理、数据封装 HCI 接口(UART/USB/SDIO) Controller 层 链路层(LL)状态机 物理层(PHY)调制解调 射频硬件 BLE 四种角色 Broadcaster 只发广播,不连接 Observer 只收广播,不连接 Peripheral 广播 + 接受连接 Central 扫描 + 发起连接 通信流程 ① 广播(Advertising) ② 扫描(Scanning) ③ 连接(Connection) ④ 数据传输(GATT R/W/N/Ind)

小结

BLE协议栈的分层设计,让开发者可以专注在Application层写业务,不用操心射频细节。四种角色覆盖了从单向广播到双向连接的所有场景。通信流程的四个阶段,每一步都有参数可以调优。

我个人觉得,理解这些基础概念,比背API更重要。API会变,但协议栈的架构和角色逻辑不会变。你把这些吃透了,后面做UWB+BLE协同开发时,就知道哪些事该BLE干,哪些事该UWB干。