第4章:工作模式详解——Active、Idle、Sleep、Standby、Hibernate五种模式切换
各位做低功耗的朋友,咱们今天聊聊全志R系列MCU的看家本领——五种工作模式。这玩意儿说白了就是芯片的「省电秘籍」。我刚开始接触R系列时,也被这五种模式搞得有点晕,后来踩了几个坑才摸清楚门道。
你想想看,一个物联网设备,大部分时间都在待机,真正干活的时间可能不到1%。如果一直让芯片满功率跑,电池撑不了几天。所以,学会合理切换工作模式,是低功耗设计的核心。
4.1 五种模式概览
全志R系列MCU提供了五种工作模式,从耗电最高到最低依次是:Active、Idle、Sleep、Standby、Hibernate。我习惯把它们分成三类:干活模式(Active)、打盹模式(Idle/Sleep)、深度睡眠模式(Standby/Hibernate)。
| 模式 | CPU状态 | 外设状态 | RAM保持 | 唤醒源 | 典型功耗 |
|---|---|---|---|---|---|
| Active | 运行 | 全开 | 是 | N/A | 数十mA |
| Idle | 暂停 | 部分关闭 | 是 | 中断 | 数mA |
| Sleep | 停止 | 可配置 | 是 | RTC/GPIO | 数百μA |
| Standby | 掉电 | 最小系统 | 部分 | RTC/唤醒引脚 | 数十μA |
| Hibernate | 完全掉电 | 几乎全关 | 否 | 复位/唤醒引脚 | 数μA |
核心要点:功耗每降低一个数量级,唤醒时间就会增加一个数量级。这是典型的「用时间换功耗」的trade-off。
4.2 Active模式——全力干活
Active模式就是芯片的正常工作状态。CPU全速运行,所有外设想开就开。这时候功耗最高,但性能也最强。
我记得有个项目,客户要求设备在10ms内完成数据采集和上传。没办法,只能让芯片在Active模式下硬扛。但我会在任务完成后立刻切到低功耗模式,绝不浪费一微秒。
我的习惯:在Active模式下,我会用DMA+中断的方式处理数据,让CPU尽量少参与搬运工作。这样能缩短Active时间,间接降低平均功耗。
4.3 Idle模式——浅度打盹
Idle模式,说白了就是CPU暂停了,但外设还在工作。这时候CPU时钟停了,但SRAM和寄存器内容都保留。任何中断都能把它唤醒。
什么时候用Idle?比如你在等一个外设完成操作,或者等一个定时器超时。这时候CPU闲着也是闲着,不如让它歇会儿。
// 进入Idle模式的典型代码
void enter_idle_mode(void)
{
// 关闭不必要的时钟
CLK->GATING_CTRL &= ~(1 << 3); // 关闭SPI时钟
// 设置CPU进入WFI状态
__WFI(); // Wait For Interrupt
// 醒来后继续执行
// 注意:醒来后要重新配置时钟
}
我曾经踩过的坑:进入Idle前没关掉不用的外设时钟,结果功耗只降了20%。后来才发现,有些外设虽然没在用,但时钟还开着,它们会偷偷耗电。所以进入任何低功耗模式前,先检查一遍时钟门控。
4.4 Sleep模式——深度睡眠
Sleep模式比Idle更进一步。CPU完全停止,大部分外设的时钟也关了。只有RTC(实时时钟)和少数唤醒源还在工作。
这个模式适合那些需要定时唤醒的场景。比如一个温湿度传感器,每10秒采集一次数据。平时就睡大觉,到点了RTC叫它起床干活。
嗯,这里要注意:Sleep模式下,RAM是保持的。这意味着你的程序状态、变量值都不会丢。醒来后可以接着干,不用重新初始化。
// 进入Sleep模式的配置
void enter_sleep_mode(void)
{
// 1. 保存关键寄存器
uint32_t saved_reg = REG->CTRL;
// 2. 配置唤醒源(这里用RTC闹钟)
RTC->ALARM = SYSTEM_TICK_10S;
RTC->CTRL |= (1 << 3); // 使能闹钟中断
// 3. 进入Sleep
PMU->MODE_CTRL = 0x02; // Sleep模式
__WFI();
// 4. 醒来后恢复
REG->CTRL = saved_reg;
}
4.5 Standby模式——待机省电
Standby模式,我管它叫「半睡半醒」。CPU掉电了,但部分RAM区域还能保持。这个模式的关键在于:唤醒后芯片会从Boot ROM重新启动,但你可以选择保留一些数据在「备份RAM」里。
为什么需要Standby?因为有些场景下,你既想省电,又不想完全丢失状态。比如一个智能门锁,平时待机功耗要控制在50μA以内,但用户指纹信息不能丢。这时候Standby就派上用场了。
关键区别:Sleep模式唤醒后继续执行程序,Standby模式唤醒后从复位向量重新启动。所以Standby的唤醒时间更长(毫秒级),但功耗更低。
// Standby模式下的数据保持技巧
// 使用备份RAM保存关键数据
#define BACKUP_RAM_ADDR 0x4000F000
void save_to_backup_ram(uint32_t data)
{
volatile uint32_t *backup = (uint32_t *)BACKUP_RAM_ADDR;
*backup = data;
}
uint32_t load_from_backup_ram(void)
{
volatile uint32_t *backup = (uint32_t *)BACKUP_RAM_ADDR;
return *backup;
}
4.6 Hibernate模式——彻底关机
Hibernate模式是功耗最低的模式,没有之一。CPU完全掉电,RAM全部丢失,几乎所有外设都关了。只有几个唤醒引脚和复位电路还在工作。
这个模式适合什么场景?电池供电的设备,几个月才用一次的那种。比如一个水表,一年才抄一次表。平时就让它彻底睡死过去,功耗能降到个位数微安。
我曾经犯过的错:第一次用Hibernate模式时,没注意唤醒引脚的配置。结果芯片睡下去就醒不来了,只能拔电池复位。后来我学乖了,每次进入Hibernate前,都会反复确认唤醒引脚的电气特性——上拉还是下拉?电平触发还是边沿触发?这些细节搞错了,设备就变砖了。
4.7 模式切换实战建议
说了这么多,到底怎么用?我总结了几条实战经验:
- 能不睡就不睡,要睡就睡透——如果空闲时间超过100ms,直接上Sleep或Standby。频繁在Idle和Active之间切换,反而会增加平均功耗。
- 唤醒源要精简——每多一个唤醒源,就多一份漏电流。我一般只用RTC和1-2个GPIO作为唤醒源。
- 注意唤醒时间——从Hibernate醒来可能需要几十毫秒,如果你的应用对响应时间有要求,就别用太深的睡眠模式。
- 实测功耗——别光看数据手册。我习惯用万用表串在电源上,实际测一下每种模式的电流。数据手册给的往往是理想值,实际会有偏差。
我的小技巧:在代码里加一个调试接口,可以实时查看当前工作模式。这样调试时能清楚知道芯片到底在哪个状态,省得猜来猜去。
好了,五种模式就聊到这儿。下一章咱们会深入讲讲模式切换时的时钟和电源管理,那才是真正考验功力的地方。记住一句话:低功耗设计不是把芯片调到最低功耗模式就完事了,而是在正确的时间用正确的模式。