目录

一、BLE 的由来与本质

1.1 什么是 BLE

1.2 BLE 的由来

1.3 BLE 与经典蓝牙的区别

1.4 BLE 的核心设计理念

1.5 BLE 与经典蓝牙的共存

1.6 BLE 的应用场景

二、BLE 协议分层架构

2.1 BLE 协议栈分层

2.2 物理层(PHY)

2.3 链路层(LL)

链路层数据包格式

跳频机制

2.4 L2CAP(逻辑链路控制与适配协议)

2.5 ATT(属性协议)

2.6 GATT(通用属性配置文件)

2.7 GAP(通用访问配置文件)

2.8 SMP(安全管理协议)

三、GAP 广播与扫描

3.1 广播类型

3.2 广播数据格式

3.3 扫描

3.4 连接建立

四、GATT 与 ATT

4.1 属性表

4.2 服务与特征的发现

4.3 通知与指示

4.4 UUID

4.5 ATT MTU 与数据传输

4.6 GATT 服务示例

4.7 标准服务与自定义服务

五、SMP 配对与安全

5.1 配对方法

5.2 LE Secure Connections

5.3 密钥分发

5.4 私有地址

5.5 加密与签名

5.6 安全最佳实践

六、计费与业务模型

6.1 BLE 本身的计费

6.2 蓝牙认证(BQB)

6.3 业务模型

6.4 功耗与成本

七、架构设计与关键机制

7.1 单芯片与双芯片架构

7.2 连接状态机

7.3 多连接管理

7.4 数据传输优化

7.5 低功耗模式

7.6 广播功率与距离

7.7 吞吐量与延迟

7.8 错误处理与重连

八、代码实现(改写版)

8.1 GATT 服务与特征定义

8.2 GAP 广播配置

8.3 连接参数与功耗管理

九、Linux 平台 BLE 实践

9.1 BlueZ 协议栈

9.2 Linux BLE 编程

BlueZ D-Bus 接口示例

9.3 Linux BLE 调试

十、Android 平台 BLE 实践

10.1 Android BLE 架构

10.2 Android BLE 扫描

10.3 Android BLE 连接与通信

10.4 Android BLE 功耗与兼容性

10.5 Android BLE 开发注意事项

10.6 Android GATT 服务器

十一、ESP/嵌入式平台 BLE 实践

11.1 ESP-IDF 的 BLE

11.2 Zephyr 的 BLE

11.3 Nordic SoftDevice

11.4 嵌入式 BLE 功耗优化

11.5 嵌入式 BLE 与 WiFi 共存

十二、多平台对比与选型建议

12.1 各平台 BLE 协议栈对比

12.2 选型建议

12.3 BLE 与其他无线技术的对比

十三、发展历程与未来趋势

13.1 BLE 的发展阶段

13.2 BLE Audio 的影响

13.3 BLE Mesh

13.4 未来趋势

13.5 总结

13.6 BLE 与其他无线技术的协作

13.7 BLE 在各行业的应用


一、BLE 的由来与本质

1.1 什么是 BLE

BLE(Bluetooth Low Energy,低功耗蓝牙)是蓝牙技术联盟(Bluetooth SIG)于 2010 年在蓝牙 4.0 规范中引入的低功耗无线通信技术。与经典蓝牙(Bluetooth Classic)相比,BLE 专注于低功耗、低复杂度、低成本,适用于物联网、可穿戴设备、智能家居等场景。

BLE 的本质是用极低的功耗实现短距离、低速率的无线通信。BLE 设备在不通信时处于深度睡眠状态,只在需要时短暂唤醒发送或接收数据,因此功耗可以低到微安级别,一粒纽扣电池可以使用数月甚至数年。

1.2 BLE 的由来

BLE 的前身是诺基亚在 2006 年开发的 Wibree 技术。2007 年,诺基亚与蓝牙技术联盟合作,将 Wibree 纳入蓝牙规范。2010 年,蓝牙 4.0 发布,Wibree 以 Bluetooth Low Energy 的名称正式成为蓝牙标准的一部分。

BLE 的设计目标与经典蓝牙完全不同:

  • 经典蓝牙:面向音频流和文件传输,追求高吞吐(可达 24 Mbps),功耗较高。

  • BLE:面向传感器和控制信号,追求低功耗,吞吐较低(最大约 2 Mbps,实际应用通常几十 Kbps)。

蓝牙 4.0 之后,BLE 持续演进:

  • 蓝牙 4.2(2014):引入数据包长度扩展(LE Data Length Extension),提高吞吐量。

  • 蓝牙 5(2016):引入 2 Mbps 物理层、长距离模式(Coded PHY)、广播扩展(Advertising Extensions)。

  • 蓝牙 5.1(2019):引入寻向功能(Direction Finding),支持厘米级定位。

  • 蓝牙 5.2(2020):引入 LE Isochronous Channels,支持低延迟音频。

  • 蓝牙 5.3(2021):优化连接建立和周期广播。

  • 蓝牙 5.4(2023):引入周期性广播响应,支持大规模设备配置。

1.3 BLE 与经典蓝牙的区别

维度经典蓝牙BLE
功耗高(几十 mA)极低(几 μA)
传输距离10-100 米10-100 米(长距离模式可达 1000 米)
吞吐率1-24 Mbps125 Kbps - 2 Mbps
连接延迟约 100 ms约 6 ms
网络拓扑微微网(1 主 7 从)星型、Mesh
典型应用耳机、音箱、文件传输传感器、可穿戴、智能家居
安全性SSPLE Secure Connections

1.4 BLE 的核心设计理念

BLE 的设计理念围绕"低功耗"展开:

  1. 快速连接:连接建立只需几毫秒,通信后立即断开,减少射频活动时间。

  2. 短数据包:数据包长度小,传输时间短,减少射频开启时间。

  3. 低占空比:设备大部分时间处于睡眠状态,只在广播或连接事件时唤醒。

  4. 跳频扩频:在 40 个信道上跳频,避免干扰,提高可靠性。

  5. 星型拓扑:一个主设备连接多个从设备,简化网络管理。

