4. 定时器/计数器接口的低功耗设计:时钟源选择、预分频器、自动重装载与单次模式、低功耗定时器(LPTIM)
定时器,可以说是嵌入式系统里最常用的外设之一。做低功耗设计时,它又成了最让人头疼的家伙。
为什么?因为传统定时器太“耗电”了。你想想看,它需要主时钟一直跑着,哪怕CPU睡了,定时器还得醒着。这不合理。
我早年做一款电池供电的传感器节点,就吃过这个亏。当时用普通TIM做周期性唤醒,结果待机电流比预期高了整整一个数量级。查了两天才发现——定时器时钟源没选对,预分频器配置也不合理。从那以后,我对定时器的低功耗设计就格外上心。
4.1 时钟源选择:低功耗的第一道关卡
定时器要工作,首先得有时钟。但时钟源的选择,直接决定了功耗基线。
核心原则:能用低速时钟,就别用高速时钟。能关掉主时钟,就用独立时钟源。
常见的定时器时钟源有这么几种:
| 时钟源 | 典型频率 | 功耗等级 | 适用场景 |
|---|---|---|---|
| 系统主时钟(HCLK) | 数十~数百MHz | 高 | 高精度PWM、高频计数 |
| 内部低速RC(LSI) | 32~40kHz | 低 | 低功耗定时器、看门狗 |
| 外部低速晶振(LSE) | 32.768kHz | 极低 | RTC、精准定时唤醒 |
| 内部高速RC(HSI) | 8~16MHz | 中 | 普通定时任务 |
我个人的习惯是:只要定时周期在毫秒级以上,优先考虑LSI或LSE。别小看这几十kHz的差别,在深度睡眠模式下,一个用HCLK的定时器可能吃掉几百微安,而用LSE的LPTIM只需要几微安。
小技巧:有些MCU允许定时器在休眠时切换到LSI时钟,醒来后再切回HCLK。这种“动态时钟切换”功能,既保证了低功耗,又不牺牲唤醒后的精度。
4.2 预分频器:精度与功耗的平衡术
预分频器,说白了就是给时钟降频。但怎么降、降多少,这里面有讲究。
预分频器的本质是一个计数器,它对输入时钟进行分频,产生一个更慢的时钟给定时器核心使用。分频系数通常是2的幂次(如1、2、4、8…),也有些芯片支持连续分频。
举个例子:
// 假设时钟源为 LSI,32kHz
// 目标:产生 1Hz 的定时中断
// 方案A:不分频,直接计数
// 需要计数 32000 次,计数器位宽需 ≥ 16位
TIM->PSC = 0; // 预分频系数 = 1
TIM->ARR = 31999; // 自动重装载值
// 方案B:分频后计数
// 先分频到 1kHz,再计数 1000 次
TIM->PSC = 31; // 预分频系数 = 32
TIM->ARR = 999; // 自动重装载值
两种方案都能实现1Hz中断,但区别在哪?
- 方案A:计数器跑得快(32kHz),每次计数功耗略高,但ARR值大,适合长周期。
- 方案B:计数器跑得慢(1kHz),每次计数功耗低,但ARR值小,适合短周期。
我在项目中遇到过一个问题:用方案A做10秒定时,ARR需要设到319999,结果计数器溢出了一次,定时不准了。后来改成方案B,先分频到100Hz,再计1000次,问题就解决了。
注意:预分频器本身也是计数器,它也在耗电。分频系数越大,预分频器翻转次数越多,功耗反而可能上升。所以不是分频越大越好,要实测权衡。
4.3 自动重装载与单次模式:两种典型工作方式
定时器的两种工作模式,对应着不同的低功耗策略。
4.3.1 自动重装载模式
这是最常用的模式。计数器从0计数到ARR值,产生事件,然后自动重置为0,继续下一轮。
适合周期性任务,比如:
- 周期性唤醒CPU检查传感器
- 产生固定频率的PWM波
- 系统心跳节拍
低功耗要点:尽量让定时器在休眠期间独立运行,CPU只在事件发生时醒来。别让CPU陪着定时器一起数数。
4.3.2 单次模式(One-Shot)
计数器只跑一轮,产生事件后就停止。适合一次性延时或超时检测。
我特别喜欢单次模式做“延时关机”——按下按键后,定时器启动,5秒后自动切断电源。这期间CPU可以睡大觉。
// 单次模式配置示例(STM32 LPTIM)
LPTIM->CFGR |= LPTIM_CFGR_COUNTMODE; // 设置为单次模式
LPTIM->ARR = 4999; // 5秒(假设时钟1kHz)
LPTIM->CR |= LPTIM_CR_ENABLE; // 启动定时器
// 定时器开始计数,CPU可以进入低功耗模式
// 5秒后产生中断,唤醒CPU
经验之谈:单次模式配合低功耗定时器,是做“事件驱动型”低功耗系统的利器。我曾经用这个组合,把一款门磁传感器的待机功耗降到了1.5µA以下。
4.4 低功耗定时器(LPTIM):专为省电而生
普通定时器在低功耗模式下往往无法工作,或者需要额外配置。于是芯片厂商专门设计了低功耗定时器(LPTIM)。
LPTIM和普通TIM有什么区别?我整理了一张表:
| 特性 | 普通TIM | LPTIM |
|---|---|---|
| 时钟源 | 通常依赖HCLK | 支持LSI/LSE/外部时钟 |
| 低功耗模式 | 多数模式下停止 | 可在Stop/Standby下运行 |
| 功耗 | 数百µA~数mA | 几µA~几十µA |
| 位宽 | 16位或32位 | 通常16位 |
| 功能 | 丰富(PWM/捕获/比较) | 基础(定时/计数/唤醒) |
LPTIM的设计哲学很明确:放弃花哨功能,换取极致低功耗。
它通常具备以下特性:
- 独立时钟域:即使系统主时钟停了,LPTIM依然可以运行
- 异步唤醒:定时事件可以直接将MCU从深度睡眠中唤醒
- 输入脉冲计数:可以在休眠状态下统计外部脉冲
- 超低功耗设计:内部电路经过专门优化,静态电流极低
我曾经用LPTIM做过一个“超长待机”项目:设备每30秒唤醒一次,采集数据后继续休眠。用普通TIM,待机电流约12µA;换成LPTIM后,降到了2.3µA。电池寿命从3个月延长到了18个月。
避坑指南:LPTIM虽然省电,但精度有限。LSI的温漂可能达到±10%,如果你需要高精度定时,还是得用LSE或者定期校准。我曾经因为没考虑温漂,导致设备在高温环境下唤醒周期偏差了15%,差点误事。
4.5 知识结构总览
下面这张图,把本章的核心知识点串起来了:
4.6 实战建议
说了这么多,最后给几条实在的建议:
- 先看芯片手册:确认你的MCU有没有LPTIM,支持哪些时钟源。别等到画板子了才发现没有。
- 实测功耗:理论计算和实际测量往往有差距。我习惯在原型阶段就用电流探头测一下定时器单独工作时的功耗。
- 预留校准接口:如果用了LSI,最好留一个校准通道。温度变化时,可以通过RTC或者外部晶振来修正定时参数。
- 别过度设计:如果系统只需要秒级定时,别用32位定时器。16位LPTIM加合适的分频,完全够用。
嗯,定时器这块就聊到这儿。记住一句话:低功耗设计不是把功能做少,而是把每一分电都用在刀刃上。