
做低功耗蓝牙产品绕不开芯片选型和低功耗架构这两座大山。最近在整理一个基于 CH592 的集成方案把 RISC-V 内核、BLE 5.4 协议栈、传感器采集、HID 外设这些模块拼到一起踩了不少坑也沉淀了一套靠谱的设计路径。这篇东西不聊太虚的理论直接讲我实际怎么选型、怎么算功耗、怎么把 TMOS 用顺以及调试时那些让人抓狂的问题该怎么定位。CH592 是沁恒推出的一款单模低功耗蓝牙 MCU本质上是把 Cortex-M 换成 RISC-V 内核再集成完整的 BLE 协议栈、射频收发器和丰富外设。它的目标很明确用一颗芯片搞定大部分物联网节点、智能穿戴、键鼠遥控器这类应用而不是像传统方案那样必须配一颗主控 MCU 外加一颗蓝牙透传模块。对工程师来说这篇文章适合正在做 BLE 产品选型、第一次接触沁恒蓝牙 SDK、或者想把产品待机功耗从毫安级压到微安级的朋友。1. 项目定位与芯片选型思路1.1 为什么是 CH592 而不是“STM32 蓝牙模块”不少工程师习惯用熟悉的主控再加外置蓝牙模块比如 STM32 配 HC05、配杰理或配其他厂家的透传模块。这套老组合开发速度快、资料多但问题也很明显两套系统、两个电源域模块待机功耗很难压下去串口透传还有波特率匹配和流控问题。之前我帮人排查过一个“HC05 蓝牙模块连不上”的案例最后发现是主控串口初始化时序和模块默认波特率没对齐这种问题在单芯片方案里基本不会出现。选 CH592 做集成方案核心原因是它把 MAC、基带、协议栈、射频都封装在同一颗裸片里应用代码直接跑在同一个内核上没有跨芯片通信的中间层。这样有三点实打实的收益物料成本降低PCB 面积缩小系统待机功耗可控。要强调的是这里的“可控”不是因为芯片本身待机电流数值好看而是你不需要为了保持主控和蓝牙模块通信而让任何一侧持续醒来整个系统可以做到真正的按需唤醒。另外RISC-V 内核的适配成本没有想象中高。沁恒自家 MounRiver Studio 基于 Eclipse 魔改装好就能编译、下载、调试配合 WCH-Link 调试器体验和 STM32CubeIDE 那套差异不大。第一次上手的人可能会对 SDK 里的任务调度方式感到陌生但这是学习曲线问题不是能效问题。1.2 单芯片方案与双芯片方案的取舍集成方案并不意味着一律单芯片要分场景。CH59x 系列里CH592 和 CH591 的定位就有差异。CH591 的 RAM 和 Flash 更小适合做透传桥、遥控器这类轻应用CH592 资源更充裕适合做本地传感器采集、复杂 HID 外设和需要较多缓冲区的场景。单芯片方案的结构是传感器直接接在 CH592 的 GPIO 或 ADC 上采集逻辑、数据处理、BLE 通信都在一颗芯片内完成。好处不用多说坏处是如果产品主控原本有一套成熟逻辑迁到新平台需要全部重写。这种情况不如保守一些让原主控继续干活CH592 只负责蓝牙链路两边用 UART 或 SPI 沟通。我个人的判断标准是如果产品逻辑简单到一颗小内核能跑完果断单芯片如果主控已经有 RTOS、文件系统、复杂状态机硬往 CH592 上塞只会增加调试难度。做集成方案不是炫技怎么省事怎么来双芯片之间只要把协议层定义清楚比如用自定义串口帧封装 payload可靠性一样很高。1.3 资源评估与外设规划很多人画完原理图才发现引脚不够用这是资源评估没做细。CH592 的外设其实够丰富有常规 UART、SPI、I2C、ADC、PWM 和 USB 控制器但一颗芯片的引脚就那么多。我的经验是先列一张“外设资源占用表”把所有需要用到的功能写清楚哪些是固定的调试引脚哪些用于射频和晶振哪些给传感器协议哪些给状态指示灯和按键。比如做一把蓝牙机械键盘就需要考虑按键矩阵需要十几到二十几个 GPIORGB 灯需要额外的 PWM 或 SPI 通道电量检测要一个 ADC 通道可能还要留一个 UART 做固件升级。如果把矩阵扫描、HID 报告和低功耗休眠都放在一起设计GPIO 和定时器资源的冲突就会提前暴露。早期做规划比在布线阶段改原理图省太多时间。2. 低功耗设计的底层逻辑与关键指标2.1 芯片功耗的构成不要只看待机电流很多选型的人第一眼只盯着芯片手册上的“Sleep 模式典型电流 0.3uA”这种数字觉得够低就下单。实际上一个 BLE 节点的平均功耗是由三部分组成的射频收发时的瞬时电流、MCU 活动时的电流、以及真正的睡眠电流。CH592 在 RX/TX 时的峰值电流在十毫安级别哪怕每次只持续 1-2ms如果事件间隔很短平均功耗依然可观。也就是说低功耗设计的核心不是选择一颗睡眠电流最低的芯片而是尽量压缩射频活跃时间和 CPU 活跃时间让系统绝大多数时间真正睡在最低功耗档位。这个道理说起来简单实践中最容易翻车比如调试阶段用串口 printf 打印调试信息每打印一条就把芯片从低功耗模式拉起来一次再比如事件循环里写了 delay 延时轮询CPU 一直在跑功耗直接飙到毫安级。2.2 平均功耗的计算方法一个可以直接套用的公式产品做功耗评估时我会用一个简化公式来算平均电流I_avg (T_adv * I_adv T_conn * I_conn T_sensor * I_sensor T_sleep * I_sleep) / T_cycleT_adv 是广播事件持续时间I_adv 是广播时的瞬时电流T_conn 是连接事件持续时间I_conn 是连接时的电流T_sensor 和 I_sensor 是本地采集任务的开销剩下时间全部是睡眠。举一个实际例子假设广播间隔 100ms每次广播持续约 1.2ms广播电流 12mA睡眠电流 0.5uA那么广播带来的平均电流就是 1.2/100 * 12mA ≈ 0.144mA。如果广播间隔改成 20ms平均广播电流就变成 0.72mA差距立刻拉大。这就是为什么很多低功耗产品在广播阶段会采取“快速广播唤醒 慢速广播等待”的策略刚上电时用高频率广播快速被手机找到几秒后切到低频率广播搜不到设备时干脆停止广播进入深度休眠。这个策略对应到代码里就是状态机的切换可以在 TMOS 定时事件里实现。2.3 连接参数对功耗的影响连接间隔与从机延迟一旦手机和设备建立了连接功耗主要由连接间隔、从机延迟Slave Latency和数据量决定。连接间隔越短双方通信越频繁实时性越好但平均电流越高。从机延迟允许从机跳过若干次连接事件同时不丢失数据这是低功耗传感器项目的救星。举个例子连接间隔设成 30ms这意味着一秒内约有 33 个连接事件。如果从机延迟设为 4从机可以连续跳过 4 个事件只在第 5 个事件时醒来处理数据有效唤醒频率从 33Hz 降到约 6.6Hz。对温度、湿度、电量这类周期性上报的数据来说这个实时性完全够用功耗却能下降 80% 左右。但要注意从机延迟过大也会拉长数据传输时延所以做远程遥控时不能设太大否则按键响应会有明显延迟。2.4 一个特别容易忽略的漏电路IO 引脚配置这是我在实测里栽过跟头的点。芯片睡着之后功耗却比手册标称值高十倍以上反复查了电路也没发现问题最后用电流表逐个引脚排查发现是把一个未使用的 GPIO 设成了输入且内部上拉关闭引脚悬空后电平不定内部的输入缓冲电路一直在产生漏电。正确做法是所有不用的 GPIO 要么配置成模拟输入要么软件里配置为输出低电平绝不能有悬空的输入引脚。另外外部按键接内部上拉时建议把上拉开关和按键电平检测联动起来按键按下时才产生电流路径。还有一点分压电阻测电池电压也是常见漏电源两个分压电阻如果阻值太小会一直有毫安级电流损耗所以在电池电压检测回路里尽量用兆欧级电阻或者通过 MOS 管控制分压网络只在采样瞬间打开。3. TMOS 事件驱动架构的集成要点3.1 TMOS 是什么一套轻量级事件调度器接触沁恒蓝牙 SDK 的人肯定会遇到 TMOS全称大概是 Task Management OS一套极简的事件驱动调度机制。它不像 FreeRTOS 那样有抢占式多任务、信号量、队列它的模型更轻应用程序由若干个任务组成任务之间通过事件标志来触发系统提供了定时服务到点之后给对应任务发送定时事件。用生活化的类比TMOS 像一个前台接线员所有来电事件都先推给接线员接线员按照登记顺序把电话转给对应的办公室任务。办公室里一次只处理一件事处理完了把手头工作交还给接线员接线员继续处理下一件。这个模型天然就是协作式的没有任务抢占带来的竞争问题对资源有限的蓝牙 SoC 来说极度合适。一开始写代码时总会不自觉地想用 while(1) 空转或者 HAL_Delay 延时这在 TMOS 里是反模式。正确思路是把整个应用拆解成任务和事件靠定时器驱动 STAT 机运转。比如按键扫描与其在循环里轮询不如注册一个 10ms 的定时事件每次触发时扫描一次按键矩阵检测到变化后再决定是否发送 HID 报告。3.2 TMOS 的核心 API 使用心得SDK 里常用的几个接口需要理解透彻。tmos_start_task 用于注册一个带初始延时的任务事件tmos_set_event 用于立即向某个任务发送事件tmos_start_task 配合周期触发可以实现软件定时器。官方例程里还会出现类似 tmos_set_task 的变体作用大同小异但参数里的事件 ID 和间隔单位要看清。实际写代码时我见过不少新手把这几个 API 混着用导致事件重复触发或者定时任务永远停不下来。比如在一个周期事件的处理函数末尾再次调用 tmos_start_task 来实现周期定时如果参数不对就可能在同一事件周期里注册了两份定时器后一次触发时事件队列里堆了两次事件功耗和逻辑都会出问题。我的经验是周期任务只在一个地方注册事件处理函数内部不要轻易递归式注册要把超时事件当作一个独立的状态转移触发点而不是定时器回调。3.3 把项目拆成哪些任务是合理的做集成方案时任务划分直接影响低功耗表现。按我的习惯一个典型的 CH592 项目会划分成以下几个任务BLE 协议栈任务SDK 自带、应用主任务管理状态机和业务逻辑、外设采集任务传感器数据读取、上报/存储任务处理数据帧。蓝牙协议栈任务由 SDK 内部维护这部分不要动。应用主任务负责收到广播连接事件、传感器事件后决定系统进入哪个状态可以进入睡眠、切换广播参数、启动传感器采集。外设采集任务和上报任务使用 TMOS 定时事件周期性唤醒采集完成后立刻回到睡眠。这样系统的每个功能模块都只在需要时被事件驱动不会出现一个 while 循环把整个芯片拖死的情况。3.4 事件驱动的技巧状态机与功耗联动事件驱动和状态机是天生一对。我习惯在每个任务内维护一个简单的枚举状态机比如“IDLE、ADVERTISING、CONNECTED、SENSOR_READING、SLEEPING”。事件触发时根据当前状态决定如何处理。比如定时广播事件触发时如果状态是 CONNECTED就忽略广播相关逻辑如果电量低于阈值就切到低功耗广播参数。这样写还有一个附加好处睡眠逻辑可以被统一管理。系统进入 SLEEPING 状态之前统一关闭外设电源、配置所有 IO 低功耗模式、确保没有挂起的定时事件然后调用进入睡眠的接口。换句话说低功耗不是写代码时临时的优化而是在状态机设计过程中自然形成的约束条件。4. BLE 协议栈集成与典型场景实现4.1 服务与特征值的规划透传还是 HID集成方案里最常用的两种蓝牙应用是数据透传和 HID 外设。透传方案一般基于自定义 Service用两个特征值分别接收和发送数据一个负责 Write一个负责 Notify。这种方案灵活适合传感器数据上报或者手机 App 互联。HID 方案则要遵循蓝牙 HID Profile通常用于键盘、鼠标、遥控器这类人机交互设备。两者不能混为一谈。HID 设备需要在 GATT 服务里包含 HID Service、Report Map、HID Report 特征、Battery Service 等结构相对固定但好处是手机、电脑、电视等主机无需安装 App系统自带蓝牙驱动就可以识别。透传服务则灵活得多但主机侧必须跑你自己写的 App 或上位机软件。选型时如果产品既是传感器上报又要兼容手机原生控制可以考虑同时实现两个服务只是初始化代码量会增加不少。4.2 MTU 协商影响吞吐量的隐形瓶颈很多刚开始用 BLE 透传的工程师会疑惑明明理论速率能到几十 KB/s为什么实际传数据慢得离谱多数原因是 MTU 没协商。默认状态下的 PHY Attribute MTU 只有 23 字节去掉 ATT 头之后一次有效负载只有 20 字节。如果数据量大这样的单包开销会极大限制吞吐量。正确做法是在连接建立后主动发起 MTU 交换请求。比如协商到 247 字节单包负载变成 244 字节同样是传 4KB 数据耗时会从几百包降到十几包功耗和速度都改善。需要注意的是MTU 开大之后协议栈内部的收发缓冲区也会变大这对 RAM 有限的 MCU 来说是占资源的。CH592 的内存虽然不像 PC 那么充裕但规划好缓冲区大小支持 247 字节 MTU 还是可行的。我之前在一个透传项目里把接收缓冲区和发送缓冲区分开配置实测吞吐量提升了好几倍。4.3 HID 键盘与低功耗的配合做 HID 键盘之类的设备要特别注意按键矩阵扫描、去抖和休眠的逻辑。有人直接把按键扫描放在主循环里轮询导致芯片几乎无法睡眠。用 TMOS 的思路应该是每 10ms 或 20ms 定时唤醒一次扫描矩阵扫描完成后立刻回到睡眠。因为按键事件本身是稀疏的一个 20ms 的扫描周期带来的平均功耗很小。键值变化后通过 HID 报告发送到主机这个时机很重要。主机侧对 HID 报告的轮询间隔由连接间隔决定如果连接间隔太长键盘手感会变差。一般建议把键鼠这类交互设备的连接请求间隔设到 7.5ms 到 15ms 之间虽然功耗会略高但用户体验优先。另外HID 设备还要处理好从连接状态断开后重新进入广播状态以及主动休眠唤醒主机等细节。4.4 广播与扫描策略让设备随时可连又不太耗电广播参数不是一劳永逸的。设太慢用户用手机扫描半天搜不到设备体验极差设太快待机功耗直线上升。我的建议是采用两阶段广播上电后先以 20ms 到 50ms 的快速广播持续几秒方便快速被发现如果一直没有主机连接就切换到 500ms 到 1s 的慢速广播再过一段时间还没有连接停止广播进入深度睡眠等待外部唤醒条件。广播内容的设计也要讲究。广播包里可以带上设备名称、服务 UUID、以及自定义的厂家数据。厂家数据可以用来携带设备状态比如电量、固件版本这样手机在扫描阶段就能直接显示这些信息不用等连接后再读取。但广播包容量有限能塞的数据有限需要权衡哪些信息必须放在广播里哪些放在连接后通过 GATT 读取。5. 硬件布局与调试常见问题实录5.1 天线与晶振射频性能的隐形杀手软件写得再好射频性能不行等于白做。CH592 这类 SoC 对天线匹配网络和晶振布局的要求跟其他蓝牙芯片差异不大但新手往往忽略。32MHz 主晶振要尽量靠近芯片周围不要走高速数字信号线晶振底下最好铺地避免干扰导致频率偏差。天线区域的净空要求和参考设计保持一致匹配元件要按参考设计预留位置天线走线两侧要有足够的地的过孔环绕。我见过一个项目蓝牙搜不到设备排查了半天发现是天线匹配网络与参考设计不一致导致发射功率低得可怜。改回参考设计后信号就恢复了。5.2 硬件调试串口打印和功耗实测是两件事这是我最想强调的点调试阶段用串口打印信息完全没问题但如果你想测功耗必须通过 GPIO 跳线来控制串口绝对不能在功耗测试板上直接带着调试器测量。否则芯片被调试器供电同时又不断被调试器唤醒测出来的电流数据完全不能用。真正的功耗测量方法是把 CH592 的 VDD 电源路径串入电流表或采样电阻用示波器测采样电阻两端的电压波形再结合软件打出的 GPIO 状态波形就能看清广播事件、连接事件、采集事件各自消耗的时间和电流。如果手上只有万用表就把万用表调到微安档记住它测得的是一段时间内的平均值省去繁琐采样。5.3 烧录与下载问题jtag 之类工具连接报错典型的烧录问题集中在下载时提示“MCU shutdown”或者连接失败。这类问题多数不是芯片坏了而是供电不稳定、引脚复用冲突或者调试器接触不良。比如芯片进入了深度睡眠模式调试器试图连接时芯片对调试请求没有响应就会被判断成目标不可达。这种情况下可以先让芯片退出睡眠模式比如接一根线把复位脚拉低然后释放让芯片回到初始状态再进行烧录。另一个常见问题是调试引脚和被占用的 GPIO 冲突。如果应用代码把 SWDIO/SWCLK 所在引脚复用为其他功能调试器就无法稳定连接。我的习惯是原理图阶段就把调试引脚单独引出来不接其他负载同时在下电之后才进行烧录操作。5.4 常见问题速查表现象可能原因排查思路手机搜不到设备广播未开启、天线匹配异常、晶振不起振用抓包工具看广播报文对比参考设计检查天线和晶振连接后数据交互缓慢MTU 未协商、连接间隔过大主动发起 MTU 协商申请更短的连接间隔待机功耗远高于标称值IO 引脚浮空、外设未断电、串口未关闭统一配置空闲 IO切断外设电源关闭调试串口烧录或调试连接失败芯片深度睡眠、调试引脚复用、供电不足尝试复位后再连接检查调试引脚占用确认供电电压广播阶段功耗过高广播间隔过短、广播包过长两阶段广播策略精简广播数据内容HID 设备时灵时不灵报告描述符错误、键盘矩阵扫描冲突核对 Report Map扫描周期和去抖逻辑重新调整5.5 实测功耗记录一组数据帮助校准预期最后分享一组我之前做的测量数据帮大家对数字有直观感知。一个传感器节点使用 CH592连接间隔 50ms、从机延迟 4、每 10 秒上报一次传感器数据每次上报大约需要 10 个连接事件。实际测下来平均电流约为 18uA两节 AA 电池供电约能跑一年以上。而同样场景下如果把连接间隔改成 20ms、从机延迟设为 0上报间隔不变平均电流立刻升到约 60uA。这说明连接参数对寿命的影响非常大调优前后可以差出三倍以上。这个经验值建议大家在自己的项目里复测因为天线效率、电源转换效率、传感器耗电流都不同但趋势是一致的。做低功耗蓝牙集成方案我越来越觉得软件和硬件的边界是模糊的。搞定了 TMOS 的任务拆分搞定了 GPIO 漏电的坑射频走线再注意一点这个方案基本就能站住了。你不需要在一开始就把所有参数调到最优先跑通功能再让设备真正睡下去然后用电流表逐项排查这比任何纸上谈兵的优化都来得实际。