STM32一般具有三种电源管理模式
sleep mode
CPU 停止运行,但所有外设(包括定时器、USART、SPI、I2C、RTC 等)仍然保持工作状态
可以由任意可用的中断源(例如外部中断、RTC、USART 接收等)唤醒
stop mode
CPU 和大部分外设停止运行,但 SRAM 和寄存器保持内容。
PLL 和 HSI/HSE 关闭,但 LSE(低速外部晶振)或 LSI(低速内部 RC 振荡器)可用于 RTC
唤醒后,时钟需要重新配置
stanby mode
所有时钟(包括 HSI、HSE、PLL、LSE)都关闭
SRAM 和寄存器内容丢失(仅 RTC 和备份寄存器保持)
功耗最低(几乎是断电状态),仅供电部分电路保持工作
唤醒后相当于 硬件复位(复位 MCU)
对于STOP mode,在实践中发现,在使用Cube生成HAL库代码的情况下,systick会唤醒STOP mode——这与数据手册上systick依赖于HCLK相冲突,因为在STOP mode下会关闭HCLK。
这可能是HAL库的一个BUG,或许是stm32有些特性不明确,但在使用休眠模式下,尽量关闭systick
这里使用到的是SLEEP mode,因为CPU可以即使准备工作而且系统不需要重启,同时可以通过串口中断唤醒
而STOP mode下只能通过外部中断或RTC唤醒,一般非低功耗系列的32单片机不能通过串口唤醒,而L系列的可以。
但如果搭配上看门狗,SLEEP mode下没有外设喂狗,势必会发生狗咬人重启。
这里我创建了一个auto_sleep函数,用于没有操作延迟自动进入休眠
void auto_sleep(){
if(g_sleep){
my_printf("SLEEP Zzzzzzz...\r\n");
HAL_Delay(1);
// Pause sys Tick
HAL_SuspendTick(); // 发现了sys tick会唤醒stop mode
__HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG(); // clear flag
// 使能Sleep-On-Exit模式
HAL_PWR_EnableSleepOnExit();
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
// 如果进入stop mode后,不能通过串口来唤醒,所以不再使用stop mode休眠
// if(g_stop){
// HAL_ResumeTick();
// my_printf("DEEP SLEEP Zzzz...\r\n");
// HAL_Delay(1);
// HAL_SuspendTick();
// HAL_PWR_EnableSleepOnExit();
// // 进入 Stop Mode(主调节器模式)
// HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
// // 唤醒后恢复时钟
// SystemClock_Config();
// }
HAL_ResumeTick();
my_printf("WAKEUP Vvvvvvv...\r\n");
}
}
这个函数中有几个注意的点
首先关闭systick,清楚外部中断唤醒标识位
使能sleep-on-exit模式,该模式能够在中断唤醒之后立即再次进入休眠,而不用调用WFI(),比较适合通过RTC中断喂狗的情况
进入SLEEP mode
退出SLEEP mode 后恢复systick
对于喂狗的情况,通过RTC内部中断进行
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc){
HAL_IWDG_Refresh(&hiwdg); //feed dog
// sleep delay time: rtc interrupt interval times $(g_sleepDelayCounter)
// 750 * 10 = 7500ms
if(!g_sleep && g_sleep_enable){
g_sleepDelayCounter++;
}else if(g_sleep && !g_stop){
g_sleepDelayCounter++;
}
else{
g_sleepDelayCounter = 0;
}
if(g_sleepDelayCounter >= SLEEPDELAYTIME && g_sleepDelayCounter < STOPDELAYTIME){
g_sleep = 1;
}
// else if(g_sleepDelayCounter >= STOPDELAYTIME){
// g_stop = 1;
// HAL_PWR_DisableSleepOnExit();
// }
// sleep status led
if(g_sleep){
HAL_GPIO_TogglePin(USR_LED_GPIO_Port, USR_LED_Pin);
}else{
HAL_GPIO_WritePin(USR_LED_GPIO_Port, USR_LED_Pin, SET);
}
}
通过设置SLEEPDELAYTIME 来限制休眠延时时间