1.5 BLE 与经典蓝牙的共存

蓝牙 4.0 及以后的版本同时支持经典蓝牙和 BLE,称为双模(Dual Mode)蓝牙。双模设备可以同时与经典蓝牙设备和 BLE 设备通信。

还有单模(Single Mode)BLE 设备,只支持 BLE,不支持经典蓝牙。单模设备成本更低、功耗更低,但只能与 BLE 设备通信。

大多数智能手机和电脑是双模设备,大多数物联网传感器是单模设备。

1.6 BLE 的应用场景

BLE 的应用场景广泛,主要包括:

  • 可穿戴设备:智能手表、手环、心率带等,通过 BLE 与手机同步数据。

  • 智能家居:智能灯、门锁、温控器等,通过 BLE 与手机或网关通信。

  • 医疗健康:血糖仪、体温计、血压计等,通过 BLE 上传健康数据。

  • 资产追踪:BLE Beacon 用于室内定位和资产追踪。

  • 人机接口:蓝牙键盘、鼠标、遥控器等。

  • 近场支付:BLE 可以用于近场支付和门禁。


二、BLE 协议分层架构

2.1 BLE 协议栈分层

BLE 协议栈自下而上分为三层:

  1. 控制器层(Controller):包括物理层(PHY)和链路层(LL),负责射频收发、跳频、连接管理。

  2. 主机层(Host):包括 L2CAP、ATT、GATT、GAP、SMP,负责数据封装、服务发现、配对安全。

  3. 应用层(Application):具体的应用程序,定义自定义服务和特征。

控制器层和主机层之间通过 HCI(Host Controller Interface)通信。在单芯片方案中,HCI 是芯片内部接口;在双芯片方案中,HCI 可以是 UART、SPI 或 USB。

HCI 定义了主机和控制器之间的命令、事件和数据包格式。主机通过 HCI 命令控制控制器(如启动广播、发起连接),控制器通过 HCI 事件通知主机(如连接完成、断开),数据包通过 HCI ACL 或 HCI LE ACL 传输。

HCI 的标准化使得主机和控制器可以独立实现和替换,这是 BLE 生态繁荣的基础。

2.2 物理层(PHY)

BLE 物理层工作在 2.4 GHz ISM 频段,分为 40 个信道:

  • 3 个广播信道(37、38、39):用于设备发现和连接建立。

  • 37 个数据信道(0-36):用于连接后的数据传输,采用跳频。

BLE 支持多种物理层速率:

  • 1 Mbps:蓝牙 4.0 起支持,兼容所有 BLE 设备。

  • 2 Mbps:蓝牙 5 起支持,吞吐量加倍,适合音频和固件升级。

  • 125 Kbps / 500 Kbps(Coded PHY):蓝牙 5 起支持,长距离模式,通过前向纠错提高灵敏度。

2.3 链路层(LL)

链路层负责设备间的射频通信,主要功能包括:

  • 广播:设备定期在广播信道发送广播包,宣告自身存在。

  • 扫描:设备监听广播信道,发现周围设备。

  • 连接建立:发起方收到广播后发送连接请求,建立连接。

  • 跳频:连接建立后,双方按约定的跳频序列在数据信道间跳频。

  • 流控与重传:通过序列号和确认机制保证数据可靠传输。

  • 信道映射:根据信道质量,排除受干扰的信道。

链路层有五种状态:待机(Standby)、广播(Advertising)、扫描(Scanning)、发起(Initiating)、连接(Connection)。

链路层数据包格式

BLE 链路层数据包由四部分组成:

  • 前导码(Preamble):1 字节,用于接收机同步。1 Mbps PHY 为 0xAA,2 Mbps PHY 为 0x55。

  • 接入地址(Access Address):4 字节,标识数据包所属的连接。广播信道使用固定地址 0x8E89BED6,数据信道使用连接时协商的随机地址。

  • PDU(协议数据单元):2-257 字节,包含数据头和有效载荷。

  • CRC(循环冗余校验):3 字节,用于检错。

PDU 的头包含类型字段,标识数据包的类型(广播、扫描请求、连接请求、数据等)。

跳频机制

BLE 连接使用自适应跳频(Adaptive Frequency Hopping),在 37 个数据信道间跳频。跳频序列由中央设备生成,基于连接的接入地址和中央设备时钟。双方在连接事件中使用相同的跳频序列,保证能在相同信道上相遇。

自适应跳频会根据信道质量排除受干扰的信道。中央设备定期评估信道质量,将差的信道加入黑名单,跳频时跳过这些信道。

2.4 L2CAP(逻辑链路控制与适配协议)

L2CAP 位于链路层之上,提供多路复用和数据分片重组。BLE 的 L2CAP 支持两种信道:

  • 固定信道:用于 ATT(0x0004)、SMP(0x0006)、L2CAP 信令(0x0005)。

  • 动态信道:用于 LE Credit Based Flow Control Mode,支持自定义协议。

L2CAP 的数据单元称为 SDU(Service Data Unit),L2CAP 将 SDU 分片为链路层的 PDU(Protocol Data Unit)传输。

2.5 ATT(属性协议)

ATT 是 BLE 数据访问的基础协议,定义了客户端如何读取、写入、通知服务器上的属性。ATT 基于客户端-服务器模型:

  • 服务器(Server):持有属性数据,响应客户端请求。

  • 客户端(Client):读取或写入服务器的属性。

ATT 的操作包括:

  • Read:读取属性值。

  • Write:写入属性值。

  • Notify:服务器主动通知客户端属性变化(无确认)。

  • Indicate:服务器主动指示客户端属性变化(有确认)。

2.6 GATT(通用属性配置文件)

GATT 在 ATT 之上定义了数据的层次结构:

  • 服务(Service):一组相关的特征,代表一个功能模块。

  • 特征(Characteristic):一个数据项,包含值、属性、描述符。

  • 描述符(Descriptor):特征的附加信息,如客户端特性配置(CCCD)。

