第三章 时钟系统与功耗:选对时钟,省电一半

时钟系统,说白了就是MCU的心脏。心跳多快,功耗就有多高。但很多人一上来就开PLL跑到最高频,结果电池撑不了两天。我见过不少项目,明明可以跑32kHz,偏要跑72MHz,功耗差了三个数量级。

这一章,咱们把STM32的时钟源挨个拆开看。哪个最省电?哪个最精准?怎么在运行时动态切换?把这些搞明白,你的低功耗设计就成功了一半。

3.1 四大时钟源,谁最省电?

STM32内部有四个主要时钟源:HSE、HSI、LSE、LSI,再加上PLL这个倍频器。先看一张对比表,心里有个底。

时钟源 频率范围 典型功耗 启动时间 精度
HSE(外部高速晶振) 4-26 MHz ~500 µA - 1 mA ~2 ms 极高(0.005%)
HSI(内部高速RC) 8/16 MHz ~100 - 200 µA ~1 µs 中等(1%)
LSE(外部低速晶振) 32.768 kHz ~0.5 - 1 µA ~1 s 极高(0.001%)
LSI(内部低速RC) ~32 kHz ~0.1 - 0.3 µA ~50 µs 低(5-10%)
PLL(锁相环倍频) 最高可达216 MHz ~200 - 500 µA ~100 µs 取决于输入源

核心结论:功耗差距巨大。LSE比HSE省电近1000倍。能用低速就别用高速,能用内部就别用外部。

3.2 时钟树配置对功耗的影响

很多人以为选对了时钟源就完事了。其实时钟树上的每个分频器、每个使能位,都在偷偷吃电。

我踩过的一个坑:有一次做NB-IoT终端,待机电流死活降不到10µA以下。查了两天,最后发现是APB2总线上挂了一个没用的SPI外设,时钟没关。关了之后,待机电流直接降到3µA。

时钟树功耗优化要点

  1. 关闭未使用的外设时钟——这是最基础也最容易被忽略的。每个外设的时钟使能位都在RCC寄存器里,不用的就关掉。
  2. 降低总线时钟频率——APB1、APB2、AHB的分频器不是摆设。如果外设不需要高速,就把总线时钟降下来。
  3. 使用合适的时钟源——休眠时切换到LSI或LSE,醒来再切回HSE+PLL。
  4. 关闭PLL——PLL本身就有几百µA的功耗,不用的时候一定要关掉。

我的习惯:在初始化代码里,先关掉所有外设时钟,然后按需逐个打开。这样能避免遗漏。

3.3 动态时钟切换技巧

动态时钟切换,说白了就是让MCU在运行时根据负载切换时钟源。高负载时跑高速,低负载时跑低速,休眠时跑最低速。

这个技巧在电池供电设备里特别实用。我做过一个手持采集器,平时采集数据时跑48MHz,处理完数据后切到32kHz,功耗从20mA降到20µA。

切换流程

  1. 配置目标时钟源并等待其稳定
  2. 设置系统时钟源为目标时钟
  3. 等待切换完成标志位
  4. 关闭原时钟源(可选)

下面是一个从HSE切换到HSI的示例代码:

void SystemClock_Switch_HSI(void)
{
    // 1. 使能HSI并等待稳定
    RCC->CR |= RCC_CR_HSION;
    while(!(RCC->CR & RCC_CR_HSIRDY));
    
    // 2. 切换系统时钟到HSI
    RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSI;
    
    // 3. 等待切换完成
    while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI);
    
    // 4. 关闭HSE和PLL(可选)
    RCC->CR &= ~RCC_CR_HSEON;
    RCC->CR &= ~RCC_CR_PLLON;
}

注意:切换时钟时,如果外设正在使用原时钟,可能会造成通信异常。我建议在切换前先暂停外设操作,切换完成后再恢复。

3.4 时钟系统知识图谱

下面这张图把时钟系统的核心逻辑串起来了。从时钟源到系统时钟,再到各个总线,每一步都影响功耗。

STM32时钟系统与功耗关系图 STM32时钟系统与功耗关系 HSE (4-26 MHz) HSI (8/16 MHz) LSE (32.768 kHz) LSI (~32 kHz) PLL (倍频) SYSCLK AHB (分频) APB1 (分频) APB2 (分频) 外设 (GPIO, DMA...) 外设 (USART, I2C...) 外设 (SPI, TIM...) 功耗: ~500 µA 功耗: ~100 µA 功耗: ~0.5 µA 功耗: ~0.1 µA

3.5 实战建议

说了这么多,总结几条我自己的经验:

  • 待机用LSI——RTC需要计时就用LSE,精度高;如果只是简单定时唤醒,LSI就够了,启动还快。
  • 运行用HSI——如果对精度要求不高,HSI比HSE省电,而且启动快,适合频繁唤醒的场景。
  • 高性能用HSE+PLL——需要算力的时候再开,算完立刻切回去。
  • 动态切换要快——切换时间越短,浪费的功耗越少。HSI和LSI启动快,适合做中间过渡。

一个小技巧:在切换时钟前,先把所有外设时钟关了,切换完再开。这样能避免切换过程中外设误动作,也能省一点电。

时钟系统调优,说白了就是「按需分配」。需要多少算力,就给多少时钟。别让MCU一直跑在最高速,也别让它在需要算力的时候卡在低速上。动态切换做得好,功耗能降一个数量级。