文章目录
- 1.概述
- 2.协议栈架构中的数据流转与MTU定义
-
- [2.1 物理层(PHY)与链路层(Link Layer)的物理限制](#2.1 物理层(PHY)与链路层(Link Layer)的物理限制)
- [2.2 L2CAP层:逻辑通道与分片重组机制](#2.2 L2CAP层:逻辑通道与分片重组机制)
-
- [2.2.1 L2CAP PDU 结构](#2.2.1 L2CAP PDU 结构)
- [2.3 ATT层:应用数据的直接载体](#2.3 ATT层:应用数据的直接载体)
- [3. MTU 的深度实现原理:分片与流控](#3. MTU 的深度实现原理:分片与流控)
-
- [3.1 链路层分片(Fragmentation)机制详界](#3.1 链路层分片(Fragmentation)机制详界)
- [3.2 错误处理与流控](#3.2 错误处理与流控)
- [4. MTU 协商工作流程与状态机](#4. MTU 协商工作流程与状态机)
-
- [4.1 协商协议(Exchange MTU Request/Response)](#4.1 协商协议(Exchange MTU Request/Response))
- [4.2 操作系统行为差异分析](#4.2 操作系统行为差异分析)
-
- [4.2.1 Android 生态](#4.2.1 Android 生态)
- [4.2.2 iOS 生态 (CoreBluetooth)](#4.2.2 iOS 生态 (CoreBluetooth))
- [5. 数据长度扩展(DLE)与MTU的协同效应](#5. 数据长度扩展(DLE)与MTU的协同效应)
-
- [5.1 DLE 的工作机制](#5.1 DLE 的工作机制)
- [5.2 MTU 与 DLE 的四种组合场景分析](#5.2 MTU 与 DLE 的四种组合场景分析)
- [6. 吞吐量数学模型与影响因子](#6. 吞吐量数学模型与影响因子)
-
- [6.1 理论吞吐量计算公式](#6.1 理论吞吐量计算公式)
- [6.2 关键影响因子](#6.2 关键影响因子)
-
- [6.2.2 时间参数与帧间间隔(T_IFS)](#6.2.2 时间参数与帧间间隔(T_IFS))
- [6.2.3 连接间隔(Connection Interval)](#6.2.3 连接间隔(Connection Interval))
- [6.2.4 操作系统限制(Packets per Event)](#6.2.4 操作系统限制(Packets per Event))
- [6.3 算例对比](#6.3 算例对比)
- [7. 实际开发中的作用与优化策略](#7. 实际开发中的作用与优化策略)
-
- [7.1 OTA 固件升级的最佳实践](#7.1 OTA 固件升级的最佳实践)
- [7.2 功耗与能效优化](#7.2 功耗与能效优化)
- [7.3 内存管理](#7.3 内存管理)
- [8. 总结](#8. 总结)
- 9.相关推荐
- 相关参考
1.概述
蓝牙低功耗(Bluetooth Low Energy, BLE)作为现代物联网(IoT)的基石技术,其数据传输效率直接决定了用户体验的流畅度与设备的能效表现。在BLE协议栈的架构中,最大传输单元(Maximum Transmission Unit, MTU) 是一个贯穿物理层、链路层、逻辑链路控制与适配层(L2CAP)以及属性协议层(ATT)的关键参数。它不仅定义了数据包在逻辑通道中的最大载荷,更直接影响着通信的吞吐量、延迟特性以及功耗水平。
本博客将从协议栈的最底层出发,抽丝剥茧地解析MTU的实现原理,探讨其与数据长度扩展(DLE)、物理层速率(PHY)的深层耦合关系,并深入剖析Android与iOS系统在MTU协商上的异同与演进。最后,我们将基于第一性原理,构建面向高吞吐量(如OTA升级)和低延迟场景的工程最佳实践。
2.协议栈架构中的数据流转与MTU定义
要真正理解MTU,不能将其孤立为一个单一的数值,而应将其视为协议栈各层之间为了适配物理信道限制而达成的一种"契约"。BLE协议栈采用了分层架构,每一层对数据包的大小都有着严苛的定义与限制。下面是BLE分层设计示意图。

2.1 物理层(PHY)与链路层(Link Layer)的物理限制
在BLE 4.0/4.1规范的原始设计中,设计哲学是极致的低功耗与简单的状态机。因此,链路层(Link Layer, LL) 定义的空中接口数据包(Air Interface Packet)被严格限制。
一个标准的BLE链路层数据包结构如下:

| 组成部分 | 长度(字节) | 功能描述 |
|---|---|---|
| 前导码 (Preamble) | 1 | 用于接收机同步射频信号,调整增益。 |
| 接入地址 (Access Address) | 4 | 标识特定的连接,确保数据发送给正确的设备。 |
| PDU 报头 (Header) | 2 | 包含PDU类型、长度字段(Length)等控制信息。 |
| PDU 净荷 (Payload) | 0 - 27 | 核心限制所在。承载上层数据。 |
| CRC 校验 | 3 | 循环冗余校验,保证数据完整性。 |
在BLE 4.0/4.1标准中,PDU净荷的最大长度被硬件固定为 27字节。这一数字并非随意选取,而是为了在保证抗干扰能力(通过跳频)和降低射频开启时间(Tx Window)之间取得平衡。这27字节必须承载所有上层协议的开销与数据。因此,在未启用扩展特性的情况下,无论应用层想发送多少数据,物理层一次只能"搬运"27字节的内容。
2.2 L2CAP层:逻辑通道与分片重组机制
逻辑链路控制与适配协议(L2CAP)位于链路层之上,是主机(Host)与控制器(Controller)之间的桥梁。它起到了"多路复用器 "和"数据适配器"的作用。
2.2.1 L2CAP PDU 结构
当ATT层传递下来的数据(SDU)加上L2CAP报头后超过了链路层的承载能力,L2CAP会将数据切割。
- 基本L2CAP报头(Basic L2CAP Header): 占用 4字节。
- 长度(Length, 2字节): 指示整个L2CAP Payload的长度(不含报头本身)。
- 通道ID(Channel ID, CID, 2字节): 标识数据所属的逻辑通道(例如,ATT通道的CID固定为0x0004)。
这意味着,在最基础的BLE数据包中,27字节的链路层净荷扣除4字节L2CAP报头后,仅剩下 23字节 给上层协议。
2.3 ATT层:应用数据的直接载体
ATT_MTU 是应用开发者最直接接触的参数,它定义了客户端(Client)与服务器(Server)之间单个属性协议数据单元(ATT PDU)的最大长度。
- 默认值: BLE规范规定,所有BLE设备必须支持的最小ATT_MTU为 23字节。
- 有效载荷 (Effective Payload): ATT协议本身也需要报头来描述操作类型。
- 对于常见的写操作(Write Request / Command)或通知(Notification):
- Opcode(操作码): 1字节。
- Attribute Handle(属性句柄): 2字节。
- 对于常见的写操作(Write Request / Command)或通知(Notification):
- 因此,ATT Header = 3字节。
结论: 在默认情况下(ATT_MTU = 23),应用层用户数据的最大吞吐量被限制为 23 − 3 = 20 23 - 3 = 20 23−3=20 字节。这就是广为人知的"20字节限制"的各种技术根源。
3. MTU 的深度实现原理:分片与流控
当开发者请求修改MTU(例如请求512字节)并获得成功后,底层究竟发生了什么?数据是如何在受限的物理信道上传输的?
3.1 链路层分片(Fragmentation)机制详界
假设应用层发送了一个180字节的数据包,且协商后的 ATT_MTU 为 185 字节。此时,ATT PDU 总长为 180 ( Data ) + 3 ( ATT Header ) = 183 180 (\text{Data}) + 3 (\text{ATT Header}) = 183 180(Data)+3(ATT Header)=183 字节。L2CAP 层加上4字节报头,总长187字节。
如果链路层未开启数据长度扩展(DLE),仍限制为27字节,L2CAP层将执行以下分片流程:
- 起始分片(Start Fragment) :
- L2CAP层构建第一个链路层PDU。
- 链路层报头(LL Header)中的 LLID 字段 被设置为 0b10。这在二进制层面明确告知接收方:"这是一个L2CAP消息的开始,或者是一个完整的L2CAP消息" 。
- 该分片包含:4字节 L2CAP Header + 23字节 ATT数据片段。
- 链路层净荷被填满(27字节)。
- 延续分片(Continuation Fragment ):
- 剩余数据( 187 − 27 = 160 187 - 27 = 160 187−27=160 字节)被切割为后续的多个包。
- 后续包的 LLID 字段 被设置为 0b01。这告知接收方:"这是上一个L2CAP消息的后续部分" 。
- 每个延续分片尽可能填满27字节。需要 160 / 27 ≈ 6 160 / 27 \approx 6 160/27≈6 个数据包。
- 重组(Reassembly ):
- 接收方的链路层控制器接收到 LLID = 0b10 的包后,解析L2CAP报头中的长度字段(Length = 183),以此预知总数据量。
- 它进入"重组状态",将后续接收到的 LLID = 0b01 的包追加到缓冲区。
- 直到接收的数据总量达到预期长度,控制器将完整的L2CAP PDU上交主机栈(Host Stack)。

扩展说明 :这种分片机制是完全在控制器(Controller)硬件或固件中处理的,对上层应用透明。增加ATT_MTU的主要优势在于减少了L2CAP报头和ATT报头的开销比例 。发送180字节数据,如果分9次发送(每次20字节),总共需要9个L2CAP头( 9 × 4 = 36 9 \times 4 = 36 9×4=36 字节)和9个ATT头( 9 × 3 = 27 9 \times 3 = 27 9×3=27 字节)。而使用大MTU分片发送,只需要1个L2CAP头和1个ATT头。这不仅节省了60多字节的空中开销,更重要的是减少了8次应用层到协议栈的上下文切换和中断处理。
3.2 错误处理与流控
分片机制引入了潜在的风险。如果中间某个延续分片(Continuation Fragment)在空中丢失:
- 由于链路层有自动重传机制(ACK/NACK),通常能保证单一分片的可靠性。
- 但如果在极端干扰下重传失败导致连接超时,整个L2CAP包将被丢弃。
- L2CAP层没有复杂的选择性重传(Selective Repeat)机制来针对单个分片,它依赖链路层的可靠性。如果链路层放弃(Supervision Timeout),L2CAP重组失败,上层将感知到连接断开或超时。
此外,L2CAP支持基于信用的流控(Credit Based Flow Control),主要用于L2CAP连接导向通道(CoC)。但在ATT协议中,流控主要依赖于 Request-Response 机制或应用层的逻辑。
4. MTU 协商工作流程与状态机
MTU的大小不是静态配置的,而是动态协商的结果。理解这一流程对于解决Android与iOS的兼容性问题至关重要。
4.1 协商协议(Exchange MTU Request/Response)
协商过程遵循严格的 Client-Server 模型,通常在连接建立并加密(如果需要)之后立即进行。
- 发起者限制: 根据蓝牙核心规范(Core Spec Vol 3, Part F, 3.4.2.1),只有 GATT Client(通常是手机)有权发起 ATT_EXCHANGE_MTU_REQ。GATT Server(通常是外设)只能被动响应。
注:如果外设需要充当Client角色(例如智能手表读取手机通知),它也可以发起请求,但在典型的IoT场景中,多由手机发起。
-
请求(Request): Client发送请求包,包含 Client Rx MTU(客户端支持的最大接收大小)。
- Opcode: 0x02
- Client Rx MTU: (2字节,例如 517)
-
响应(Response): Server收到请求后,回复 ATT_EXCHANGE_MTU_RSP,包含 Server Rx MTU。
- Opcode: 0x03
- Server Rx MTU: (2字节,例如 247)
- 约束: Server回复的数值表示它自身的能力,该值可以小于、等于或大于Client请求的值(虽然大于没有意义,因为最终会取最小值)。
-
计算最终值 : 双方均采用以下公式计算并在本地生效:
Effective MTU = min ( Client Rx MTU , Server Rx MTU ) \text{Effective MTU} = \min(\text{Client Rx MTU}, \text{Server Rx MTU}) Effective MTU=min(Client Rx MTU,Server Rx MTU) -
不可逆性: 该过程在一次连接中只能发生一次。一旦协商完成,MTU值锁定,直到连接断开。
4.2 操作系统行为差异分析
不同操作系统的蓝牙协议栈对MTU协商的处理逻辑存在显著差异,这是跨平台开发的主要痛点。
4.2.1 Android 生态
Android系统赋予了开发者较高的控制权,但也带来了碎片化问题。
- API 调用: 开发者需显式调用 BluetoothGatt.requestMtu(int mtu) 。
- 最大值支持: Android 源码(Bluedroid/Fluoride栈)中定义的 GATT_MAX_MTU_SIZE 通常为 517字节。这一数值来源于L2CAP的规范限制与内存分配策略。
- 协商时机: 建议在 onConnectionStateChange 变为 CONNECTED 后,且在 discoverServices 之前调用。虽然规范允许随时协商,但早期协商能确保后续的服务发现(Service Discovery)利用大包优势,加速UUID的读取。
- 版本怪癖(Android 13/14): 在最新的Android版本(如Android 14)中,观察到系统可能会自动发起MTU协商请求,且请求值默认为517字节,即使App代码中没有调用 requestMtu 。这要求外设固件必须具备处理517字节请求的能力,不能因为请求值过大而崩溃或拒绝服务。
- 回调陷阱: requestMtu 是异步操作。必须等待 onMtuChanged 回调返回 GATT_SUCCESS 后,新的MTU才生效。如果在此之前发送大包,协议栈可能会因为包过大而丢弃,或者按照旧的MTU(23)进行截断。
4.2.2 iOS 生态 (CoreBluetooth)
iOS的设计哲学是封闭与自动化,旨在通过系统托管来优化全局性能。
-
无主动API: CoreBluetooth 框架没有提供请求MTU的接口。开发者无法像Android那样设置特定的值 。
-
自动协商机制: iOS设备在连接建立后,会自动发起MTU协商。
-
数值演进史:
- iOS 9及更早: 协商值约为 158 字节。
- iOS 10 - iOS 15: 这一时期的设备非常稳定地请求 185 字节。这通常被认为是iOS BLE的"标准"上限 。
- iOS 16+: 引入了变数。在在部分设备与系统版本的实际抓包中观察到(如配备较新芯片的iPhone 14/15),系统可能尝试协商更高的MTU(如256或517字节),但也存在因系统Bug导致回退或协商失败的案例 。
-
获取当前值: 既然无法设置,开发者如何知道当前MTU?可以使用 peripheral.maximumWriteValueLength(for:.withoutResponse) 方法。该方法返回的是应用层有效载荷大小(即 MTU - 3)。
-
策略建议: 由于iOS不可控,外设固件应设计为"自适应"。即外设应支持较大的MTU(如247或512),然后接受iOS请求的任何数值(通常是185)。
5. 数据长度扩展(DLE)与MTU的协同效应
仅仅增加ATT_MTU并不能彻底释放BLE的性能潜力,必须配合蓝牙4.2引入的 数据长度扩展(Data Length Extension, DLE)。这是物理层吞吐量飞跃的关键。
5.1 DLE 的工作机制
DLE 允许链路层数据包的 Payload 从 27 字节扩展到 251 字节 。
- 协商过程(LL_LENGTH_REQ/RSP): 这是一个链路层控制过程(Link Layer Control Procedure),独立于ATT MTU协商。主机(手机)或控制器(外设)交换各自支持的 MaxRxOctets(最大接收字节数)和 MaxTxOctets(最大发送字节数)。
- 物理意义: 这意味着无线电波(Radio)一次开启(Tx Window)可以连续发送更多的数据位,而不是频繁地开启/关闭/切换频率。
5.2 MTU 与 DLE 的四种组合场景分析
为了直观展示两者的关系,我们分析以下四种场景:
| 场景 | ATL_MTU | DLE (LL Payload) | 行为与效率分析 |
|---|---|---|---|
| A: 传统模式 | 23 字节 | 27 字节 (Default) | 低效。数据被切除,每个包包含大量头部(前导、地址、CRC)。有效载荷比率 ≈ 36%。 |
| B: 瓶颈模式 | 23 字节 | 251 字节 (Enabled) | 极低效。物理层有能力发大包,但应用层每次只喂给它20字节数据。物理帧大部分为空或极短,浪费了 DLE 的能力,且增加了空口交互次数。 |
| C: 软分片模式 | 247 字节 | 27 字节 (Default) | 中等。应用层一次提交大量数据,减少了系统调用开销。但L2CAP层必须将其切分为 ~10 个物理小包。虽然比场景A好(减少了ATTL2CAP头部重复),但物理层头部开销依然很高。 |
| D: 高速模式 | 247 字节 | 251 字节 (Enabled) | 最佳实践。应用层数据包(247+3=250字节)几乎完美填充一个物理帧(251字节)。L2CAP不分片或仅极少分片。有效载荷比率 ≈ 90%。 |
实际使用注意:
- 同步开启: 追求高吞吐量时,必须同时 增大 ATT_MTU 和启用 DLE。
- 数值匹配: 最佳的 ATT_MTU 设置应匹配 DLE 的能力。公式为:Optimal ATT_MTU = DLE_Payload_Size - L2CAP_Header_Size(4) = 251 - 4 = 247。这解释了为什么 247 字节 是BLE开发中的一个"魔术数字" 。
6. 吞吐量数学模型与影响因子
为了在实际开发中预估传输速度,我们需要建立基于时间的数学模型。
6.1 理论吞吐量计算公式
BLE的吞吐量由以下核心公式决定:
Throughput (bps) = Data per Interval × 8 Connection Interval \text{Throughput (bps)} = \frac{\text{Data per Interval} \times 8}{\text{Connection Interval}} Throughput (bps)=Connection IntervalData per Interval×8
其中:(该值为链路层理论上限,实际吞吐通常受 OS 调度、控制器实现限制)
Data per Interval = Packets per Event × User Payload per Packet \text{Data per Interval} = \text{Packets per Event} \times \text{User Payload per Packet} Data per Interval=Packets per Event×User Payload per Packet
6.2 关键影响因子
1M PHY: 传输1 bit 需要 1 µs。
2M PHY: 传输1 bit 需要 0.5 µs。
影响: 使用2M PHY,发送同样大小(如251字节)的数据包,其占用空口的时间(Air Time)减半。这意味着在固定的连接间隔内,可以塞入更多的数据包。
6.2.2 时间参数与帧间间隔(T_IFS)
BLE规定两个连续数据包之间必须有 150 µs 的帧间间隔(T_IFS)用于射频切换(TX -> RX 或 RX -> TX)。
-
一个完整的数据交互周期 = Tx Packet Time + T_IFS + Rx Packet Time (ACK) + T_IFS。
-
对于 Write Without Response(无应用层ACK),链路层仍需回复空的ACK包(约40-80µs)。
6.2.3 连接间隔(Connection Interval)
- 范围:7.5ms - 4.0s。
- 误区: 间隔越短越好。
- 真相: 如果设备的MCU处理能力强,且支持在一个间隔内发送多个包(Multi-packet per Interval),较长的间隔(如30ms或50ms)可能比7.5ms更有效率。因为每个间隔开始时都有唤醒开销,较长间隔减少了这种开销的占比,允许更长的连续突发传输 。
6.2.4 操作系统限制(Packets per Event)
- iOS限制: 早期iOS限制每个间隔最多4-6个包。但在iPhone 11及后续机型,配合高性能模式,这一限制已大幅放宽,取决于信道质量 。
- Android限制: 取决于蓝牙芯片厂商(Qualcomm, MTK等)。旗舰机型通常能填满连接事件的最大时长。
6.3 算例对比
场景:1M PHY, 连接间隔 30ms
-
未优化(MTU 23, 无 DLE):
- 包长:37字节(296 bits) -> 296 µs。
- 周期: 296 + 150 + 80 ( ACK ) + 150 = 676 μ s 296 + 150 + 80 (\text{ACK}) + 150 = 676 \mu s 296+150+80(ACK)+150=676μs。
- 30ms内理论最多包数: 30000 / 676 ≈ 44 30000 / 676 \approx 44 30000/676≈44 个。
- 每包有效数据:20字节。
- 极限吞吐: 44 × 20 / 0.03 ≈ 29.3 KB/s 44 \times 20 / 0.03 \approx 29.3 \text{ KB/s} 44×20/0.03≈29.3 KB/s。
- 注:实际因系统调度远达不到44个包,通常只能发4-6个,导致实际速度仅 2-4 KB/s。
-
全优化(MTU 247, DLE 251, 2M PHY):
- 2M PHY下,251字节数据包(加上头尾约265字节)传输耗时约 1100 µs。
- 周期: 1100 + 150 + 44 ( ACK ) + 150 ≈ 1444 μ s 1100 + 150 + 44 (\text{ACK}) + 150 \approx 1444 \mu s 1100+150+44(ACK)+150≈1444μs。
- 30ms内理论包数: 30000 / 1444 ≈ 20 30000 / 1444 \approx 20 30000/1444≈20 个。
- 每包有效数据:244字节。
- 极限吞吐: 20 × 244 / 0.03 ≈ 162 KB/s 20 \times 244 / 0.03 \approx 162 \text{ KB/s} 20×244/0.03≈162 KB/s。
结论: 优化MTU、DLE和PHY可以将吞吐量提升一个数量级(从~3KB/s 到 ~160KB/s)。
7. 实际开发中的作用与优化策略
基于上述原理,我们在实际工程中可以提炼出以下核心策略。
7.1 OTA 固件升级的最佳实践
OTA是BLE应用中对MTU最敏感的场景。
- 协商最大值: 固件端应配置支持 DLE (251) 和大 MTU (如 247 或 517)。允许手机端协商出其支持的最大值。
- 指令选择: 必须使用 Write Without Response (Command) 。Write Request (带响应) 引入了应用层的RTT(往返时延),会严重拖慢速度(通常降至 <1KB/s)。
- 应用层流控 (Application Flow Control): 这是一个极易被忽视的关键点。
- 问题: 使用 Write Without Response 时,如果发送速度超过了底层协议栈或空口的处理能力,数据包会在发送缓冲区溢出并被静默丢弃,导致固件校验失败。
- iOS 方案: 利用 peripheralIsReady(toSendWriteWithoutResponse:) 回调。当 canSendWriteWithoutResponse 属性变为 false 时,停止写入;等待回调触发后再恢复写入 。这是iOS提供的高效背压(Backpressure)机制。
- Android 方案: Android 13/14 引入了类似的流控回调,但在旧版本上,通常需要手动实现"令牌桶"算法,或者采用"每发送N个无响应包,插入一个带响应的写请求"的混合策略,利用该响应作为同步点,防止缓冲区溢出 。
7.2 功耗与能效优化
MTU 越大,单次传输的耗时越长,这是否意味着功耗更高?
- 能效比(Energy per Bit): 事实上,大MTU 更省电。
- 原因: 射频电路(Radio)的开启和关闭有固定的能量损耗(Ramp-up/Ramp-down)。发送一个小包需要经历完整的 开启-发送-关闭 流程。发送一个大包虽然发送时间长,但分摊了开启和关闭的固定损耗。
- 数据: 根据实测,使用大MTU配合2M PHY,传输相同数据量的总功耗可降低 15% - 20% 。因为设备能更快地完成传输任务,更早地进入休眠状态。
7.3 内存管理
在资源受限的嵌入式设备(如 RAM < 32KB 的 SoC)上,盲目追求 517 字节 MTU 是危险的。
- BLE 协议栈通常需要为每个连接实例分配 Rx/Tx 缓冲区。
- 如果 MTU = 517,每个连接可能额外消耗 1KB+ 的 RAM。对于支持多连接的网关设备,这可能导致内存耗尽(OOM)。
- 建议: 如果不需要极高的吞吐量,将 MTU 限制在 247 字节 是一个兼顾性能与内存的最佳平衡点。
8. 总结
BLE MTU 的实现原理深刻体现了通信协议设计中的"权衡"艺术:在受限的物理信道上,通过逻辑层的分片、适配与协商,实现高效的数据传输。
对于我们开发者而言,掌握MTU不仅仅是记住"23"和"247"这两个数字。它意味着:
- 理解分层架构: 知道数据为何被分片,知道瓶颈可能出现在链路层(无DLE)还是L2CAP层。
- 尊重平台差异: 针对 Android 的碎片化和 iOS 的封闭性设计不同的连接与协商策略。
- 全栈优化思维 : 认识到吞吐量的提升是 MTU、DLE、PHY、连接间隔以及流控算法共同作用的结果。

通过合理配置 MTU 并结合应用层流控,开发者可以将 BLE 从一个简单的"状态同步通道"升级为"高速数据管道",从而支撑起 OTA、音频传输等复杂应用场景,极大提升产品的用户体验与竞争力。
激励自己:
真正拉开工程师差距的,从来不是 API 调用,而是对协议栈每一层"为什么这样设计"的理解。
9.相关推荐
想系统了解BLE可阅读下面文章
(一)蓝牙的发展历史
(二)蓝牙架构概述-通俗易懂
(三)BLE协议栈协议分层架构设计详解
(四)BLE的广播及连接-通俗易懂
(五)图文结合-详解BLE连接原理及过程
(六)BLE安全指南:别让"配对降级"和硬件I/O毁了安全等级(BLE SMP)
(七)Nordic实战--保姆级教程:nRF Connect SDK 开发环境搭建全指南