GATT 定义了多种标准服务(如电池服务、心率服务),厂商也可以定义自定义服务。

2.7 GAP(通用访问配置文件)

GAP 定义了设备如何发现、连接和管理连接。GAP 定义了四种设备角色:

  • 广播者(Broadcaster):只发送广播,不接受连接。

  • 观察者(Observer):只扫描广播,不发起连接。

  • 外设(Peripheral):广播并接受连接。

  • 中央(Central):扫描并发起连接。

GAP 还定义了广播数据格式、扫描响应格式、连接参数等。

2.8 SMP(安全管理协议)

SMP 负责设备配对和密钥分发,提供加密和认证。BLE 的配对流程包括:

  1. 配对特征交换:交换配对能力(输入输出能力、认证要求)。

  2. 密钥生成:根据配对方法生成短期密钥(STK)。

  3. 链路加密:使用 STK 加密链路。

  4. 密钥分发:分发长期密钥(LTK)、身份解析密钥(IRK)等。

BLE 4.2 引入 LE Secure Connections,使用 ECDH 密钥交换,防止中间人攻击。


三、GAP 广播与扫描

3.1 广播类型

BLE 定义了四种广播类型:

  • ADV_IND:可连接可扫描的非定向广播,最常用。

  • ADV_DIRECT_IND:定向广播,只向特定设备发送,用于快速重连。

  • ADV_NONCONN_IND:不可连接的广播,用于广播者角色(如 Beacon)。

  • ADV_SCAN_IND:可扫描但不可连接的广播。

3.2 广播数据格式

广播数据包最大 31 字节(蓝牙 5 扩展广播可达 255 字节),由多个 AD Structure 组成,每个结构包含长度、类型、数据。常见的 AD 类型包括:

  • Flags:设备模式(有限可发现、通用可发现等)。

  • Incomplete List of 16-bit Service UUIDs:设备支持的服务。

  • Complete Local Name:设备名称。

  • TX Power Level:发射功率。

  • Manufacturer Specific Data:厂商自定义数据。

3.3 扫描

扫描设备监听广播信道,接收广播包。扫描有两种模式:

  • 被动扫描:只接收广播包,不发送扫描请求。

  • 主动扫描:收到广播后发送扫描请求,获取扫描响应数据。

扫描参数包括扫描间隔(Scan Interval)和扫描窗口(Scan Window)。扫描间隔是两次扫描的间隔,扫描窗口是每次扫描的持续时间。占空比 = Scan Window / Scan Interval,占空比越高发现设备越快,但功耗越大。

3.4 连接建立

中央设备收到外设的广播后,可以发送连接请求(CONNECT_IND)。连接请求包含连接参数:

  • 连接间隔(Connection Interval):两次连接事件的间隔,7.5 ms - 4000 ms。

  • 从设备延迟(Slave Latency):从设备可以跳过的连接事件数。

  • 监管超时(Supervision Timeout):连接的超时时间。

连接建立后,双方按连接间隔在数据信道上跳频通信。


四、GATT 与 ATT

4.1 属性表

GATT 服务器维护一个属性表,每个属性包含:

  • 句柄(Handle):唯一标识,16 位。

  • 类型(Type):属性类型的 UUID(16 位或 128 位)。

  • 权限(Permissions):读、写、通知等权限。

  • 值(Value):属性数据。

属性表按句柄顺序排列,客户端通过句柄或类型访问属性。

4.2 服务与特征的发现

客户端连接后,需要发现服务器提供的服务和特征。发现过程使用 ATT 的 Read By Type Request:

  1. 发现主要服务:通过 Read By Group Type 请求获取所有服务。

  2. 发现特征:通过 Read By Type 请求获取服务中的特征。

  3. 发现描述符:通过 Find Information 请求获取特征的描述符。

发现完成后,客户端可以通过句柄直接读写特征值。

4.3 通知与指示

通知(Notify)和指示(Indicate)是服务器主动向客户端推送数据的方式:

  • 通知:服务器发送属性值,客户端不需要确认。适合不需要可靠传输的场景(如传感器数据)。

  • 指示:服务器发送属性值,客户端需要回复确认。适合需要可靠传输的场景。

客户端通过写入 CCCD(Client Characteristic Configuration Descriptor)来启用通知或指示。

4.4 UUID

UUID(通用唯一标识符)用于标识服务、特征和描述符。BLE 使用两种 UUID:

  • 16 位 UUID:蓝牙 SIG 定义的标准服务和特征,如电池服务(0x180F)。

  • 128 位 UUID:厂商自定义的服务和特征,保证全局唯一。

16 位 UUID 是 128 位 UUID 的简写,格式为 0000XXXX-0000-1000-8000-00805F9B34FB。

4.5 ATT MTU 与数据传输

ATT 的最大传输单元(MTU)决定了一次 ATT 操作能传输的最大数据量。默认 MTU 为 23 字节(1 字节操作码 + 20 字节数据)。连接后双方可以协商更大的 MTU,最大可达 247 字节(蓝牙 4.2+)。

增大 MTU 可以减少分包次数,提高数据传输效率。但 MTU 越大,单个数据包的传输时间越长,可能影响延迟。实际应用中需要根据数据大小和延迟要求选择合适的 MTU。

4.6 GATT 服务示例

以电池服务为例,GATT 层次结构如下:

电池服务(UUID: 0x180F)
  └── 电池电量特征(UUID: 0x2A19)
        ├── 值(0-100,表示电量百分比)
        └── CCCD 描述符(启用通知)

客户端连接后,通过发现服务获取电池服务的句柄,然后读取电池电量特征值,或启用通知以在电量变化时接收推送。

4.7 标准服务与自定义服务

蓝牙 SIG 定义了大量标准服务,覆盖常见应用场景:

  • 设备信息服务(0x180A):厂商名称、型号、序列号等。

  • 电池服务(0x180F):电池电量。

  • 心率服务(0x180D):心率数据。

  • 血压服务(0x1810):血压数据。

  • 环境传感服务(0x181A):温度、湿度等环境数据。

