1. 课程导论:BLE低功耗设计概述、GATT协议栈架构、休眠唤醒机制的价值

各位工程师朋友,欢迎来到《BLE GATT服务休眠唤醒低功耗设计实战》的第一章。

做蓝牙低功耗(BLE)开发这些年,我见过太多产品死在功耗上。功能都调通了,连上了,跑起来了,结果一测电流——几十毫安。老板问:“这跟经典蓝牙有什么区别?” 嗯,场面一度很尴尬。

所以这门课,咱们不聊虚的。直接切入BLE低功耗设计的核心痛点:GATT服务怎么在休眠唤醒的节奏下,把功耗压到极致。

1.1 BLE低功耗设计:不只是“省电”两个字

很多人觉得BLE低功耗就是“少发数据”、“把广播间隔拉长”。其实没那么简单。

BLE的低功耗,本质上是一种时间分片的工作哲学。设备大部分时间在睡觉,醒来快速干完活,再睡回去。这个“睡-干-睡”的节奏,决定了你的产品能撑一周、一个月,还是一年。

我个人习惯把BLE功耗拆成三块来看:

  • 连接事件功耗:主从设备约定时间点交换数据,这是BLE最核心的功耗来源。
  • 广播/扫描功耗:设备还没建立连接时,靠广播包刷存在感。刷得越勤,电掉得越快。
  • 空闲态功耗:啥也不干的时候,芯片能不能进入深度睡眠。很多新手栽在这一块。

核心观点:BLE低功耗设计的本质,不是“少干活”,而是“干完活立刻睡,睡到下次该干活再醒”。GATT服务的设计,必须围绕这个节奏来展开。

我在项目中遇到过一款智能门锁,连接态功耗做到20μA以下,但客户反馈电池只能用两个月。查了半天,问题出在GATT服务上——每次唤醒后,服务要枚举所有特征值,耗时200ms。这200ms里,芯片全速跑,电流十几毫安。一天唤醒几十次,功耗全耗在“起床穿衣服”上了。

你看,GATT服务的设计,直接决定了休眠唤醒的效率。

1.2 GATT协议栈架构:从Profile到Attribute

聊休眠唤醒之前,得先把GATT的底子打牢。GATT(Generic Attribute Profile)是BLE应用层的核心框架。说白了,它定义了数据怎么组织、怎么读写、怎么通知。

GATT的架构,我习惯用“三层嵌套”来理解:

  1. Profile(服务集合):一个产品通常包含多个服务。比如心率计有心率服务、电池服务、设备信息服务。
  2. Service(服务):一组相关特征值的集合。每个服务有唯一的UUID。
  3. Characteristic(特征值):真正存数据的地方。包含值、属性、描述符。

你想想看,GATT本质上就是一棵树。树根是Profile,树枝是Service,树叶是Characteristic。数据就挂在树叶上。

下面这张图,帮你把GATT协议栈的层次关系看清楚:

GATT协议栈架构图 应用层(Application) 智能手环 / 传感器 / 门锁 / 医疗设备 GATT层(Generic Attribute Profile) Profile → Service → Characteristic → Descriptor 数据读写 / 通知 / 指示 / 广播包封装 ATT层(Attribute Protocol) 属性句柄 / 类型UUID / 权限 / 值 L2CAP / HCI / Link Layer / PHY 数据分片 / 重传 / 跳频 / 调制解调 数据流向:应用 → GATT → ATT → 空中

这张图里,从上到下是数据封装的过程。应用层的数据,经过GATT组织成服务/特征值,再通过ATT协议挂到属性表上,最后通过L2CAP和Link Layer发出去。

反过来,接收数据时,数据从空中进来,一路解包,最终回到应用层。

避坑提示:很多开发者把GATT服务和ATT属性表混为一谈。其实GATT是“逻辑组织”,ATT是“物理存储”。GATT告诉你数据长什么样,ATT告诉你数据放在哪、怎么访问。休眠唤醒时,我们操作的是ATT属性表,但设计时要按GATT的层次来规划。

1.3 GATT Profile的结构细节

咱们再深入一层。一个典型的GATT服务,内部长这样:

层级 元素 说明 休眠唤醒关注点
Service UUID + 包含的特征值列表 服务的唯一标识,如0x180D(心率) 服务声明属性在唤醒后需快速可访问
Characteristic 声明 + 值 + 描述符 声明包含属性、UUID、值句柄 值句柄的缓存策略影响唤醒速度
Value 实际数据(最长512字节) 传感器读数、状态标志等 唤醒后是否需要重新读取?还是用缓存?
Descriptor CCC配置、用户描述等 CCC决定是否使能通知/指示 CCC状态必须在休眠期间保持

这里有个关键点:CCC(Client Characteristic Configuration)描述符。它决定了设备要不要主动给手机发数据。很多低功耗设计翻车,就是因为休眠后CCC状态丢了,醒来后手机收不到通知,还以为设备死了。

我曾经调试过一个血压计项目,休眠后唤醒,手机收不到测量结果。查了两天,发现是CCC描述符在休眠时被清空了。解决方案很简单:把CCC状态保存在非易失区,唤醒后恢复。但就是这个小细节,功耗曲线直接从平滑变成锯齿状。

1.4 休眠唤醒机制的价值:为什么这门课值得你花时间?

好,咱们回到最根本的问题:为什么要在GATT服务层面专门讲休眠唤醒?

直接说结论:BLE芯片的休眠电流已经做到1μA以下了,但你的产品功耗还是下不来。瓶颈不在芯片,在软件架构。

我见过太多案例:

  • 芯片休眠电流0.5μA,整机平均功耗50μA。差了两个数量级。
  • 问题出在哪?GATT服务在唤醒后做了大量冗余操作:重新注册服务、重新枚举特征值、重新建立安全连接。
  • 这些操作,每多一次,就多耗几毫秒。几毫秒的全速运行电流,抵得上几小时的休眠。

休眠唤醒机制的价值,可以归纳为三点:

  1. 缩短唤醒窗口:从“醒来做所有事”变成“醒来只做必要事”。GATT服务的初始化流程必须精简。
  2. 保持连接状态:休眠期间不丢连接参数、不丢CCC状态、不丢服务缓存。醒来后直接恢复,不用重新握手。
  3. 按需加载服务:不是所有服务都需要在每次唤醒时加载。低频服务可以延迟加载,甚至只在需要时加载。

警告:不要以为休眠唤醒只是“调一下睡眠模式”那么简单。GATT服务的状态机、属性表的缓存策略、连接参数的协商时机,每一个环节都可能成为功耗黑洞。这门课后面会逐一拆解。

嗯,说到这里,我想起一个典型的对比案例。同样是温湿度传感器,A方案用标准GATT服务,每次唤醒都重新注册所有特征值,平均功耗12μA。B方案做了休眠唤醒优化,服务状态保持,唤醒后只更新数据,平均功耗2.3μA。同样的芯片,同样的传感器,功耗差了5倍。

这就是咱们这门课要解决的问题。

1.5 本章小结

这一章,咱们把BLE低功耗设计的核心逻辑、GATT协议栈的层次结构、以及休眠唤醒机制的价值捋了一遍。

记住三个关键点:

  • BLE低功耗的本质是时间分片,GATT服务必须适配这个节奏。
  • GATT架构是Profile → Service → Characteristic的三层树形结构,休眠唤醒时要关注每一层的状态保持。
  • 休眠唤醒优化的价值在于缩短唤醒窗口、保持连接状态、按需加载服务。