STM32CubeMX教程25 PWR 电源管理 - 睡眠、停止和待机模式
1、准备材料
STM32CubeMX软件(Version 6.10.0)
keil µVision5 IDE(MDK-Arm)
2、实验目标
使用STM32CubeMX软件配置STM32F407开发板的PWR电源管理,并了解STM32的睡眠、停止和待机模式
3、实验流程
3.0、前提知识
3.0.1、睡眠模式
睡眠模式可以立即进入,也可以在退出优先级最低的中断时再进入,在进入睡眠模式前可以通过HAL_PWR_EnableSleepOnExit() / HAL_PWR_DisableSleepOnExit()设置
通过调用HAL库的HAL_PWR_EnterSLEEPMode()函数可以进入睡眠模式,以WFI进入的睡眠模式任何中断均可将MCU唤醒,以WFE进入的睡眠模式任何唤醒事件均可将MCU唤醒
如下图所示为立即和退出休眠两种情况的进入/退出说明 (注释1)


睡眠模式下系统状态如下
- CPU时钟关闭,CPU停止运行,程序暂停
- 外设时钟正常,所有外设正常工作,I/O引脚状态与进入睡眠模式时一致
- 调压器正常工作
任何中断或唤醒事件导致退出睡眠模式时,CPU重新运行,程序从暂停处继续运行
3.0.2、停止模式
HAL库中通过HAL_PWR_EnterSTOPMode()可以进入停止模式
由于进入停止模式所有外部中断线均需退出,可以使用EXTI->PR = 0;强制复位所有外部中断线,以保证实验可以正常进入停止模式
如下图所示为停止模式的进入/退出说明 (注释1)

停止模式下系统状态如下
- CPU时钟关闭,CPU停止运行,程序暂停
- 1.2V域外设时钟停止,外设停止工作
- 调压器开启/处于低功耗模式,寄存器/SRAM内容保留
- FLASH处于正常/掉电模式(通过HAL_PWREx_EnableFlashPowerDown()/HAL_PWREx_DisableFlashPowerDown()函数设置)
- HSI和HSE振荡器关闭
所有配置为外部中断线EXTI上的中断/事件触发都将导致退出停止模式,退出停止模式时,系统重新启动HSI时钟,然后CPU重新运行,程序从暂停处继续运行
3.0.3、待机模式
HAL库中通过HAL_PWR_EnterSTANDBYMode()可以进入停止模式
通过HAL_PWR_EnableWakeUpPin()可以使能唤醒引脚PA0,当处于待机模式时,PA0引脚出现上升沿则从待机模式退出
如下图所示为待机模式的进入/退出说明 (注释1)

待机模式下系统状态如下
- 所有外设停止工作,除能退出待机模式的一些引脚,其他引脚均为高阻态
- 1.2V调压器关闭,寄存器/SRAM内容全部丢失
- PLL、HSI和HSE振荡器均关闭
- VBAT供电的RTC寄存器,备份域SRAM内容保留,RTC正常工作
WKUP引脚上升沿、RTC闹钟(闹钟A和闹钟B)、RTC唤醒事件、RTC入侵事件、RTC时间戳事件、NRST引脚外部复位和IWDG复位 其中任何一个事件发生时退出待机模式,CPU复位,程序从头开始运行(退出待机模式相当于复位)
另外从待机模式中唤醒后需要注意以下两件事情
- 当MCU从待机模式中唤醒后需要使用__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU)软件手动清除唤醒标志,否则下次再次进入待机模式将直接唤醒
- 另外可以顺便使用HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1)将PA0上升沿唤醒关闭,只在即将进入待机模式前开启
3.1、CubeMX相关配置
3.1.0、工程基本配置
打开STM32CubeMX软件,单击ACCESS TO MCU SELECTOR选择开发板MCU(选择你使用开发板的主控MCU型号),选中MCU型号后单击页面右上角Start Project开始工程,具体如下图所示


开始工程之后在配置主页面System Core/RCC中配置HSE/LSE晶振,在System Core/SYS中配置Debug模式,具体如下图所示


详细工程建立内容读者可以阅读“STM32CubeMX教程1 工程建立”
3.1.1、时钟树配置
系统时钟使用8MHz外部高速时钟HSE,HCLK、PCLK1和PCLK2均设置为STM32F407能达到的最高时钟频率,具体如下图所示