对于标准服务未覆盖的场景,厂商可以定义自定义服务,使用 128 位 UUID。自定义服务的 UUID 应随机生成,避免与其他厂商冲突。


五、SMP 配对与安全

5.1 配对方法

BLE 根据设备的输入输出能力选择配对方法:

  • Just Works:无输入输出,使用固定 PIN 码(000000)。安全性最低,适合无交互设备。

  • Passkey Entry:一端显示 6 位数字,另一端输入。适合有显示屏和键盘的设备。

  • Numeric Comparison:两端显示相同的 6 位数字,用户确认是否一致。适合有显示屏的设备。

  • Out of Band(OOB):通过其他信道(如 NFC)交换密钥。安全性最高。

5.2 LE Secure Connections

蓝牙 4.2 引入 LE Secure Connections,使用 ECDH(椭圆曲线 Diffie-Hellman)密钥交换,防止中间人攻击。配对流程:

  1. 双方交换公钥。

  2. 双方计算共享密钥。

  3. 双方根据配对方法生成确认值。

  4. 双方交换确认值并验证。

  5. 生成长期密钥(LTK)。

LE Secure Connections 提供前向保密(Forward Secrecy),即使 LTK 泄露,历史通信内容也无法解密。

5.3 密钥分发

配对完成后,双方分发以下密钥:

  • LTK(Long Term Key):用于链路加密。

  • IRK(Identity Resolving Key):用于解析私有地址。

  • CSRK(Connection Signature Resolving Key):用于数据签名。

  • EDIV(Encrypted Diversifier)和 Rand:用于 LTK 的标识。

这些密钥存储在双方的安全存储中,用于后续重连时快速加密。

5.4 私有地址

为防止设备被跟踪,BLE 支持私有地址(Private Address):

  • 静态私有地址:设备启动时随机生成,重启后变化。

  • 可解析私有地址:使用 IRK 生成,可以被配对的设备解析。

私有地址定期变化(默认 15 分钟),防止攻击者通过地址跟踪设备。

5.5 加密与签名

配对完成后,链路使用 AES-CCM 加密,提供机密性和完整性。加密密钥在配对时生成,存储在双方的安全存储中。

BLE 还支持数据签名(Signed Write),允许在未加密的链路上发送经过签名的写入命令。签名使用 CSRK 生成,接收方验证签名后执行写入。

5.6 安全最佳实践

在 BLE 应用中,应遵循以下安全最佳实践:

  • 使用 LE Secure Connections:启用安全配对,防止中间人攻击。

  • 加密关键特征:敏感特征(如密码、密钥)应要求加密后才能访问。

  • 限制广播数据:不要在广播中包含敏感信息。

  • 使用私有地址:启用可解析私有地址,防止被跟踪。

  • 安全存储密钥:配对密钥应存储在安全区域(如硬件加密区)。

  • 定期更换密钥:在某些场景下,定期重新配对可以降低密钥泄露的风险。


六、计费与业务模型

6.1 BLE 本身的计费

BLE 技术本身是开放标准,不需要支付专利费(蓝牙技术联盟成员可免费用)。但使用 BLE 需要:

  • 蓝牙认证:产品需要通过蓝牙认证(BQB),认证费用数千美元,确保互操作性。

  • 硬件成本:BLE 芯片的成本,从几毛钱到几十元不等。

  • 开发成本:BLE 协议栈的开发和集成成本。

6.2 蓝牙认证(BQB)

蓝牙认证(Bluetooth Qualification)是使用蓝牙技术的产品必须通过的认证。认证包括:

  • 测试:产品需要通过蓝牙规范的一致性测试。

  • 注册:向蓝牙技术联盟注册产品,分配 DIDS(Declaration ID)。

  • 费用:会员免费,非会员约 8000 美元起。

BQB 认证确保不同厂商的 BLE 设备可以互操作。未认证的产品使用蓝牙标志可能面临法律风险。

6.3 业务模型

BLE 支持多种业务模型:

  • 设备销售:销售带 BLE 的硬件设备,如传感器、可穿戴。

  • 数据服务:设备采集数据上传云端,按数据量或订阅收费。

  • 生态平台:提供 BLE 设备接入的云平台,按设备数或消息量收费。

  • 定位服务:基于 BLE Beacon 的室内定位,按定位次数或面积收费。

6.4 功耗与成本

BLE 的低功耗特性直接影响电池成本和用户体验:

  • 电池寿命:低功耗意味着电池寿命更长,减少更换电池的成本和不便。

  • 电池容量:可以使用更小的电池,降低设备体积和成本。

  • 充电频率:减少充电频率,提升用户体验。

对于大批量的物联网设备,BLE 的低功耗可以显著降低电池和维护成本。


七、架构设计与关键机制

7.1 单芯片与双芯片架构

BLE 协议栈有两种实现架构:

  • 单芯片(SoC):控制器和主机集成在一个芯片上,如 nRF52、ESP32。成本低,功耗低,适合简单应用。

  • 双芯片:控制器和主机分离,主机运行在 MCU 上,通过 HCI 连接控制器。灵活但成本高,适合需要复杂应用的场景。

大多数物联网设备使用单芯片方案,将 BLE 协议栈和应用程序运行在同一个 MCU 上。

7.2 连接状态机

BLE 连接的状态机管理连接的建立、维持和断开:

  1. 广播:外设发送广播。

  2. 扫描:中央扫描广播。

  3. 发起:中央发送连接请求。

  4. 连接:双方建立连接,开始通信。

  5. 更新连接参数:协商连接间隔、延迟、超时。

  6. 断开:任一方可以断开连接。

连接参数可以在连接后更新,以适应不同的应用场景(如低功耗 vs 高吞吐)。

7.3 多连接管理

中央设备可以同时连接多个外设(典型值 3-8 个)。多连接管理需要:

  • 时间调度:为每个连接分配连接事件,避免冲突。

  • 跳频协调:每个连接使用不同的跳频序列,避免干扰。

  • 缓冲区管理:为每个连接分配独立的收发缓冲区。

