第2章:STM32时钟系统与功耗关系
时钟,是MCU的心脏。心跳多快,功耗就有多高。这个道理很简单,但实际项目中,很多人栽在时钟配置上。
我记得刚做低功耗产品那会儿,一块电池供电的传感器板,怎么调都多出2mA电流。查了三天,最后发现是HSI没关,外设时钟还在跑。嗯,从那以后,我每次看原理图第一件事就是先理清时钟树。
2.1 时钟树架构详解
STM32的时钟树,说白了就是一套时钟源 + 分频器 + 开关的网络。你想想看,CPU、外设、总线、RTC,它们各自需要不同频率的时钟。如果全都用同一个高频时钟,那功耗肯定爆炸。
下面这张图,是我画的一个简化版时钟树结构。它帮你快速理解时钟是怎么分发的。
从图上你能看到,时钟源有四个:HSE(外部高速)、HSI(内部高速)、LSE(外部低速)、LSI(内部低速)。它们经过PLL倍频后,生成SYSCLK,再分发给AHB、APB1、APB2总线。
这里有个关键点:APB1最高只能跑到36MHz(F1系列),而APB2可以到72MHz。如果你把APB1的外设时钟配高了,不仅外设可能跑飞,功耗也会白白增加。
2.2 HSE/LSE/HSI/LSI的选择策略
选哪个时钟源,直接决定了你的功耗基线。我列个表,你一看就明白。
| 时钟源 | 频率 | 典型功耗 | 适用场景 |
|---|---|---|---|
| HSE | 4-16MHz(常用8MHz) | 高(需外部晶振+起振电流) | 需要高精度主频,如通信、数据处理 |
| HSI | 8/16MHz(取决于型号) | 中(内部RC,无需外部元件) | 快速启动、低成本设计 |
| LSE | 32.768kHz | 极低(μA级) | RTC日历、低功耗休眠唤醒 |
| LSI | 约32kHz(精度差) | 极低(μA级) | 独立看门狗、低精度RTC |
我的经验:如果产品需要长时间休眠,我建议用LSE做RTC时钟源。LSI虽然省电,但温度漂移大,一天能差几分钟。曾经有个客户反馈设备时间越走越偏,最后发现是LSI惹的祸。
选型时,你可以这样判断:
- 追求低功耗 + 不需要高精度主频 → 直接用HSI,省掉外部晶振,省2个引脚,省PCB面积。
- 需要高精度通信(如CAN、USB) → 必须用HSE,内部RC精度不够,通信会丢包。
- 休眠时需要保持时间 → 用LSE,功耗只有几个μA。
- 只是喂狗,不需要精确时间 → LSI就够了,省一个晶振。
2.3 系统时钟与总线时钟的配置对功耗的影响
时钟频率和功耗的关系,不是线性的,而是近似正比。频率翻倍,动态功耗几乎翻倍。但静态功耗(漏电流)基本不变。
所以,调优的核心思路是:够用就好,别多给。
2.3.1 系统时钟(SYSCLK)配置
SYSCLK是CPU的运行频率。跑得越快,处理能力越强,但功耗也越高。我见过有人把STM32F103超到128MHz,结果芯片发烫,电池半天就没电。
实际项目中,我一般这样配:
- 待机/低负载:SYSCLK降到8-16MHz,用HSI直接输出,不经过PLL。
- 中等负载:SYSCLK 48-64MHz,用HSE+PLL,平衡性能和功耗。
- 高负载:SYSCLK 72MHz(F1上限),只在需要大量计算时短暂使用。
关键公式:动态功耗 ≈ C × V² × f。其中f是时钟频率,V是工作电压。频率降一半,功耗降一半。电压降一点,功耗平方级下降。
2.3.2 总线时钟(AHB/APB)配置
总线时钟控制着外设的访问速度。很多人只关注SYSCLK,忽略了总线时钟。其实,总线时钟每降低1MHz,都能省下几十μA。
我举个例子:
- APB1上挂的是低速外设(UART、I2C、SPI、TIM),这些外设通常不需要高频时钟。APB1最高36MHz,但如果你只跑115200波特率的UART,APB1给8MHz就绰绰有余。
- APB2上挂的是高速外设(ADC、SPI1、TIM1),如果不用这些外设,可以把APB2时钟降到最低。
注意:降低总线时钟时,要确保外设的时钟源满足其最低工作频率。比如,SPI通信速率取决于APB时钟,配低了会导致通信失败。
2.3.3 外设时钟门控
这是最容易被忽略的一点。STM32每个外设都有独立的时钟使能位。即使SYSCLK和总线时钟都配好了,如果某个外设的时钟没关,它依然在耗电。
我曾经在一个项目中,发现UART1明明没用,但功耗多了0.5mA。查了半天,原来是初始化代码里开了RCC_APB2Periph_USART1,但后面忘了关。
正确的做法是:
// 开启外设时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 使用外设...
// 使用完毕后,关闭外设时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, DISABLE);
嗯,这个习惯一定要养成。每次配完外设,顺手把不用的时钟关掉。
2.4 实战配置建议
下面是我个人习惯的一套低功耗时钟配置流程,你可以参考:
- 确定应用场景:是持续运行还是间歇工作?需要高精度吗?
- 选择主时钟源:低功耗选HSI,高精度选HSE。
- 配置PLL:如果不需要高频,直接旁路PLL,省掉PLL的功耗(约几十μA)。
- 分频总线时钟:AHB、APB1、APB2按需分频,能低则低。
- 关闭未用外设时钟:在初始化末尾,遍历所有外设,关掉不用的。
- 休眠前降频:进入Stop模式前,把SYSCLK降到最低,再切到HSI。
一个小技巧:在调试阶段,可以用RCC_GetClocksFreq()函数打印出当前所有时钟频率,确认配置是否符合预期。我每次调完时钟都会跑一遍这个函数,心里踏实。
好了,时钟系统这部分就讲到这里。记住一句话:时钟是功耗的源头,管好时钟,就管好了一半的功耗。