3.1.2、外设参数配置
本实验需要初始化开发板上KEY2、KEY1和KEY0用户按键做普通输入,具体配置步骤请阅读“STM32CubeMX教程3 GPIO输入 - 按键响应”
本实验需要初始化开发板上WK_UP按键为外部中断,具体配置请阅读“STM32CubeMX教程4 EXTI 按键外部中断”
本实验需要初始化TIM6外设实现500ms定时,具体配置步骤请阅读“STM32CubeMX教程5 TIM 定时器概述及基本定时器”
本实验需要初始化USART1作为输出信息渠道,具体配置步骤请阅读“STM32CubeMX教程9 USART/UART 异步通信”
3.1.3、外设中断配置
本实验无需配置
3.2、生成代码
3.2.0、配置Project Manager页面
单击进入Project Manager页面,在左边Project分栏中修改工程名称、工程目录和工具链,然后在Code Generator中勾选“Gnerate peripheral initialization as a pair of 'c/h' files per peripheral”,最后单击页面右上角GENERATE CODE生成工程,具体如下图所示


详细Project Manager配置内容读者可以阅读“STM32CubeMX教程1 工程建立”实验3.4.3小节
3.2.1、外设初始化调用流程
无
3.2.2、外设中断调用流程
本实验没有启动电源管理相关中断
3.2.3、添加其他必要代码
在主函数中添加按键控制逻辑,按下KEY2按键进入睡眠模式,按下KEY1按键进入停止模式,按下KEY0按键进入待机模式
源代码如下
/*main.c标志位定义*/
uint8_t mode_flag = 0;
/*main.h标志位声明*/
extern uint8_t mode_flag;
extern void SystemClock_Config(void);
/*main.c主函数内初始化程序*/
printf("\r\nReset\r\n");
HAL_TIM_Base_Start_IT(&htim6);
/*main.c主循环内控制程序*/
while(1)
{
/*从待机模式唤醒后手动清除唤醒标志,否则下次进入待机模式将直接唤醒*/
if(__HAL_PWR_GET_FLAG(PWR_FLAG_WU)==SET)
{
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
}
/*从待机模式唤醒后失能唤醒引脚*/
if(__HAL_PWR_GET_FLAG(PWR_FLAG_SB)==SET)
{
HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1);
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
}
/*按键KEY2被按下*/
if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(50);
if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin) == GPIO_PIN_RESET)
{
/*进入睡眠模式*/
mode_flag = 3;
printf("\r\nKEY2 Pressed,Into Sleep Mode\r\n");
HAL_SuspendTick();
HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON,PWR_SLEEPENTRY_WFI);
while(!HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin));
}
}
/*按键KEY1被按下*/
if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(50);
if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin) == GPIO_PIN_RESET)
{
/*进入停止模式*/
mode_flag = 2;
printf("\r\nKEY1 Pressed,Into Stop Mode\r\n");
HAL_PWREx_EnableFlashPowerDown();
EXTI->PR = 0;
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON,PWR_SLEEPENTRY_WFI);
while(!HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin));
}
}
/*按键KEY0被按下*/
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(50);
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin) == GPIO_PIN_RESET)
{
/*进入待机模式*/
mode_flag = 1;
printf("\r\nKEY0 Pressed,Into StandBy Mode\r\n");
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
HAL_PWR_EnterSTANDBYMode();
while(!HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin));
}
}
HAL_Delay(100);
HAL_GPIO_TogglePin(GREEN_LED_GPIO_Port,GREEN_LED_Pin);
}
在gpio.c中重新实现WK_UP按键外部中断回调函数HAL_GPIO_EXTI_Callback()
源代码如下
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == WK_UP_Pin)
{
/*睡眠模式唤醒*/
if(mode_flag == 3)
{
HAL_ResumeTick();
}
/*停止模式唤醒*/
else if(mode_flag == 2)
{
HAL_Init();
SystemClock_Config();
}
printf("\r\nWK_UP Pressed\r\n");
}
}
4、常用函数
/*进入睡眠模式*/
void HAL_PWR_EnterSLEEPMode(uint32_t Regulator, uint8_t SLEEPEntry)
/*进入停止模式*/
void HAL_PWR_EnterSTOPMode(uint32_t Regulator, uint8_t STOPEntry)
/*进入待机模式*/
void HAL_PWR_EnterSTANDBYMode(void)
/*挂起滴答定时器*/
void HAL_SuspendTick(void)
/*恢复滴答定时器*/
void HAL_ResumeTick(void)
/*使能停止模式时的FLASH掉电模式*/
void HAL_PWREx_EnableFlashPowerDown(void)
/*停止模式时的FLASH处于正常模式*/
void HAL_PWREx_DisableFlashPowerDown(void)
/*使能待机唤醒引脚*/
void HAL_PWR_EnableWakeUpPin(uint32_t WakeUpPinx)
/*立即进入睡眠模式*/
void HAL_PWR_EnableSleepOnExit(void)
/*退出后进入睡眠模式*/
void HAL_PWR_DisableSleepOnExit(void)
5、烧录验证
烧录程序,开发板上电后,由外设TIM控制的红色LED每隔500ms状态翻转一次,由程序控制的绿色LED大约每隔100ms状态翻转一次
当按下KEY2按键时单片机会进入睡眠模式,此时程序暂停运行,所有外设正常运行,因此绿色LED保持进入睡眠模式的状态不再改变,但是红色LED仍然正常每隔500ms状态翻转一次,在睡眠模式时如果按下WK_UP按键,单片机会被唤醒,程序从停止处正常运行
当按下KEY1按键时单片机会进入停止模式,此时程序暂停运行,所有外设也停止工作,调压器处于开启/低功耗状态,因此绿色LED和红色LED的状态均保持进入停止模式时的状态不再改变,在停止模式时如果按下WK_UP按键,单片机会被唤醒,程序从停止处正常运行 (注释2)
当按下KEY0按键时单片机会进入待机模式,此时程序暂停运行,所有外设也停止工作,调压器也关闭,因此绿色LED和红色LED均会熄灭,在待机模式下如果按下WK_UP按键,单片机会退出待机模式,但单片机会复位,程序会重新开始运行
如下图所示为上述整个过程串口输出的信息和开发板绿色/红色LED状态