外设通常只连接一个中央,但蓝牙 5 支持多角色(Multi-Role),设备可以同时是中央和外设。

7.4 数据传输优化

BLE 的数据传输可以通过以下方式优化:

  • 增大 MTU:增大 ATT MTU(默认 23 字节),减少分包次数。蓝牙 4.2 支持最大 247 字节。

  • 增大连接事件:在一个连接事件中发送多个数据包,提高吞吐量。

  • 使用 2 Mbps PHY:蓝牙 5 的 2 Mbps 物理层,吞吐量加倍。

  • 减少连接间隔:减小连接间隔,降低延迟,但增加功耗。

7.5 低功耗模式

BLE 设备的低功耗通过以下机制实现:

  • 广播间隔:增大广播间隔,减少射频活动。

  • 连接间隔:增大连接间隔,减少连接事件频率。

  • 从设备延迟:允许从设备跳过连接事件。

  • 深度睡眠:不活动时进入深度睡眠,只保留 RTC 运行。

在连接状态下,从设备可以在连接事件之间进入睡眠,只在下一个连接事件前唤醒。

7.6 广播功率与距离

BLE 的传输距离与发射功率和接收灵敏度有关。常见的功率等级:

  • +8 dBm:长距离,约 100 米视距。

  • 0 dBm:标准,约 10-30 米。

  • -20 dBm:近场,约 1 米。

蓝牙 5 的 Coded PHY 通过前向纠错(FEC)提高接收灵敏度,可以在相同功率下实现 4 倍的距离。但 Coded PHY 的吞吐量较低(125 Kbps 或 500 Kbps),适合长距离低速率场景。

7.7 吞吐量与延迟

BLE 的吞吐量和延迟受多种因素影响:

  • 连接间隔:间隔越小,延迟越低,吞吐量越高,但功耗越大。

  • 从设备延迟:延迟越大,从设备可以跳过更多连接事件,功耗越低,但延迟增加。

  • MTU:MTU 越大,每次传输的数据越多,吞吐量越高。

  • PHY 速率:2 Mbps PHY 的吞吐量是 1 Mbps 的两倍。

  • 数据包数量:每个连接事件可以发送多个数据包,提高吞吐量。

实际应用中,需要在吞吐量、延迟和功耗之间取得平衡。

7.8 错误处理与重连

BLE 连接可能因干扰、距离过远等原因断开。应用需要处理断开事件并尝试重连:

  • 短断开:监管超时内重新连接,可以恢复加密状态。

  • 长断开:超过监管超时,需要重新配对或使用存储的密钥加密。

重连时,双方可以使用配对时存储的 LTK 快速加密,无需重新配对。这提高了重连速度和用户体验。


八、代码实现(改写版)

8.1 GATT 服务与特征定义

/* ble_gatt.h - BLE GATT 服务定义(改写版,参考 Zephyr BLE 和 Nordic SoftDevice) */
#ifndef BLE_GATT_H
#define BLE_GATT_H
​
#include <stdint.h>
​
/* UUID 类型 */
#define BLE_UUID_TYPE_16    0
#define BLE_UUID_TYPE_128   1
​
/* 16 位标准 UUID */
#define BLE_UUID_BATTERY_SERVICE        0x180F
#define BLE_UUID_BATTERY_LEVEL          0x2A19
#define BLE_UUID_DEVICE_INFORMATION     0x180A
#define BLE_UUID_MANUFACTURER_NAME      0x2A29
​
/* 属性权限 */
#define BLE_PERM_READ      (1 << 0)
#define BLE_PERM_WRITE     (1 << 1)
#define BLE_PERM_NOTIFY    (1 << 2)
#define BLE_PERM_INDICATE  (1 << 3)
​
/* GATT 属性 */
struct ble_gatt_attr {
    uint16_t    handle;
    uint8_t     uuid_type;
    uint8_t     uuid[16];
    uint16_t    permissions;
    uint8_t    *value;
    uint16_t    value_len;
    uint16_t    value_max_len;
};
​
/* GATT 特征 */
struct ble_gatt_char {
    struct ble_gatt_attr  value_attr;
    struct ble_gatt_attr  cccd_attr;   /* 客户端特性配置描述符 */
    uint8_t               props;       /* 特征属性(读/写/通知/指示) */
};
​
/* GATT 服务 */
struct ble_gatt_service {
    uint16_t            start_handle;
    uint16_t            end_handle;
    uint8_t             uuid_type;
    uint8_t             uuid[16];
    struct ble_gatt_char *chars;
    uint8_t             char_count;
};
​
/* 初始化 GATT 服务 */
int ble_gatt_service_init(struct ble_gatt_service *svc);
​
/* 读取特征值 */
int ble_gatt_char_read(struct ble_gatt_service *svc, uint16_t handle,
                       uint8_t *buf, uint16_t *len);
​
/* 写入特征值 */
int ble_gatt_char_write(struct ble_gatt_service *svc, uint16_t handle,
                        const uint8_t *data, uint16_t len);
​
/* 发送通知 */
int ble_gatt_char_notify(struct ble_gatt_service *svc, uint16_t conn_handle,
                         uint16_t value_handle, const uint8_t *data, uint16_t len);
​
#endif /* BLE_GATT_H */

8.2 GAP 广播配置

