4、时钟与外设管理:待机状态下的“断舍离”
好,咱们接着聊。前面几章我们把待机模式的进入和唤醒讲得差不多了。这一章,我重点说说时钟和外设的管理。
你想想看,一个系统在待机时,CPU都停了,你还开着PLL、HSE这些大功率时钟源干嘛?那不是白白浪费电嘛。我个人的习惯是,进入待机前,必须做一次彻底的“断舍离”——把不必要的时钟源统统关掉,把没用的外设时钟也禁掉。
4.1 为什么要关时钟源?
说白了,时钟源就是功耗的“大头”。
- PLL(锁相环):这东西倍频上去,功耗可不小。我测过,一个8MHz的HSE经过PLL倍频到72MHz,PLL本身就能吃掉几百微安。待机时你根本用不着高频,关了它。
- HSE(高速外部晶振):外部晶振起振后,振荡电路一直在工作。待机时如果不需要精确的RTC时钟,完全可以关掉。
- HSI(高速内部振荡器):这个相对省电一些,但待机时如果连CPU都不跑了,留着它也没意义。
嗯,这里要注意:关时钟源不是随便关的。你得确保系统在唤醒后能重新初始化时钟树。我见过有人把HSE关了,结果唤醒后忘了重新配置PLL,系统直接跑在HSI上,时序全乱套了。
4.2 禁用未使用的外设时钟
这个其实是个基本功。很多工程师在初始化时把外设时钟都打开了,但待机时忘了关。你想想看,一个USART模块,即使不发送数据,只要时钟还开着,它就在消耗电流。
我建议的做法是:
- 在进入待机前,遍历所有外设,把那些不需要的时钟位清零。
- 保留必要的外设,比如RTC、LPTIM(低功耗定时器)、某些唤醒引脚对应的GPIO。
- 注意DMA和中断控制器,它们的时钟有时会被忽略。
我曾经在一个项目中,待机电流怎么也降不下来。查了半天,发现是DMA的时钟没关。那个DMA虽然没在传输数据,但时钟一开,寄存器还在工作,白白多耗了50微安。你说冤不冤?
4.3 配置RTC作为定时唤醒源
这是待机方案的核心之一。RTC(实时时钟)在待机模式下依然可以运行,靠的是低速外部晶振(LSE)或者低速内部振荡器(LSI)。
我个人习惯用LSE,32.768kHz那种。精度高,功耗也低。LSI虽然省电,但温漂大,做定时唤醒容易不准。
配置RTC唤醒的步骤大致如下:
// 1. 使能RTC时钟(如果还没使能)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
// 2. 允许访问备份域
PWR_BackupAccessCmd(ENABLE);
// 3. 配置RTC时钟源为LSE
RCC_LSEConfig(RCC_LSE_ON);
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET); // 等待LSE稳定
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
// 4. 使能RTC
RCC_RTCCLKCmd(ENABLE);
// 5. 等待RTC寄存器同步
RTC_WaitForSynchro();
// 6. 配置唤醒定时器
RTC_SetWakeUpCounter(0x7FFF); // 设置唤醒计数值
RTC_WakeUpCmd(ENABLE); // 使能唤醒功能
// 7. 使能RTC唤醒中断(在NVIC中也要使能)
RTC_ITConfig(RTC_IT_WUT, ENABLE);
这里有个坑:RTC的唤醒中断在待机模式下是有效的,但前提是你得在进入待机前把中断使能配置好。我刚开始做的时候,忘了使能NVIC中的RTC中断线,结果待机后怎么都唤不醒。查了两天,才发现是中断没配通。
4.4 时钟切换的“平滑过渡”
进入待机前,你可能需要从PLL切换到HSI或者直接关闭系统时钟。这个切换过程要小心。
我建议的流程是:
- 先把系统时钟切换到HSI(或者直接关闭,如果支持的话)。
- 然后关闭PLL、HSE。
- 最后再进入待机模式。
为什么要先切换?因为如果你直接关PLL,系统时钟可能瞬间丢失,导致CPU跑飞。我遇到过这种情况,代码直接卡死在某个中断里,再也出不来了。
4.5 实测数据:关与不关的差别
我拿STM32F103做过一个测试,大家看看数据:
| 状态 | 时钟源 | 外设时钟 | 待机电流 |
|---|---|---|---|
| 未优化 | PLL+HSE+HSI全开 | 所有外设时钟使能 | 约 850 µA |
| 部分优化 | 仅保留HSI | 关闭大部分外设 | 约 120 µA |
| 完全优化 | 仅保留LSE(给RTC) | 仅保留RTC和唤醒GPIO | 约 3.5 µA |
看到了吧?从850微安降到3.5微安,差了200多倍。这就是时钟和外设管理的威力。
4.6 避坑指南
最后,我总结几个容易踩的坑:
- 坑一:关掉HSE后,RTC如果依赖HSE分频,会直接停摆。所以RTC一定要用LSE或LSI。
- 坑二:有些外设的时钟是“链式”的。比如USART的时钟关了,但它的GPIO复用功能可能还开着。要一起关。
- 坑三:唤醒后,时钟树恢复的顺序很重要。先开HSE,再开PLL,最后切换系统时钟。顺序错了,系统可能直接死机。
嗯,这一章的内容就这些。时钟和外设管理,说白了就是“该关的关,该留的留”。你只要把每个模块的功耗都抠出来,待机电流自然就降下去了。下一章,我们聊聊GPIO和唤醒源的具体配置,那个更细,也更考验耐心。