第三章 时钟系统与功耗:选对时钟,省电一半
时钟系统,说白了就是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。
时钟树功耗优化要点
- 关闭未使用的外设时钟——这是最基础也最容易被忽略的。每个外设的时钟使能位都在RCC寄存器里,不用的就关掉。
- 降低总线时钟频率——APB1、APB2、AHB的分频器不是摆设。如果外设不需要高速,就把总线时钟降下来。
- 使用合适的时钟源——休眠时切换到LSI或LSE,醒来再切回HSE+PLL。
- 关闭PLL——PLL本身就有几百µA的功耗,不用的时候一定要关掉。
我的习惯:在初始化代码里,先关掉所有外设时钟,然后按需逐个打开。这样能避免遗漏。
3.3 动态时钟切换技巧
动态时钟切换,说白了就是让MCU在运行时根据负载切换时钟源。高负载时跑高速,低负载时跑低速,休眠时跑最低速。
这个技巧在电池供电设备里特别实用。我做过一个手持采集器,平时采集数据时跑48MHz,处理完数据后切到32kHz,功耗从20mA降到20µA。
切换流程
- 配置目标时钟源并等待其稳定
- 设置系统时钟源为目标时钟
- 等待切换完成标志位
- 关闭原时钟源(可选)
下面是一个从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 时钟系统知识图谱
下面这张图把时钟系统的核心逻辑串起来了。从时钟源到系统时钟,再到各个总线,每一步都影响功耗。
3.5 实战建议
说了这么多,总结几条我自己的经验:
- 待机用LSI——RTC需要计时就用LSE,精度高;如果只是简单定时唤醒,LSI就够了,启动还快。
- 运行用HSI——如果对精度要求不高,HSI比HSE省电,而且启动快,适合频繁唤醒的场景。
- 高性能用HSE+PLL——需要算力的时候再开,算完立刻切回去。
- 动态切换要快——切换时间越短,浪费的功耗越少。HSI和LSI启动快,适合做中间过渡。
一个小技巧:在切换时钟前,先把所有外设时钟关了,切换完再开。这样能避免切换过程中外设误动作,也能省一点电。
时钟系统调优,说白了就是「按需分配」。需要多少算力,就给多少时钟。别让MCU一直跑在最高速,也别让它在需要算力的时候卡在低速上。动态切换做得好,功耗能降一个数量级。