/* ble_gap.c - BLE GAP 广播配置(改写版) */
#include "ble_gap.h"
#include <string.h>
​
/* 设置广播数据 */
int ble_gap_set_advertising_data(const char *name, uint16_t service_uuid)
{
    uint8_t adv_data[31];
    uint8_t idx = 0;
​
    /* Flags */
    adv_data[idx++] = 2;            /* 长度 */
    adv_data[idx++] = 0x01;         /* 类型:Flags */
    adv_data[idx++] = 0x06;         /* 通用可发现 + 不支持 BR/EDR */
​
    /* 16 位服务 UUID */
    adv_data[idx++] = 3;            /* 长度 */
    adv_data[idx++] = 0x03;         /* 类型:完整 16 位服务 UUID */
    adv_data[idx++] = service_uuid & 0xFF;
    adv_data[idx++] = (service_uuid >> 8) & 0xFF;
​
    /* 设备名称 */
    uint8_t name_len = strlen(name);
    if (name_len > 0 && idx + name_len + 2 <= 31) {
        adv_data[idx++] = name_len + 1;  /* 长度 */
        adv_data[idx++] = 0x09;          /* 类型:完整名称 */
        memcpy(&adv_data[idx], name, name_len);
        idx += name_len;
    }
​
    /* 设置广播参数:100 ms 间隔,可连接非定向广播 */
    struct ble_adv_params params = {
        .interval_min = 160,    /* 100 ms */
        .interval_max = 200,    /* 125 ms */
        .type = BLE_ADV_TYPE_IND,
    };
​
    /* ble_gap_adv_set_data(adv_data, idx); */
    /* ble_gap_adv_start(&params); */
    return 0;
}
​
/* 设置扫描响应数据 */
int ble_gap_set_scan_response_data(const char *manuf_data, uint8_t len)
{
    uint8_t sr_data[31];
    uint8_t idx = 0;
​
    /* 厂商数据 */
    if (len > 0 && len + 3 <= 31) {
        sr_data[idx++] = len + 2;    /* 长度 */
        sr_data[idx++] = 0xFF;       /* 类型:厂商数据 */
        sr_data[idx++] = 0x00;       /* 厂商 ID 低字节 */
        sr_data[idx++] = 0x00;       /* 厂商 ID 高字节 */
        memcpy(&sr_data[idx], manuf_data, len);
        idx += len;
    }
​
    /* ble_gap_scan_rsp_set_data(sr_data, idx); */
    return 0;
}

8.3 连接参数与功耗管理

/* ble_conn.c - BLE 连接管理(改写版) */
#include "ble_conn.h"
​
/* 连接参数 */
struct ble_conn_params {
    uint16_t min_conn_interval;   /* 最小连接间隔(单位 1.25 ms) */
    uint16_t max_conn_interval;   /* 最大连接间隔 */
    uint16_t slave_latency;       /* 从设备延迟 */
    uint16_t supervision_timeout; /* 监管超时(单位 10 ms) */
};
​
/* 低功耗连接参数:连接间隔 1 秒,从设备延迟 4 */
static const struct ble_conn_params low_power_params = {
    .min_conn_interval = 800,     /* 1000 ms */
    .max_conn_interval = 800,     /* 1000 ms */
    .slave_latency = 4,
    .supervision_timeout = 400,   /* 4000 ms */
};
​
/* 高吞吐连接参数:连接间隔 15 ms */
static const struct ble_conn_params high_throughput_params = {
    .min_conn_interval = 12,      /* 15 ms */
    .max_conn_interval = 12,      /* 15 ms */
    .slave_latency = 0,
    .supervision_timeout = 200,   /* 2000 ms */
};
​
/* 更新连接参数 */
int ble_conn_update_params(uint16_t conn_handle,
                           const struct ble_conn_params *params)
{
    /* 发送 L2CAP 连接参数更新请求 */
    /* ble_l2cap_conn_param_update_req(conn_handle, params); */
    return 0;
}
​
/* 根据应用场景选择连接参数 */
const struct ble_conn_params *ble_conn_select_params(bool low_power)
{
    return low_power ? &low_power_params : &high_throughput_params;
}

九、Linux 平台 BLE 实践

9.1 BlueZ 协议栈

BlueZ 是 Linux 官方蓝牙协议栈,支持经典蓝牙和 BLE。BlueZ 提供了命令行工具和 D-Bus API:

  • bluetoothctl:交互式命令行工具,用于扫描、连接、配对。

  • hciconfig:配置蓝牙控制器。

  • hcitool:低层次 HCI 工具(已过时,被 bluetoothctl 替代)。

  • btmon:蓝牙监控工具,抓取 HCI 数据包。

  • D-Bus API:应用通过 D-Bus 访问 BlueZ 的功能。

BlueZ 的 BLE 实现包括:

  • GATT 服务器:通过 D-Bus 注册 GATT 服务。

  • GATT 客户端:通过 D-Bus 发现和访问远程 GATT 服务。

  • 广播/扫描:通过 D-Bus 启动广播或扫描。

  • 配对管理:通过 D-Bus 处理配对和密钥。

9.2 Linux BLE 编程

Linux 上开发 BLE 应用有多种方式:

  • D-Bus API:直接调用 BlueZ 的 D-Bus 接口,适合复杂应用。

  • bluetoothctl 脚本:通过命令行脚本控制蓝牙,适合简单应用。

  • 第三方库:如 bluepy(Python)、Bleak(Python 跨平台)、SimpleBLE(C++)。

Python 是 Linux 上 BLE 开发的常用语言,因为有成熟的库和快速的开发周期。

BlueZ D-Bus 接口示例

BlueZ 的 D-Bus 接口提供了丰富的 BLE 功能。以下是使用 D-Bus 连接 BLE 设备并读取特征的伪代码:

1. 启动蓝牙适配器:org.bluez.Adapter1.StartDiscovery()
2. 发现设备后获取设备路径:org.bluez.Device1
3. 连接设备:Device1.Connect()
4. 发现服务:等待 ServicesResolved 属性变化
5. 遍历服务和特征:org.bluez.GattService1, GattCharacteristic1
6. 读取特征:GattCharacteristic1.ReadValue()
7. 启用通知:GattCharacteristic1.StartNotify()
8. 接收通知:监听 PropertiesChanged 信号

D-Bus 接口的优势是与语言无关,任何支持 D-Bus 的语言都可以使用。

9.3 Linux BLE 调试

  • btmon:抓取 HCI 数据包,分析 BLE 通信。

  • bluetoothctl:查看设备状态、连接、配对信息。

  • hcidump:旧版 HCI 抓包工具。

  • Wireshark:通过 btmon 导出的数据包分析。


