4. 功耗分析基础

时钟,是嵌入式系统的心脏。但很多人没意识到,这颗“心脏”跳动的代价有多大。我见过不少项目,前期选型时随便挑了个时钟方案,结果后期功耗压不下去,只能推倒重来。今天咱们就把时钟系统的功耗账,一笔一笔算清楚。

4.1 四大时钟源:HSI、HSE、LSI、LSE

MCU内部通常有四个时钟源,它们各有各的脾气。我习惯把它们分成两组:高速组和低速组。

时钟源 全称 典型频率 启动时间 功耗等级
HSI 高速内部振荡器 8/16 MHz 几μs 中等
HSE 高速外部晶振 4~25 MHz 几ms 高
LSI 低速内部振荡器 32~40 kHz 几十μs 极低
LSE 低速外部晶振 32.768 kHz 1~2 s 低

看到这个表,你可能会想:HSI启动快、功耗也不高,那为什么还要用HSE?

原因很简单——精度。HSI受温度和电压影响很大,误差可能到±2%甚至更高。而HSE的精度可以做到±50ppm以内。我在做一款NB-IoT终端时,就因为用了HSI导致载波频率偏移,通信距离直接砍半。后来换成HSE,问题才解决。

核心原则:精度要求高(如通信、USB、ADC采样)→ 用HSE;精度要求低(如普通GPIO控制)→ 用HSI省功耗。

低速组这边,LSE是RTC的黄金搭档。32.768 kHz这个频率,分频后正好是1秒,做日历时钟再合适不过。LSI虽然功耗更低,但精度差,做RTC一天能差好几秒。

我的习惯:只要产品需要掉电保存时间,我一定用LSE。LSI只用来做看门狗或唤醒定时器,省那几微安不值得冒时间不准的风险。

4.2 时钟分频与门控:最容易被忽略的功耗优化点

很多人觉得,时钟源选好了就完事了。其实不然。时钟树上的分频器和门控,才是真正的功耗优化战场。

分频器本身不耗多少电,但它决定了后续所有外设的工作频率。你想想看,一个SPI模块跑48 MHz和跑12 MHz,动态功耗差4倍。但很多外设根本不需要那么高的频率。

我建议的做法是:

  1. 先确定每个外设的最低工作频率(查数据手册)
  2. 再配置对应的时钟分频器,让频率刚好够用
  3. 不用的外设,直接关掉时钟

时钟门控(Clock Gating)是MCU厂商给的福利。大部分MCU都有RCC(Reset and Clock Control)寄存器,可以单独控制每个外设的时钟开关。

// 以STM32为例,关闭USART1时钟
RCC->APB2ENR &= ~RCC_APB2ENR_USART1EN;

// 需要时再打开
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
__NOP(); __NOP(); // 等待两个时钟周期,让时钟稳定
USART1->CR1 |= USART_CR1_UE; // 使能USART

注意:关闭时钟前,一定要确保外设处于空闲状态。我曾经在USART还在发送数据时关了时钟,结果数据卡在移位寄存器里,下一包数据发出去就乱码了。排查了整整两天。

还有一个容易被忽略的点:总线时钟分频。AHB、APB1、APB2这些总线,频率越高功耗越大。如果外设都挂在APB1上,而APB1不需要那么高的频率,完全可以降低它的分频系数。

4.3 PLL与倍频:性能的代价

PLL(锁相环)是个好东西。它能把低频时钟倍频到高频,让MCU跑得更快。但好东西都有代价。

PLL的功耗由三部分组成:

  • 鉴相器(PFD):比较参考时钟和反馈时钟的相位差
  • 电荷泵(Charge Pump):把相位差转换成电压
  • 压控振荡器(VCO):产生高频时钟

其中VCO是功耗大头。频率越高,VCO的功耗越大,而且不是线性增长,是指数级的。我实测过某款MCU:

工作模式 时钟配置 系统电流 相对功耗
HSI 8 MHz 直接使用 2.1 mA 1x
HSE 8 MHz 直接使用 2.8 mA 1.33x
HSE 8 MHz + PLL 72 MHz 倍频到72 MHz 18.5 mA 8.8x
HSE 8 MHz + PLL 120 MHz 倍频到120 MHz 42.3 mA 20.1x

看到了吗?从8 MHz倍频到72 MHz,频率只增加了9倍,但功耗增加了8.8倍。再往上到120 MHz,功耗直接翻倍还多。

结论很明确:PLL倍频的功耗代价,远高于频率本身的线性增长。能用低频率解决问题,就别开PLL。

那什么时候必须用PLL?

  • 需要高算力(如音频处理、加密运算)
  • 外设需要特定频率(如USB需要48 MHz)
  • 系统有严格的时序要求

其他情况,我建议尽量绕开PLL。比如做传感器采集,1 MHz都够用,何必开到72 MHz让电池哭泣?

4.4 时钟系统功耗优化流程图

下面这张图,是我做低功耗设计时参考的时钟决策流程。每次画板子前,我都会过一遍。

时钟系统低功耗决策流程 确定系统需求 需要高精度时钟? 选择 HSE 选择 HSI 需要更高频率? 使能 PLL 倍频 直接使用时钟源 配置各外设时钟分频 关闭未使用外设的时钟门控 低功耗时钟方案 关键提醒 PLL功耗随频率指数增长 能不用就不用 分频器是免费的功耗优化

4.5 实战中的时钟切换策略

很多低功耗场景,不是固定用一个时钟就完事了。系统在不同状态下,对时钟的需求完全不同。

我举个例子:一个电池供电的温湿度采集器。

  • 休眠状态:只用LSE做RTC,电流几μA
  • 采集状态:用HSI 8 MHz,启动快,采完就睡
  • 通信状态:切换到HSE + PLL到48 MHz,保证无线模块的时序

这种动态切换,能比全程跑48 MHz省下80%以上的功耗。但要注意切换时的瞬态问题。

切换时钟的坑:我曾经在切换时钟源时,没有等新时钟稳定就切换了外设时钟。结果系统跑飞了。正确的做法是:先使能新时钟源,等待它稳定(检查标志位),再切换系统时钟,最后关闭旧时钟源。

// 时钟切换示例:从HSI切换到HSE
RCC->CR |= RCC_CR_HSEON;                    // 使能HSE
while(!(RCC->CR & RCC_CR_HSERDY));          // 等待HSE稳定
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSE; // 切换系统时钟
while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSE);    // 等待切换完成
RCC->CR &= ~RCC_CR_HSION;                   // 关闭HSI

嗯,这里要注意:等待稳定标志位的时间,不同MCU不一样。HSE可能需要几毫秒,LSE甚至要一两秒。如果系统对启动时间有要求,这个等待时间必须算进去。

我的经验:如果系统需要快速响应中断,我会让HSI一直开着作为备用时钟。中断来了先用HSI快速响应,处理完再切回低功耗时钟。虽然HSI一直开着会多耗一点电,但换来的是响应速度,值。

最后说一句:时钟系统的功耗优化,不是选一个低功耗时钟源就完事了。它是一个系统工程,需要从时钟源选择、分频配置、门控管理、动态切换等多个维度去考虑。每优化一步,可能只省下几十微安,但积少成多,整个系统的续航就能翻倍。