6、注释详解
注释1:图片来源于STM32F4xx 中文参考手册 RM009
注释2:根据手册我们知道进入停止模式时内核暂停,程序此时不应该继续执行,外设也都停止,正常情况下我们设置的红色LED和绿色LED灯都将保持进入停止模式时的状态不改变;但是笔者遇到一个奇怪的现象,不知道是个例还是程序存在BUG(大概率程序BUG),当使用DAP/STLINK烧录到开发板程序后,按下KEY1按键进入停止模式后会被自动唤醒一次,本应该不闪烁的LED灯,则因为意外唤醒而再次闪烁,只不过由于从停止模式唤醒后使用的是内部高速时钟HSI,因此闪烁会较慢,而当烧录到开发板程序后将开发板断电一次,上电后重新按下KEY1按键进入停止模式则一切正常
参考资料
STM32CubeMX教程25 PWR 电源管理 - 睡眠、停止和待机模式的更多相关文章
- ARM linux电源管理——Cortex A系列CPU(32位)睡眠和唤醒的底层汇编实现
ARM linux电源管理——Cortex A系列CPU(32位)睡眠和唤醒的底层汇编实现 承接 http://www.wowotech.net/pm_subsystem/suspend_and_re ...
- 第42章 电源管理—实现低功耗—零死角玩转STM32-F429系列
第42章 电源管理—实现低功耗 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...
- STM32电源管理
(1)3时钟模式 ①睡眠模式②停止模式③待机模式 1.睡眠模式:Cortex-M3内核(理解为CPU)停止工作,CPU供电1.8V有着,周边任何执行.执行 2.停机模式:全部时钟都停止,CPU电 ...
- Linux电源管理(7)_Wakeup events framework【转】
转自:http://www.wowotech.net/pm_subsystem/wakeup_events_framework.html 1. 前言 本文继续“Linux电源管理(6)_Generi ...
- FPGA设计中的电源管理(转载)
过去,FPGA设计者主要关心时序和面积使用率问题.但随着FPGA不断取代ASSP和ASIC器件,设计者们现正期望能够开发低功耗设计,在设计流程早期就能对功耗进行正确估算,以及管理和对与FPGA相关的各 ...
- Linux电源管理(7)_Wakeup events framework
1. 前言 本文继续"Linux电源管理(6)_Generic PM之Suspend功能"中有关suspend同步以及PM wakeup的话题.这个话题,是近几年Linux ker ...
- USB电源管理
在USB总线接口协议中,由于涉及电源供电,因此协议中规定了完整的电源管理方案.通过USB电源管理可以实现USB设备的激活.挂起.空闲和睡眠等,从而降低无效的功率消耗,实现系统电源的有效使用和合理分配. ...
- Android电源管理-休眠简要分析
一.开篇 1.Linux 描述的电源状态 - On(on) S0 - Working - Standb ...
- linux驱动程序之电源管理之linux的电源管理架构(3)
设备电源管理 Copyright (c) 2010 Rafael J. Wysocki<rjw@sisk.pl>, Novell Inc. Copyright (c) 2010 Alan ...
- Linux电源管理(9)_wakelocks【转】
1. 前言 wakelocks是一个有故事的功能. wakelocks最初出现在Android为linux kernel打的一个补丁集上,该补丁集实现了一个名称为"wakelocks&quo ...
随机推荐
- 你眼中的程序员 VS 程序员眼中的自己,是时候打破代沟了
摘要:修电脑?格子衫?脱发?程序员被误解了怎么办?如何一句话向父母说明白你的工作? 有人说,你们程序员工作赚钱真简单,电脑上按按键盘就行了,一点也不辛苦. 有人说,程序员不懂生活,就知道天天对着电脑. ...
- 云图说|ASM灰度发布,让服务发布变得更敏捷、更安全
阅识风云是华为云信息大咖,擅长将复杂信息多元化呈现,其出品的一张图(云图说).深入浅出的博文(云小课)或短视频(云视厅)总有一款能让您快速上手华为云.更多精彩内容请单击此处. 摘要:通常产品优化迭代的 ...
- linux 实时刷新显示当前时间
同步阿里云时间 ntpdate ntp1.aliyun.com 使用watch命令:周期性的执行一个命令,并全屏显示. watch -n 1 date 即可:每1秒刷新date命令. # 格式 wat ...
- 【Django drf】序列化器总结
目录 序列化器字段 外键字段自定义序列化 在模型类中写方法 在序列化类中写方法 反序列化 外键字段反序列化保存 ModelSerializer使用总结 序列化器字段 序列化中的字段可以根据用途分为三种 ...
- C++正则表达式的初步使用
正则表达式(Regular Expressions),又被称为regex.regexp 或 RE,是一种十分简便.灵活的文本处理工具.它可以用来精确地找出某文本中匹配某种指定规则的内容.从C++11开 ...
- 2019CCPC-江西省赛(重现赛)队伍题解
2019CCPC江西省赛(重现赛) 第一次组队(和队内dalao:hzf)参加比赛,这次比赛使用的是我的笔电,但因为我来的比较晚,没有提前磨合:比如我的64键位键盘导致hzf突然上手不习惯. Solv ...
- L2-030 冰岛人 (25 分) (阅读理解)
补题链接:Here 2018年世界杯,冰岛队因1:1平了强大的阿根廷队而一战成名.好事者发现冰岛人的名字后面似乎都有个"松"(son),于是有网友科普如下: 冰岛人沿用的是维京人古 ...
- django动态创建表和动态选择实体
开发有时需要动态创建表,创建完成后需要动态选择model对应的表,该需求如何实现 1.model层 TestBlock为了动态创建表.getBlockModel为了动态选择表 from djang ...
- 2023全国大学生电子设计竞赛H题全解 [原创www.cnblogs.com/helesheng]
2023年又是全国大学生电子设计竞赛年,一如既往的指导学生死磕H题.8月2日看到公布的赛题,我自己还沾沾自喜,觉得今年学生用嵌入式系统和数字信号处理知识就可以完成这题,赛前都辅导过,应该成绩不差.哪想 ...
- Deployment 和 StatefulSets 概述
这篇概述是看文章提到的一段话 xxx is not targeted to be horizontally scalable 引发的,遂整理记录在这里. 起因是有两个应用,一个是无状态的,可以 hor ...