十、Android 平台 BLE 实践

10.1 Android BLE 架构

Android 的 BLE 功能通过 android.bluetooth 包提供,核心类包括:

  • BluetoothAdapter:蓝牙适配器,管理蓝牙开关和扫描。

  • BluetoothDevice:远程蓝牙设备。

  • BluetoothGatt:GATT 客户端,访问远程 GATT 服务。

  • BluetoothGattServer:GATT 服务器,提供 GATT 服务。

  • BluetoothGattCallback:GATT 事件回调。

Android 的 BLE API 是异步的,所有操作通过回调返回结果。

10.2 Android BLE 扫描

Android 提供两种扫描方式:

  • startDiscovery():经典蓝牙扫描,也能发现 BLE 设备,但效率低。

  • BluetoothLeScanner.startScan():BLE 专用扫描,支持扫描过滤(按 UUID、MAC 地址、RSSI)。

Android 8.0 引入了未授权扫描限制,后台扫描频率受限。Android 12 要求 BLUETOOTH_SCAN 和 BLUETOOTH_CONNECT 权限。

10.3 Android BLE 连接与通信

Android 连接 BLE 设备的流程:

  1. 扫描发现设备。

  2. 调用 device.connectGatt() 连接。

  3. 在 BluetoothGattCallback.onConnectionStateChange 中处理连接结果。

  4. 连接成功后调用 gatt.discoverServices() 发现服务。

  5. 通过 gatt.readCharacteristic() 和 gatt.writeCharacteristic() 读写特征。

  6. 通过 gatt.setCharacteristicNotification() 启用通知。

10.4 Android BLE 功耗与兼容性

Android 设备的 BLE 实现差异较大,不同厂商的 ROM 可能有兼容性问题。常见问题包括:

  • 后台扫描限制:Android 8+ 限制后台扫描频率。

  • 连接超时:部分设备连接超时时间较短。

  • MTU 协商:部分设备不支持 MTU 协商。

  • GATT 缓存:GATT 服务变更后缓存未更新。

为了兼容性,建议在应用层做容错处理,如重试连接、刷新 GATT 缓存。

10.5 Android BLE 开发注意事项

Android BLE 开发有一些需要注意的坑:

  • 主线程操作:BLE 操作不应在主线程执行,避免 ANR。建议使用专用线程或协程。

  • 连接超时:Android 没有提供连接超时设置,需要自己实现定时器。

  • GATT 操作串行化:GATT 操作(读、写、通知)需要串行执行,不能并发。建议使用队列管理 GATT 操作。

  • 及时关闭:使用完 BluetoothGatt 后调用 close(),否则会泄漏资源。

  • 权限处理:Android 12+ 需要运行时申请 BLUETOOTH_SCAN、BLUETOOTH_CONNECT 权限。

10.6 Android GATT 服务器

Android 也可以作为 GATT 服务器,提供自定义服务。通过 BluetoothGattServer.openGattServer() 创建服务器,注册服务和特征,通过 BluetoothGattServerCallback 处理客户端请求。

GATT 服务器常用于手机与手机、手机与设备的双向通信,或者手机作为网关转发数据。


十一、ESP/嵌入式平台 BLE 实践

11.1 ESP-IDF 的 BLE

ESP32 系列芯片支持 BLE 和经典蓝牙,ESP-IDF 提供了完整的 BLE 协议栈。ESP-IDF 的 BLE 基于 Bluedroid(Android 的蓝牙协议栈),但经过裁剪和优化。

ESP-IDF 的 BLE API 包括:

  • esp_ble_gap_* :GAP 相关 API(广播、扫描、连接)。

  • esp_ble_gatts_* :GATT 服务器 API。

  • esp_ble_gattc_* :GATT 客户端 API。

  • esp_ble_smp_* :安全管理 API。

ESP32 还支持 NimBLE,这是一个更轻量的 BLE 协议栈,RAM 占用比 Bluedroid 小得多,适合资源受限的应用。

11.2 Zephyr 的 BLE

Zephyr RTOS 内置了完整的 BLE 协议栈,支持控制器和主机。Zephyr 的 BLE 实现是开源的,代码结构清晰,易于定制。

Zephyr 的 BLE API 基于回调机制:

  • bt_le_adv_start():启动广播。

  • bt_conn_create_le():发起连接。

  • GATT 服务定义:通过 BT_GATT_SERVICE_DEFINE 宏定义服务和特征。

  • GATT 回调:通过 bt_gatt_read_func_t、bt_gatt_write_func_t 等回调处理读写。

Zephyr 的 BLE 支持单芯片和 HCI 模式,可以使用 Zephyr 自带的控制器或外部控制器。

11.3 Nordic SoftDevice

Nordic Semiconductor 的 nRF5 系列芯片是 BLE 应用的主流选择。Nordic 提供 SoftDevice,一个预编译的 BLE 协议栈库,应用层通过 API 调用。

SoftDevice 的优势是成熟稳定、通过蓝牙认证、功耗低。劣势是闭源,无法修改协议栈内部。Nordic 也提供了开源的 nRF Connect SDK,基于 Zephyr,可以使用开源协议栈。

11.4 嵌入式 BLE 功耗优化

嵌入式 BLE 设备的功耗优化是核心工作。以下是常用的优化技巧:

  • 广播优化:增大广播间隔(如 1-2 秒),减少广播频率。使用定向广播快速重连。

  • 连接参数优化:根据数据传输需求选择连接间隔。低频率数据使用大间隔(1-4 秒),高频率数据使用小间隔(15-30 毫秒)。

  • 从设备延迟:在低延迟要求不高的场景,增大从设备延迟,减少射频活动。

  • 关闭不需要的功能:关闭经典蓝牙、LE Secure Connections(如果不需要)等功能,节省 Flash 和 RAM。

  • 使用低功耗时钟:在睡眠时使用 32.768 kHz 低频时钟,降低功耗。

