第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醒来可能需要几十毫秒,如果你的应用对响应时间有要求,就别用太深的睡眠模式。
  • 实测功耗——别光看数据手册。我习惯用万用表串在电源上,实际测一下每种模式的电流。数据手册给的往往是理想值,实际会有偏差。

我的小技巧:在代码里加一个调试接口,可以实时查看当前工作模式。这样调试时能清楚知道芯片到底在哪个状态,省得猜来猜去。

好了,五种模式就聊到这儿。下一章咱们会深入讲讲模式切换时的时钟和电源管理,那才是真正考验功力的地方。记住一句话:低功耗设计不是把芯片调到最低功耗模式就完事了,而是在正确的时间用正确的模式。