BLE 协议栈深入:从物理层到应用层的系统性拆解

文章目录

  • [BLE 协议栈深入:从物理层到应用层的系统性拆解](#BLE 协议栈深入:从物理层到应用层的系统性拆解)
    • [一、为什么 BLE 协议栈要分层](#一、为什么 BLE 协议栈要分层)
    • [二、BLE 协议栈整体架构](#二、BLE 协议栈整体架构)
      • [2.1 两大架构实现方案](#2.1 两大架构实现方案)
    • [三、Controller 层详解](#三、Controller 层详解)
      • [3.1 PHY 物理层](#3.1 PHY 物理层)
      • [3.2 Link Layer 链路层------BLE 的核心引擎](#3.2 Link Layer 链路层——BLE 的核心引擎)
        • [3.2.1 五种核心状态及转换](#3.2.1 五种核心状态及转换)
        • [3.2.2 Link Layer 数据包结构](#3.2.2 Link Layer 数据包结构)
        • [3.2.3 Link Layer 的关键职责清单](#3.2.3 Link Layer 的关键职责清单)
    • [四、HCI 主机控制器接口](#四、HCI 主机控制器接口)
      • [4.1 HCI 的三种数据包类型](#4.1 HCI 的三种数据包类型)
      • [4.2 常见 HCI LE 命令示例](#4.2 常见 HCI LE 命令示例)
      • [4.3 HCI 的物理传输方式](#4.3 HCI 的物理传输方式)
      • [4.4 HCI 的调试价值](#4.4 HCI 的调试价值)
    • [五、Host 层详解](#五、Host 层详解)
      • [5.1 L2CAP --- 逻辑链路控制与适配协议](#5.1 L2CAP — 逻辑链路控制与适配协议)
      • [5.2 ATT --- 属性协议(GATT 的底层传输)](#5.2 ATT — 属性协议(GATT 的底层传输))
        • [5.2.1 属性(Attribute)的定义](#5.2.1 属性(Attribute)的定义)
        • [5.2.2 六种 ATT 操作原语](#5.2.2 六种 ATT 操作原语)
      • [5.3 SMP --- 安全管理器协议](#5.3 SMP — 安全管理器协议)
      • [5.4 GAP --- 通用访问配置文件](#5.4 GAP — 通用访问配置文件)
      • [5.5 GATT --- 通用属性配置文件](#5.5 GATT — 通用属性配置文件)
    • 六、与经典蓝牙协议栈的结构对比
    • 七、数据流实战:一个温度值是怎么发出去的
      • [7.1 发送端:逐层封包](#7.1 发送端:逐层封包)
      • [7.2 接收端:逐层解包](#7.2 接收端:逐层解包)
    • 八、阶段检查点
    • 九、动手实验
      • [实验 1:用 nRF Connect 抓取并解析广播包](#实验 1:用 nRF Connect 抓取并解析广播包)
      • [实验 2:观察 HCI 日志](#实验 2:观察 HCI 日志)
        • [方案 A:Android HCI Snoop Log(无需额外硬件)](#方案 A:Android HCI Snoop Log(无需额外硬件))
        • [方案 B:Wireshark + nRF52840 Dongle 空口抓包(推荐进阶)](#方案 B:Wireshark + nRF52840 Dongle 空口抓包(推荐进阶))
      • [实验 3:对比 BLE 和经典蓝牙的 L2CAP](#实验 3:对比 BLE 和经典蓝牙的 L2CAP)
    • 十、推荐学习资源

BLE 协议栈深入:从物理层到应用层的系统性拆解

一、为什么 BLE 协议栈要分层

在深入每一层之前,先回答一个根本问题:协议栈为什么要分层?

蓝牙协议栈本质上是一套"信封嵌套系统"------你的应用数据(比如一个温度值 0x1A)从应用层出发,每经过一层就被包裹一层帧头/帧尾,最终变成一个满足 BLE 空中接口规范的数据包发射出去。接收端则逐层剥离,还原出原始数据。

这种分层设计带来三个核心好处:

好处 说明
关注点分离 每层只负责自己的事,PHY 管射频、LL 管时序、GATT 管数据组织
可替换性 Controller 和 Host 可以来自不同厂商,只要 HCI 接口一致就能协同工作
调试友好 出问题时逐层排查,HCI 日志是 Host/Controller 的天然分界线

与 TCP/IP 协议栈类比:BLE 的 PHY+LL 对应物理层+数据链路层,L2CAP 对应传输层,ATT/GATT 对应应用层协议。但 BLE 多了一个关键差异------安全(SMP)内嵌在协议栈中,而 TCP/IP 的安全(TLS)是后来叠加的。


二、BLE 协议栈整体架构

BLE 协议栈分为三大模块:Controller(控制器) 、HCI(主机控制器接口) 、Host(主机)。
#mermaid-svg-XH2XyIl7volPto1N{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XH2XyIl7volPto1N .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XH2XyIl7volPto1N .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XH2XyIl7volPto1N .error-icon{fill:#552222;}#mermaid-svg-XH2XyIl7volPto1N .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XH2XyIl7volPto1N .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XH2XyIl7volPto1N .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XH2XyIl7volPto1N .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XH2XyIl7volPto1N .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XH2XyIl7volPto1N .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XH2XyIl7volPto1N .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XH2XyIl7volPto1N .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XH2XyIl7volPto1N .marker.cross{stroke:#333333;}#mermaid-svg-XH2XyIl7volPto1N svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XH2XyIl7volPto1N p{margin:0;}#mermaid-svg-XH2XyIl7volPto1N .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-XH2XyIl7volPto1N .cluster-label text{fill:#333;}#mermaid-svg-XH2XyIl7volPto1N .cluster-label span{color:#333;}#mermaid-svg-XH2XyIl7volPto1N .cluster-label span p{background-color:transparent;}#mermaid-svg-XH2XyIl7volPto1N .label text,#mermaid-svg-XH2XyIl7volPto1N span{fill:#333;color:#333;}#mermaid-svg-XH2XyIl7volPto1N .node rect,#mermaid-svg-XH2XyIl7volPto1N .node circle,#mermaid-svg-XH2XyIl7volPto1N .node ellipse,#mermaid-svg-XH2XyIl7volPto1N .node polygon,#mermaid-svg-XH2XyIl7volPto1N .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XH2XyIl7volPto1N .rough-node .label text,#mermaid-svg-XH2XyIl7volPto1N .node .label text,#mermaid-svg-XH2XyIl7volPto1N .image-shape .label,#mermaid-svg-XH2XyIl7volPto1N .icon-shape .label{text-anchor:middle;}#mermaid-svg-XH2XyIl7volPto1N .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-XH2XyIl7volPto1N .rough-node .label,#mermaid-svg-XH2XyIl7volPto1N .node .label,#mermaid-svg-XH2XyIl7volPto1N .image-shape .label,#mermaid-svg-XH2XyIl7volPto1N .icon-shape .label{text-align:center;}#mermaid-svg-XH2XyIl7volPto1N .node.clickable{cursor:pointer;}#mermaid-svg-XH2XyIl7volPto1N .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-XH2XyIl7volPto1N .arrowheadPath{fill:#333333;}#mermaid-svg-XH2XyIl7volPto1N .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XH2XyIl7volPto1N .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-XH2XyIl7volPto1N .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XH2XyIl7volPto1N .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-XH2XyIl7volPto1N .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XH2XyIl7volPto1N .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-XH2XyIl7volPto1N .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-XH2XyIl7volPto1N .cluster text{fill:#333;}#mermaid-svg-XH2XyIl7volPto1N .cluster span{color:#333;}#mermaid-svg-XH2XyIl7volPto1N div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-XH2XyIl7volPto1N .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-XH2XyIl7volPto1N rect.text{fill:none;stroke-width:0;}#mermaid-svg-XH2XyIl7volPto1N .icon-shape,#mermaid-svg-XH2XyIl7volPto1N .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XH2XyIl7volPto1N .icon-shape p,#mermaid-svg-XH2XyIl7volPto1N .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-XH2XyIl7volPto1N .icon-shape rect,#mermaid-svg-XH2XyIl7volPto1N .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XH2XyIl7volPto1N .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-XH2XyIl7volPto1N .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-XH2XyIl7volPto1N :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Controller 层(控制器层)
接口层
Host 层(主机层)
应用层 Application
控制
安全
用户应用代码
GAP

通用访问配置文件

广播/扫描/连接管理
GATT

通用属性配置文件

服务/特征/描述符
SMP

安全管理器协议

配对/加密/密钥
ATT

属性协议

读/写/通知/指示
L2CAP

逻辑链路控制与适配协议

信道复用/分段重组
HCI

Host Controller Interface

标准化命令/事件/数据接口
Link Layer 链路层

状态机/连接管理/加密
Baseband 基带

时隙/跳频/时序
PHY 物理层

射频收发/GFSK调制

2.1 两大架构实现方案

BLE 协议栈在硬件上有两种部署方式,理解这一点对后续开发选型至关重要:

方案 架构 特点 典型芯片
单芯片(SoC) Host + Controller 集成在同一 MCU 体积小、功耗最低、成本最低 Nordic nRF52840、TI CC2640R2F
双芯片(NCP) Controller 独立芯片 + 外部 Host MCU 灵活度高,Host 可跑 Linux/Android CSR8510 + Linux BlueZ

在单芯片方案中,HCI 层退化为内部函数调用和消息队列,不经过物理总线。在双芯片方案中,HCI 通过 UART/USB/SPI 传输,命令和数据格式严格遵循 Bluetooth Core Specification 定义。


三、Controller 层详解

Controller 是 BLE 协议栈的"硬件核心",直接管理射频链路和底层连接控制。它包含两个子层:**PHY(物理层)**和 Link Layer(链路层)。

3.1 PHY 物理层

学习要点 详情 与经典蓝牙对比
调制方式 GFSK(高斯频移键控),与 BR 相同 经典蓝牙有 EDR 的 π/4-DQPSK / 8DPSK
频偏容限 ±150 KHz(比 BR 的 ±75 KHz 宽松一倍) 允许使用低成本晶体振荡器
发射功率 -20 ~ +20 dBm(5.0 后放宽) 经典蓝牙 Class 1 为 +20 dBm
接收灵敏度 规范要求 > -70 dBm,实际芯片 -90 ~ -100 dBm 取决于芯片设计

为什么 BLE 不用 EDR 高阶调制? 这是一个有意的设计取舍。π/4-DQPSK 和 8DPSK 虽然能提高速率(2/3 Mbps),但对射频前端的线性度要求更高,直接推高功耗和芯片成本。BLE 的设计目标是"纽扣电池供电数年",因此放弃了速率换取功耗和成本优势。

Link Layer 是整个 BLE 协议栈最重要、最复杂的一层。 它负责管理射频状态、数据包收发、连接时序、加密等几乎所有底层操作。Nordic 的 BLE 协议栈能同时支持 20 路连接,核心能力就在 LL 层。

3.2.1 五种核心状态及转换

#mermaid-svg-24qHF0vCRPJ3pQrE{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-24qHF0vCRPJ3pQrE .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-24qHF0vCRPJ3pQrE .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-24qHF0vCRPJ3pQrE .error-icon{fill:#552222;}#mermaid-svg-24qHF0vCRPJ3pQrE .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-24qHF0vCRPJ3pQrE .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-24qHF0vCRPJ3pQrE .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-24qHF0vCRPJ3pQrE .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-24qHF0vCRPJ3pQrE .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-24qHF0vCRPJ3pQrE .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-24qHF0vCRPJ3pQrE .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-24qHF0vCRPJ3pQrE .marker{fill:#333333;stroke:#333333;}#mermaid-svg-24qHF0vCRPJ3pQrE .marker.cross{stroke:#333333;}#mermaid-svg-24qHF0vCRPJ3pQrE svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-24qHF0vCRPJ3pQrE p{margin:0;}#mermaid-svg-24qHF0vCRPJ3pQrE defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-24qHF0vCRPJ3pQrE g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-24qHF0vCRPJ3pQrE g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-24qHF0vCRPJ3pQrE g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-24qHF0vCRPJ3pQrE g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-24qHF0vCRPJ3pQrE g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-24qHF0vCRPJ3pQrE .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-24qHF0vCRPJ3pQrE .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-24qHF0vCRPJ3pQrE .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-24qHF0vCRPJ3pQrE .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-24qHF0vCRPJ3pQrE .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-24qHF0vCRPJ3pQrE .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-24qHF0vCRPJ3pQrE .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-24qHF0vCRPJ3pQrE .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-24qHF0vCRPJ3pQrE .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-24qHF0vCRPJ3pQrE .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-24qHF0vCRPJ3pQrE .edgeLabel .label text{fill:#333;}#mermaid-svg-24qHF0vCRPJ3pQrE .label div .edgeLabel{color:#333;}#mermaid-svg-24qHF0vCRPJ3pQrE .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-24qHF0vCRPJ3pQrE .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-24qHF0vCRPJ3pQrE .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-24qHF0vCRPJ3pQrE .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-24qHF0vCRPJ3pQrE .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-24qHF0vCRPJ3pQrE .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-24qHF0vCRPJ3pQrE .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-24qHF0vCRPJ3pQrE #statediagram-barbEnd{fill:#333333;}#mermaid-svg-24qHF0vCRPJ3pQrE .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-24qHF0vCRPJ3pQrE .cluster-label,#mermaid-svg-24qHF0vCRPJ3pQrE .nodeLabel{color:#131300;}#mermaid-svg-24qHF0vCRPJ3pQrE .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-24qHF0vCRPJ3pQrE .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-24qHF0vCRPJ3pQrE .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-24qHF0vCRPJ3pQrE .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-24qHF0vCRPJ3pQrE .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-24qHF0vCRPJ3pQrE .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-24qHF0vCRPJ3pQrE .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-24qHF0vCRPJ3pQrE .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-24qHF0vCRPJ3pQrE .note-edge{stroke-dasharray:5;}#mermaid-svg-24qHF0vCRPJ3pQrE .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-24qHF0vCRPJ3pQrE .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-24qHF0vCRPJ3pQrE .statediagram-note text{fill:black;}#mermaid-svg-24qHF0vCRPJ3pQrE .statediagram-note .nodeLabel{color:black;}#mermaid-svg-24qHF0vCRPJ3pQrE .statediagram .edgeLabel{color:red;}#mermaid-svg-24qHF0vCRPJ3pQrE #dependencyStart,#mermaid-svg-24qHF0vCRPJ3pQrE #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-24qHF0vCRPJ3pQrE .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-24qHF0vCRPJ3pQrE :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Standby Connected 上电初始化
Host 命令启动广播
Host 命令启动扫描
Host 命令发起连接
收到 CONNECT_IND
广播超时 / Host 命令停止
发现目标设备
扫描超时 / Host 命令停止
连接建立成功
连接超时 / Host 命令取消
连接断开
Advertising 发送广播包后
等待下一个广播事件
SendADV
ListenResponse
Scanning 主动扫描模式
收到 Scan Response
ListenADV
SendScanReq
Initiating
Idle
不发送也不接收\n功耗最低(μA级)
Master_or_Slave
按 Connection Interval\n周期性收发数据

各状态详解:

状态 核心动作 功耗特征 进入条件 退出条件
Standby 空闲等待 最低(μA 级) 上电默认态 / 任何状态完成操作后 Host 命令触发
Advertising 周期性在 37/38/39 信道发送广播包 取决于广播间隔(20ms ~ 10.24s) Host 命令启动 收到 CONNECT_IND → Connected;超时 → Standby
Scanning 周期性监听广播信道 取决于扫描窗口/间隔比 Host 命令启动 发现目标 → Initiating;超时 → Standby
Initiating 向目标设备发送 CONNECT_IND 短时高功耗 扫描发现目标 连接成功 → Connected;超时 → Standby
Connected 按 Connection Interval 在数据信道收发 取决于连接间隔和负载 Advertising 或 Initiating 完成连接 连接断开 → Standby

动手练习:不看任何参考资料,徒手画出五种状态及全部转换路径,标注每个转换的触发事件。这是面试和排障的高频考点。

BLE 的空中数据包(Air Packet)由 LL 层构建,结构如下:

复制代码
┌──────────┬────────────────┬─────────────────────────────┬──────────┐
│ Preamble │ Access Address │     Protocol Data Unit      │   CRC    │
│ (1 byte) │   (4 bytes)    │                             │ (3 bytes)│
│          │                │ ┌────────┬────────────────┐ │          │
│          │                │ │ Header │    Payload     │ │          │
│          │                │ │(2 byte)│  (0-255 byte)  │ │          │
│          │                │ └────────┴────────────────┘ │          │
└──────────┴────────────────┴─────────────────────────────┴──────────┘
字段 长度 作用
Preamble 1 byte 前导码(0xAA 或 0x55),用于接收端时钟同步
Access Address 4 bytes 广播包固定 0x8E89BED6;数据包为随机生成的连接标识
LL Header 2 bytes 包含 PDU Type(数据包类型)、Length(载荷长度)等控制信息
Payload 0--255 bytes 实际数据或控制指令
CRC 3 bytes 24 位循环冗余校验,保证数据完整性

关键理解 :广播包的 Access Address 是固定值 0x8E89BED6,意味着"发给所有人"。连接建立后,双方会协商一个随机的 Access Address,只属于这对连接------这就是 BLE 实现"一对一私密通信"的基础。

职责 说明
信道选择 广播用 37/38/39 固定信道;连接后用自适应跳频(AFH)在 37 个数据信道间切换
数据包识别 通过 Access Address 判断数据包是否属于自己
时序管理 控制广播间隔、扫描窗口、连接间隔等所有时间参数
数据完整性 CRC-24 校验,检测传输错误
ACK 与重传 连接状态下的确认应答和自动重传机制
链路加密 LL 层提供 AES-CCM 加密和认证(密钥由上层 SMP 协商生成)
连接管理 连接参数更新、PHY 更新、数据长度扩展等控制流程

四、HCI 主机控制器接口

HCI 是 Host 和 Controller 之间的标准化通信接口,它的存在使得不同厂商的 Host 和 Controller 可以互换使用。

4.1 HCI 的三种数据包类型

包类型 方向 标识 说明
Command Host → Controller 0x01 主机向控制器发送命令(如"启动广播""建立连接")
Event Controller → Host 0x04 控制器向主机报告状态(如"连接成功""数据到达")
ACL Data 双向 0x02 用户数据在 Host 和 Controller 之间传输

4.2 常见 HCI LE 命令示例

HCI 命令 功能 使用场景
LE Set Advertising Parameters 设置广播间隔、类型、信道 配置外设广播行为
LE Set Advertising Data 设置广播载荷内容 填入设备名、服务 UUID 等
LE Set Scan Parameters 设置扫描窗口、间隔、类型 配置主机扫描行为
LE Create Connection 向指定设备发起连接请求 建立 BLE 连接
LE Read White List Size 读取白名单容量 设备过滤
LE Set Data Length 设置数据长度扩展参数 优化吞吐量(DLE)

4.3 HCI 的物理传输方式

传输方式 特点 典型场景
UART 成本低,最常用 嵌入式双芯片方案
USB 高速,即插即用 PC 端蓝牙适配器
SPI 高速,但线序较多 部分嵌入式设计
SDIO 高速,常用于 combo 芯片 Wi-Fi + BT 组合模块

4.4 HCI 的调试价值

HCI 日志是排障的第一手资料。 当你遇到 BLE 问题时,第一反应应该是:

"问题出在 Controller 还是 Host?"

判断方法很简单------看 HCI 边界:

  • HCI 命令正确,但 Controller 返回异常 → 问题在 Controller(射频/时序/硬件)
  • HCI 命令本身就有问题 → 问题在 Host(应用层/协议栈逻辑)

五、Host 层详解

Host 层是 BLE 协议栈的"智慧中枢",运行在设备的主处理器上,承载协议栈中大部分逻辑处理与决策功能。它由 5 个协议/配置文件组成:

5.1 L2CAP --- 逻辑链路控制与适配协议

L2CAP 是 Host 层的"交通调度员",位于 LL 层之上,为上层协议提供数据封装和多路复用服务。

功能 BLE 中的实现 与经典蓝牙对比
信道复用 CID(Channel ID)分配:ATT=0x0004,SMP=0x0006 经典蓝牙用 PSM
分段重组 将上层大数据包分割为 LL 层可承载的小包 经典蓝牙最大 65535 字节
流控 Basic Mode + LE Credit Based Flow Control 经典蓝牙有 Basic/ERTM/Streaming 三种
MTU 默认 23 字节,最大 517 字节 经典蓝牙默认 672 字节

信道标识符(CID)速查:

CID 值 分配给
0x0001 L2CAP 信令通道
0x0004 ATT(属性协议)
0x0005 LE L2CAP Connection Oriented Channel
0x0006 SMP(安全管理器协议)
0x0007 SMP over BR/EDR

实际开发中你很少直接操作 L2CAP------协议栈会帮你处理分段/重组和信道分配。但理解它的存在很重要,因为当你在 Wireshark 中看到 L2CAP 层的分段信息时,需要知道它是怎么回事来的。

5.2 ATT --- 属性协议(GATT 的底层传输)

ATT 是 BLE 数据交互的"传输管道",定义了 Client 和 Server 之间传递属性信息的 6 种基本操作原语。

5.2.1 属性(Attribute)的定义

每个属性是一个四元组:

复制代码
Attribute = Handle (16-bit) + Type (UUID) + Value (变长) + Permissions
字段 说明
Handle 16 位句柄,是该属性在属性表中的唯一索引(类似数组下标)
Type UUID,标识该属性的类型(如 0x2A37 = Heart Rate Measurement)
Value 实际数据(如心率值 72)
Permissions 读/写/加密等访问权限
5.2.2 六种 ATT 操作原语
操作 方向 确认 说明
Read Client → Server 有 Response 读取属性值
Write Client → Server 有 Response 写入属性值(可靠)
Write Without Response Client → Server 无 Response 写入属性值(快速,不可靠)
Notification Server → Client 无 Confirmation 服务器主动推送(高效)
Indication Server → Client 有 Confirmation 服务器主动推送(可靠)
Read Multiple Client → Server 有 Response 批量读取多个属性

ATT 与 GATT 的关系------这是初学者最容易混淆的概念:

复制代码
ATT 是传输管道(类似 HTTP 协议)
  → 定义了"怎么传"(读/写/通知等操作原语)

GATT 是上层数据组织方式(类似 RESTful API)
  → 定义了"传什么"(Service/Characteristic/Descriptor 的层级结构)

没有 GATT,ATT 依然能工作,但对端设备不知道你的属性是什么意思------是温度?是电量?还是一个控制指令?GATT 通过标准化的 Service/Characteristic 结构解决了这个互操作性问题。

5.3 SMP --- 安全管理器协议

SMP 负责 BLE 连接的加密和安全,定义配对和密钥分发协议。它的主要功能包括:

功能 说明
配对 两台设备建立信任关系的过程
加密 使用 AES-CCM 对链路层数据进行加密
密钥管理 生成、分发和存储 LTK、IRK、CSRK 等密钥
隐私保护 支持 RPA(可解析私有地址)防止设备追踪

SMP 的详细内容将在第四阶段(安全机制) 中系统展开。这里只需要记住:SMP 位于 Host 层,通过 L2CAP 的 CID 0x0006 信道传输,最终为 Link Layer 提供加密密钥。

5.4 GAP --- 通用访问配置文件

GAP 是 Host 层中最接近应用层的一层,负责设备的对外交互行为:

功能 说明
设备发现 广播和扫描的流程定义
连接建立 从广播到连接的完整流程管理
安全等级 定义 4 个安全等级(Level 1--4)
设备角色 定义 Peripheral/Central/Broadcaster/Observer 四种角色

GAP 的详细内容将在第三阶段(GAP 与 GATT) 中系统展开。

5.5 GATT --- 通用属性配置文件

GATT 建立在 ATT 之上,用层级结构组织属性数据:

复制代码
Profile(配置文件)
 └── Service(服务)          ← 例: Heart Rate Service (0x180D)
      ├── Characteristic(特征) ← 例: Heart Rate Measurement (0x2A37)
      │    └── Descriptor(描述符)← 例: CCCD (0x2902)
      └── Characteristic
           └── Descriptor

GATT 是 BLE 开发中最常打交道的协议层,实际工作中 80% 的问题出在这一层。详细内容将在第三阶段系统展开。


六、与经典蓝牙协议栈的结构对比

对于有经典蓝牙基础的开发者,以下对比表能帮你快速建立 BLE 的知识映射:

经典蓝牙独有 BLE 独有 共有但实现不同
SDP(服务发现) GATT(属性模型) L2CAP
RFCOMM(串口仿真) ATT(属性协议) SMP / 安全
SCO/eSCO(同步语音链路) --- HCI
Inquiry / Page 流程 Advertising / Scanning ---
LMP(链路管理协议) LL Control PDU ---
A2DP / HFP / PBAP Health Thermometer / Battery 等 GAP

核心差异总结:

  1. 服务发现机制不同:经典蓝牙用 SDP(基于查询-响应),BLE 用 GATT(基于属性浏览)。GATT 更轻量,适合资源受限设备。
  2. 连接建立方式不同:经典蓝牙走 Inquiry → Page → 连接(耗时数秒),BLE 走 Advertising → CONNECT_IND(耗时数毫秒)。
  3. 没有语音链路:BLE 4.x 没有 SCO/eSCO 等价物,直到 BLE 5.2 引入 LE Audio(CIS/BIS)才补齐音频能力。
  4. 协议栈更精简:BLE 去掉了 RFCOMM、SDP、LMP 等经典蓝牙独有的协议层,整体栈深度更浅,实现更简单。

七、数据流实战:一个温度值是怎么发出去的

理解协议栈最好的方式,是跟踪一个真实数据的传输过程。假设设备 A(Peripheral)要把当前温度 25°C(十六进制 0x19)发送给设备 B(Central)。

7.1 发送端:逐层封包

#mermaid-svg-F4RJIDVmRSju8SVZ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-F4RJIDVmRSju8SVZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-F4RJIDVmRSju8SVZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-F4RJIDVmRSju8SVZ .error-icon{fill:#552222;}#mermaid-svg-F4RJIDVmRSju8SVZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-F4RJIDVmRSju8SVZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-F4RJIDVmRSju8SVZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-F4RJIDVmRSju8SVZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-F4RJIDVmRSju8SVZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-F4RJIDVmRSju8SVZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-F4RJIDVmRSju8SVZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-F4RJIDVmRSju8SVZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-F4RJIDVmRSju8SVZ .marker.cross{stroke:#333333;}#mermaid-svg-F4RJIDVmRSju8SVZ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-F4RJIDVmRSju8SVZ p{margin:0;}#mermaid-svg-F4RJIDVmRSju8SVZ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-F4RJIDVmRSju8SVZ .cluster-label text{fill:#333;}#mermaid-svg-F4RJIDVmRSju8SVZ .cluster-label span{color:#333;}#mermaid-svg-F4RJIDVmRSju8SVZ .cluster-label span p{background-color:transparent;}#mermaid-svg-F4RJIDVmRSju8SVZ .label text,#mermaid-svg-F4RJIDVmRSju8SVZ span{fill:#333;color:#333;}#mermaid-svg-F4RJIDVmRSju8SVZ .node rect,#mermaid-svg-F4RJIDVmRSju8SVZ .node circle,#mermaid-svg-F4RJIDVmRSju8SVZ .node ellipse,#mermaid-svg-F4RJIDVmRSju8SVZ .node polygon,#mermaid-svg-F4RJIDVmRSju8SVZ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-F4RJIDVmRSju8SVZ .rough-node .label text,#mermaid-svg-F4RJIDVmRSju8SVZ .node .label text,#mermaid-svg-F4RJIDVmRSju8SVZ .image-shape .label,#mermaid-svg-F4RJIDVmRSju8SVZ .icon-shape .label{text-anchor:middle;}#mermaid-svg-F4RJIDVmRSju8SVZ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-F4RJIDVmRSju8SVZ .rough-node .label,#mermaid-svg-F4RJIDVmRSju8SVZ .node .label,#mermaid-svg-F4RJIDVmRSju8SVZ .image-shape .label,#mermaid-svg-F4RJIDVmRSju8SVZ .icon-shape .label{text-align:center;}#mermaid-svg-F4RJIDVmRSju8SVZ .node.clickable{cursor:pointer;}#mermaid-svg-F4RJIDVmRSju8SVZ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-F4RJIDVmRSju8SVZ .arrowheadPath{fill:#333333;}#mermaid-svg-F4RJIDVmRSju8SVZ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-F4RJIDVmRSju8SVZ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-F4RJIDVmRSju8SVZ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-F4RJIDVmRSju8SVZ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-F4RJIDVmRSju8SVZ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-F4RJIDVmRSju8SVZ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-F4RJIDVmRSju8SVZ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-F4RJIDVmRSju8SVZ .cluster text{fill:#333;}#mermaid-svg-F4RJIDVmRSju8SVZ .cluster span{color:#333;}#mermaid-svg-F4RJIDVmRSju8SVZ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-F4RJIDVmRSju8SVZ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-F4RJIDVmRSju8SVZ rect.text{fill:none;stroke-width:0;}#mermaid-svg-F4RJIDVmRSju8SVZ .icon-shape,#mermaid-svg-F4RJIDVmRSju8SVZ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-F4RJIDVmRSju8SVZ .icon-shape p,#mermaid-svg-F4RJIDVmRSju8SVZ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-F4RJIDVmRSju8SVZ .icon-shape rect,#mermaid-svg-F4RJIDVmRSju8SVZ .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-F4RJIDVmRSju8SVZ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-F4RJIDVmRSju8SVZ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-F4RJIDVmRSju8SVZ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 调用 API

bt_gatt_notify()
组织为 Characteristic

Handle=0x0015, UUID=0x2A6E
选择操作类型

Notification Opcode=0x1B

数据包: 1B 15 00 19
添加 L2CAP Header

Length=0x0004, CID=0x0004

数据包: 04 00 04 00 1B 15 00 19
添加 LL Header + Access Address

  • CRC-24
    GFSK 调制

在数据信道上发射
应用层

温度值 = 0x19
GATT
ATT
L2CAP
LL
PHY
空中射频信号

7.2 接收端:逐层解包

接收端的流程完全对称:

层 操作
PHY GFSK 解调,还原比特流
LL 校验 Access Address(是否是发给我的)→ 校验 CRC(数据是否完整)→ 剥离 LL Header
L2CAP 根据 CID=0x0004 知道载荷属于 ATT → 重组分段(如有)→ 剥离 L2CAP Header
ATT 根据 Opcode=0x1B 识别为 Notification → 提取 Handle=0x0015 和 Value=0x19
GATT 根据 Handle=0x0015 找到 Temperature Measurement Characteristic → 解析值 0x19 = 25°C
应用层 收到通知回调:on_temperature_changed(25)

这个流程理解透了,BLE 开发中遇到的大部分问题都能快速定位------因为你知道数据在哪一层出了问题。


八、阶段检查点

  • 能画出 BLE 协议栈 Host / Controller / HCI 三层架构图,并说出每层包含的协议
  • 能画出 Link Layer 五种状态的完整转换图,标注每种转换的触发条件
  • 能解释 Access Address 在广播包和数据包中的不同作用
  • 能解释 ATT 与 GATT 的关系(类比 TCP 与 HTTP / 管道与数据组织)
  • 能列出 BLE 协议栈与经典蓝牙协议栈的至少 5 个结构性差异
  • 能跟踪一个数据值从应用层到射频发射的完整封包流程
  • 知道 HCI 日志的用途,以及如何使用它来定位 Host vs Controller 问题

九、动手实验

实验 1:用 nRF Connect 抓取并解析广播包

工具:nRF Connect for Mobile(Android / iOS 免费)

目标:直观看到 BLE 广播数据的 TLV 结构

步骤:

  1. 在手机上安装 nRF Connect(应用商店搜索 "nRF Connect for Mobile",开发者为 Nordic Semiconductor ASA)

nRF Connect 扫描到设备后显示设备名、MAC 地址、RSSI 信号强度

  1. 打开 App,点击右上角 SCAN 按钮开始扫描

  2. 在设备列表中找到任意一个 BLE 设备(如智能手环、空气净化器)

  3. 点击设备卡片展开,查看 Raw advertising data(原始广播数据)

  4. 手动按 TLV 格式解析十六进制数据:

    示例原始数据:02 01 06 09 08 4D 79 44 65 76 69 63 65

    解析:
    02 01 06
    ├── Length = 0x02 (2字节)
    ├── Type = 0x01 (Flags)
    └── Data = 0x06 (LE General Discoverable + BR/EDR Not Supported)

    09 08 4D 79 44 65 76 69 63 65
    ├── Length = 0x09 (9字节)
    ├── Type = 0x08 (Shortened Local Name)
    └── Data = "MyDevice" (ASCII)

预期收获:理解广播数据不是黑盒,而是由 Length-Type-Value 三元组组成的结构化数据。


实验 2:观察 HCI 日志

工具:Android 手机(需开发者模式)或 Wireshark + nRF Sniffer

目标:看到 Host 和 Controller 之间的真实 HCI 命令交互

方案 A:Android HCI Snoop Log(无需额外硬件)
  1. 进入手机 开发者选项 → 开启 启用蓝牙 HCI 信息收集日志

Android 开发者选项中的蓝牙 HCI 日志开关位置

  1. 打开蓝牙,用 nRF Connect 扫描并连接一个 BLE 设备
  2. 操作完成后关闭日志
  3. 将生成的 btsnoop_hci.log 文件传输到电脑
  4. 用 Wireshark 打开该文件

Wireshark 加载 HCI Snoop Log 后可以看到完整的命令/事件交互

  1. 在 Wireshark 过滤器中输入以下过滤表达式,分别观察:
    • bthci_cmd:只看 HCI 命令
    • bthci_evt:只看 HCI 事件
    • btle:只看 BLE 链路层数据包

你应该能看到的关键 HCI 命令:

命令 说明
LE Set Scan Parameters 设置扫描窗口/间隔
LE Set Scan Enable 启动扫描
LE Advertising Report 扫描到的广播设备报告
LE Create Connection 向目标设备发起连接
LE Connection Complete 连接建立完成事件
方案 B:Wireshark + nRF52840 Dongle 空口抓包(推荐进阶)

这是专业 BLE 开发者的标准抓包方案,能捕获空中的原始射频数据包。

硬件准备:

  • nRF52840 USB Dongle(约 ¥100)
  • 安装 nRF Sniffer 固件(从 Nordic GitHub 下载)

软件配置:

  1. 安装 Wireshark(≥ 3.2 版本)
  2. 安装 nRF Util 工具及 Sniffer 插件
  3. 将 Dongle 插入 USB,Wireshark 的捕获接口列表中会出现 "nRF Sniffer for Bluetooth LE"

Wireshark 捕获界面中显示的 nRF Sniffer for Bluetooth LE 接口

  1. 双击该接口开始捕获,你会看到周围所有 BLE 设备的空中数据包

常用 Wireshark 显示过滤器:

复制代码
# 只看广播包
btle.adv_header.type == 0x00

# 按设备地址过滤
btle.advertising_address == aa:bb:cc:dd:ee:ff

# 只看连接建立过程
btle.control_opcode == 0x05

# 只看 ATT 层数据
btatt

Wireshark 过滤 BTLE 协议后的数据包列表,可以看到 ADV_IND 等广播类型

预期收获:亲眼看到 LL 层的 Access Address、LL Header、PDU 结构,以及 HCI 命令的实际格式。这是理解协议栈最直接的方式。


实验 3:对比 BLE 和经典蓝牙的 L2CAP

工具 :Core Spec Vol 3, Part A(免费下载)

目标:理解 BLE L2CAP 与经典蓝牙 L2CAP 的关键差异

阅读要点:

  1. 翻到 Section 3(L2CAP Channel)
  2. 对比经典蓝牙的 3 种操作模式(Basic / ERTM / Streaming)与 BLE 的简化实现
  3. 重点关注:
    • 经典蓝牙的 PSM(Protocol/Service Multiplexer) 在 BLE 中被 CID(Channel ID) 替代
    • BLE 的 L2CAP MTU 默认只有 23 字节(经典蓝牙默认 672 字节)
    • BLE 5.2 引入的 CoC(Connection Oriented Channels) 提供了类似经典蓝牙 ERTM 的可靠传输

十、推荐学习资源

类型 资源 链接
官方规范 Bluetooth Core Spec v5.4 Vol 6 Part B(Link Layer) bluetooth.com/specifications
官方博客 深入浅出低功耗蓝牙协议栈 nordicsemi.cn/blog
培训课程 Nordic BLE 基础课程第一课 nordicsemi.cn 中文课程
芯片文档 TI BLE5-Stack Link Layer 指南 software-dl.ti.com
芯片文档 Silicon Labs BLE 架构说明 docs.silabs.com
工具 Wireshark BLE 显示过滤器参考 wireshark.org/docs/dfref/b/btle.html
工具 Nordic nRF Sniffer 使用指南 docs.nordicsemi.com

相关推荐
你怎么知道我是队长10 天前
经典蓝牙 - 中间人攻击(MIMT) - Method Confusion Attack(2021)
bluetooth
你怎么知道我是队长13 天前
经典蓝牙 - 安全机制 - Numeric Comparison和justwork的差异是什么?
bluetooth
你怎么知道我是队长23 天前
经典蓝牙(BR/EDR)核心流程详解:设备发现、连接建立、配对绑定与服务发现
bluetooth
rls_v1 个月前
jieli:I2S外设是如何工作的?
bluetooth
rls_v2 个月前
什么是蓝牙的信令测试
bluetooth
rls_v2 个月前
AC696X-双模蓝牙功耗与时隙分析
bluetooth
rls_v2 个月前
经典蓝牙音量同步机制
bluetooth
你怎么知道我是队长2 个月前
经典蓝牙(Classic Bluetooth / BR/EDR)--- 核心协议层5 --- 经典蓝牙(BR/EDR)服务发现层核心机制详解
bluetooth
你怎么知道我是队长2 个月前
经典蓝牙(Classic Bluetooth / BR/EDR)--- 核心协议层5 --- 经典蓝牙(BR/EDR)电缆替代协议层核心机制详解
bluetooth