通过合理优化,BLE 设备的平均电流可以降到微安级别,纽扣电池可以使用数年。

11.5 嵌入式 BLE 与 WiFi 共存

许多嵌入式设备同时使用 BLE 和 WiFi(如 ESP32)。两者都工作在 2.4 GHz 频段,可能相互干扰。共存机制包括:

  • 时分复用:BLE 和 WiFi 分时使用射频,避免同时传输。

  • 信道协调:WiFi 避开 BLE 使用的信道。

  • 优先级管理:根据数据类型设置优先级(如 BLE 音频优先于 WiFi 数据)。

ESP32 实现了硬件级的 BLE/WiFi 共存,通过软件调度保证两者都能正常工作。


十二、多平台对比与选型建议

12.1 各平台 BLE 协议栈对比

维度BlueZ (Linux)Android BLEESP-IDFZephyr BLENordic SoftDevice
开源是部分开源部分开源是否
RAM 占用高(MB 级)高(MB 级)中(几十 KB)低(十几 KB)低(几 KB)
功能完整度高高中高高
功耗优化一般一般好好极好
开发难度中低中中低
认证状态认证认证认证部分认证认证

12.2 选型建议

  • Linux 网关/服务器:使用 BlueZ,功能完整,D-Bus API 灵活。

  • Android 应用:使用系统 BLE API,兼容性好,开发简单。

  • 嵌入式设备:使用 ESP-IDF 或 Zephyr,根据芯片选择。

  • 低功耗设备:优先考虑 Nordic SoftDevice,功耗最优。

  • 需要定制协议栈:使用 Zephyr 开源协议栈,可以修改内部实现。

12.3 BLE 与其他无线技术的对比

维度BLEWiFiZigbeeLoRa
功耗极低高低极低
距离10-100m10-100m10-100m2-15km
吞吐125K-2M1-100M20-250K0.3-50K
网络拓扑星型/Mesh星型Mesh星型
典型应用可穿戴/传感器高吞吐数据智能家居远程传感

十三、发展历程与未来趋势

13.1 BLE 的发展阶段

BLE 的发展经历了四个阶段:

第一阶段(2010-2013):基础能力。蓝牙 4.0 引入 BLE,支持基础的广播、连接、GATT。主要用于简单的传感器和遥控器。

第二阶段(2014-2016):性能提升。蓝牙 4.2 引入数据包长度扩展和隐私保护。BLE 的吞吐量和安全性提升,开始用于更复杂的应用。

第三阶段(2016-2020):功能扩展。蓝牙 5 引入 2 Mbps、长距离、广播扩展。BLE Audio(蓝牙 5.2)支持低延迟音频,开始挑战经典蓝牙在音频领域的地位。

第四阶段(2020-至今):大规模部署。蓝牙 5.3/5.4 优化连接建立和广播,支持大规模设备配置。BLE Mesh 支持智能家居和工业物联网的大规模网络。

13.2 BLE Audio 的影响

BLE Audio 是 BLE 发展的重要里程碑,它使用 LE Isochronous Channels 传输音频,支持低延迟和多设备连接。BLE Audio 将逐步替代经典蓝牙在耳机和音箱中的应用,因为它功耗更低、功能更丰富(如空间音频、多设备共享)。

13.3 BLE Mesh

BLE Mesh 是蓝牙技术联盟于 2017 年发布的网状网络规范,允许大量 BLE 设备组成自组织网络。BLE Mesh 基于泛洪(Flooding)算法,不依赖路由,适合智能家居和工业自动化等需要大规模设备互联的场景。

13.4 未来趋势

  • BLE Audio 普及:BLE Audio 将成为耳机、助听器等音频设备的标准。

  • 室内定位:蓝牙 5.1 的寻向功能支持厘米级定位,将在商场、机场等场所普及。

  • Mesh 网络:BLE Mesh 将在智能家居和工业物联网中大规模部署。

  • 更低功耗:新的低功耗技术将进一步延长电池寿命。

  • 更高安全:持续增强配对和加密机制,防止攻击。

13.5 总结

BLE 是物联网领域最重要的无线通信技术之一,通过极低的功耗实现了短距离通信。从 2010 年蓝牙 4.0 发布至今,BLE 持续演进,从简单的传感器通信扩展到音频、定位、Mesh 网络等复杂应用。

理解 BLE 的协议分层(Controller + Host + Application)、核心协议(GAP/GATT/ATT/SMP)和低功耗设计,是用好 BLE 的基础。不同平台有不同的实现(BlueZ、Android BLE、ESP-IDF、Zephyr、SoftDevice),但核心协议一致,开发者可以根据应用场景选择合适的平台。

BLE 的未来将更加注重低功耗、高可靠和大规模部署,为物联网的普及提供坚实的通信基础。

13.6 BLE 与其他无线技术的协作

在实际应用中,BLE 通常与其他无线技术协作,各取所长:

  • BLE + WiFi:BLE 用于低功耗控制和传感器数据,WiFi 用于高吞吐数据传输(如固件升级、视频流)。

  • BLE + 蜂窝网络:BLE 用于设备间通信,蜂窝网络用于云端连接。

  • BLE + NFC:NFC 用于快速配对(OOB),BLE 用于后续通信。

  • BLE + UWB:BLE 用于设备发现和连接,UWB 用于精确测距和定位。

这种多模协作可以根据场景动态选择最优的通信方式,平衡功耗、吞吐和距离。

13.7 BLE 在各行业的应用

BLE 已广泛应用于各行各业:

  • 消费电子:耳机、手表、手环、智能家居。

  • 医疗健康:血糖仪、心率带、体温计、远程监护。

  • 工业物联网:资产追踪、环境监测、设备诊断。

  • 汽车:无钥匙进入、胎压监测、车载诊断。

  • 零售:Beacon 营销、电子价签、库存管理。

  • 体育健身:运动追踪、健身器材连接。

BLE 的低功耗和低成本使其成为物联网设备的首选无线技术。

更多推荐