1. 蓝牙协议栈概述:BLE技术演进、核心规范解读、协议栈分层架构
各位同学,欢迎来到《蓝牙GATT服务开发实战》的第一章。我是你们这门课的主讲,一个在嵌入式蓝牙领域摸爬滚打了十来年的老工程师。今天咱们不聊虚的,直接切入正题——先把蓝牙协议栈这个“地基”给夯实了。
很多新手一上来就急着写代码,结果遇到连接不稳定、数据丢包、功耗下不来,回头才发现是协议栈理解不到位。我当年也吃过这个亏,所以这一章,咱们把BLE的来龙去脉、规范长什么样、协议栈怎么分层,一次性说清楚。
1.1 BLE技术演进:从经典蓝牙到低功耗蓝牙
蓝牙技术从1994年诞生到现在,走了快三十年。我个人习惯把它分成三个阶段来看:
- 经典蓝牙(BR/EDR):最早期的版本,主打语音和文件传输。功耗高,连接建立慢,适合耳机、音箱这类设备。
- 高速蓝牙(HS):在2.1+EDR基础上加了802.11的物理层,速度上去了,但功耗依然不低。
- 低功耗蓝牙(BLE):从4.0开始引入,这才是咱们这门课的主角。它不是为了取代经典蓝牙,而是开辟了一个全新的应用场景——物联网。
为什么BLE能火?说白了,它把功耗做到了极致。一颗纽扣电池能让传感器跑一年甚至更久。你想想看,智能手环、温湿度计、门锁,这些设备要是用经典蓝牙,三天换一次电池,谁受得了?
| 特性 | 经典蓝牙(BR/EDR) | 低功耗蓝牙(BLE) |
|---|---|---|
| 诞生版本 | 1.0(1999) | 4.0(2010) |
| 峰值速率 | 2~3 Mbps | 1~2 Mbps(5.0后可达2M PHY) |
| 连接建立时间 | ~100 ms | ~3 ms |
| 典型功耗 | ~30 mA | ~5 μA(待机) |
| 主要应用 | 音频、文件传输 | 物联网、传感器、可穿戴 |
核心观点:BLE不是蓝牙的“升级版”,而是蓝牙的“轻量版”。它牺牲了速率和音频能力,换来了极低的功耗和极快的连接速度。做GATT开发,你面对的基本都是BLE设备。
1.2 核心规范解读:BLE规范到底在说什么?
蓝牙规范(Bluetooth Core Specification)是一本上千页的“天书”。我第一次看的时候,说实话,头都大了。但后来我发现,做GATT开发,你不需要把整本规范背下来,抓住几个核心部分就够了。
规范主要分为两大块:
- Controller(控制器):负责物理层和链路层的实现。这部分通常由芯片厂商搞定,咱们应用开发者基本不碰。
- Host(主机):包括L2CAP、ATT、GATT、SM、GAP等协议层。这才是咱们写代码要打交道的地方。
嗯,这里要注意一个关键点:GATT是建立在ATT之上的。ATT定义了“属性”怎么读怎么写,而GATT定义了这些属性怎么组织成“服务”和“特征值”。说白了,ATT是快递员,GATT是仓库管理员——快递员只管送货,仓库管理员决定货怎么摆。
我的经验:刚开始做项目时,我总把GATT和ATT混为一谈。后来踩了一个坑——在ATT层直接操作句柄,结果服务结构乱了,手机端读到的数据全是错的。从那以后,我坚持只用GATT API,绝不去碰底层的ATT句柄。这个习惯帮我省了不少调试时间。
1.3 协议栈分层架构:每一层都在干什么?
BLE协议栈的分层架构,我画了一张图,你一看就明白了。
咱们从上往下,一层一层说清楚。
1.3.1 物理层(PHY)
这是最底层,负责在2.4GHz频段上发送和接收无线信号。BLE在4.0/4.1/4.2时代用的是1M PHY,到了5.0引入了2M PHY,速率翻倍。但速率高了,覆盖距离会缩短。我在项目中做过对比,2M PHY在室内隔一堵墙就开始丢包,1M PHY反而稳得很。所以别盲目追求高速率,得看实际场景。
1.3.2 链路层(LL)
LL负责设备间的连接管理、数据包封装、重传、加密等。它定义了五种状态:待机、广播、扫描、发起、连接。你想想看,一个蓝牙设备要跟另一个设备通信,得先广播自己的存在,另一个设备扫描到后发起连接请求,然后双方进入连接状态——这一整套流程,都是LL在管。
避坑指南:我曾经在一个项目中,广播间隔设得太短(20ms),结果功耗飙升,电池两天就耗光了。后来把广播间隔调到200ms,功耗降了80%,连接成功率也没受影响。记住:广播间隔不是越短越好,得在功耗和响应速度之间找平衡。
1.3.3 主机控制器接口(HCI)
HCI是Host和Controller之间的“翻译官”。它定义了一套标准的命令和事件格式。Host通过HCI命令告诉Controller“我要开始广播了”,Controller通过HCI事件告诉Host“我收到一个连接请求了”。
在实际开发中,如果你用的是单芯片方案(比如Nordic的nRF52系列),HCI是内部接口,你基本感觉不到它的存在。但如果你用的是双芯片方案(比如Host跑在Linux上,Controller用TI的CC2540),那HCI就是你必须打交道的部分。
1.3.4 逻辑链路控制与适配协议(L2CAP)
L2CAP在Host层,它负责把上层的数据拆分成适合底层传输的包,也负责把底层的包重组后交给上层。它还提供了通道复用功能——多个上层协议可以共用同一条L2CAP通道。
对于GATT开发来说,L2CAP的MTU(最大传输单元)是个重要参数。默认是23字节,但你可以通过MTU协商把它提高到512字节甚至更大。我建议你在项目初期就把MTU协商逻辑写好,否则后面要传大数据时会很痛苦。
1.3.5 属性协议(ATT)
ATT定义了“属性”这个概念。一个属性包含:句柄(Handle)、类型(UUID)、权限(Permissions)、值(Value)。ATT提供了六种操作:请求、响应、命令、通知、指示、确认。
这里有个容易混淆的点:通知(Notify)和指示(Indicate)的区别。通知不需要接收方确认,速度快但不可靠;指示需要接收方确认,速度慢但可靠。我在做血糖仪项目时,数据必须100%到达,所以用了指示;而在做心率带项目时,数据丢了就丢了,下一包会补上,所以用了通知。
1.3.6 通用属性协议(GATT)
终于到了咱们这门课的核心。GATT在ATT之上建立了一套数据组织规范。它定义了三个基本概念:
- 服务(Service):一组相关特征值的集合。比如“电池服务”包含“电池电量”这个特征值。
- 特征值(Characteristic):一个包含值和描述符的数据单元。比如“电池电量”特征值,它的值就是0~100的整数。
- 描述符(Descriptor):对特征值的补充说明。比如“客户端特征配置描述符(CCCD)”用来开启或关闭通知。
一句话总结:GATT就是蓝牙世界的“数据库”。服务是表,特征值是字段,描述符是字段的元数据。你写GATT服务,本质上就是在设计这个数据库的结构。
1.4 本章小结
这一章咱们把BLE协议栈的来龙去脉和分层架构捋了一遍。从PHY到GATT,每一层各司其职,共同构成了BLE通信的完整链路。做GATT开发,你不需要精通每一层,但必须知道每一层是干什么的——这样出了问题才知道往哪一层去排查。