STM32CubeMX教程25 PWR 电源管理 - 睡眠、停止和待机模式

发布时间:2024年01月15日

目录

1、准备材料

2、实验目标

3、实验流程

3.0、前提知识

3.0.1、睡眠模式

3.0.2、停止模式

3.0.3、待机模式

3.1、CubeMX相关配置

3.1.0、工程基本配置

3.1.1、时钟树配置

3.1.2、外设参数配置

3.1.3、外设中断配置

3.2、生成代码

3.2.0、配置Project Manager页面

3.2.1、外设初始化调用流程

3.2.2、外设中断调用流程

3.2.3、添加其他必要代码

4、常用函数

5、烧录验证

6、注释详解

参考资料


1、准备材料

开发板(正点原子stm32f407探索者开发板V2.4

STM32CubeMX软件(Version 6.10.0

野火DAP仿真器

keil μVision5 IDE(MDK-Arm

CH340G Windows系统驱动程序(CH341SER.EXE

XCOM V2.6串口助手

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)

睡眠模式下系统状态如下

  1. CPU时钟关闭,CPU停止运行,程序暂停
  2. 外设时钟正常,所有外设正常工作,I/O引脚状态与进入睡眠模式时一致
  3. 调压器正常工作

任何中断或唤醒事件导致退出睡眠模式时,CPU重新运行,程序从暂停处继续运行

3.0.2、停止模式

HAL库中通过HAL_PWR_EnterSTOPMode()可以进入停止模式

由于进入停止模式所有外部中断线均需退出,可以使用EXTI->PR = 0;强制复位所有外部中断线,以保证实验可以正常进入停止模式

如下图所示为停止模式的进入/退出说明(注释1)

停止模式下系统状态如下

  1. CPU时钟关闭,CPU停止运行,程序暂停
  2. 1.2V域外设时钟停止,外设停止工作
  3. 调压器开启/处于低功耗模式,寄存器/SRAM内容保留
  4. FLASH处于正常/掉电模式(通过HAL_PWREx_EnableFlashPowerDown()/HAL_PWREx_DisableFlashPowerDown()函数设置)
  5. HSI和HSE振荡器关闭

所有配置为外部中断线EXTI上的中断/事件触发都将导致退出停止模式,退出停止模式时,系统重新启动HSI时钟,然后CPU重新运行,程序从暂停处继续运行

3.0.3、待机模式

HAL库中通过HAL_PWR_EnterSTANDBYMode()可以进入停止模式

通过HAL_PWR_EnableWakeUpPin()可以使能唤醒引脚PA0,当处于待机模式时,PA0引脚出现上升沿则从待机模式退出

如下图所示为待机模式的进入/退出说明(注释1)

待机模式下系统状态如下

  1. 所有外设停止工作,除能退出待机模式的一些引脚,其他引脚均为高阻态
  2. 1.2V调压器关闭,寄存器/SRAM内容全部丢失
  3. PLL、HSI和HSE振荡器均关闭
  4. VBAT供电的RTC寄存器,备份域SRAM内容保留,RTC正常工作

WKUP引脚上升沿、RTC闹钟(闹钟A和闹钟B)、RTC唤醒事件、RTC入侵事件、RTC时间戳事件、NRST引脚外部复位和IWDG复位 其中任何一个事件发生时退出待机模式,CPU复位,程序从头开始运行(退出待机模式相当于复位)

另外从待机模式中唤醒后需要注意以下两件事情

  1. 当MCU从待机模式中唤醒后需要使用__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU)软件手动清除唤醒标志,否则下次再次进入待机模式将直接唤醒
  2. 另外可以顺便使用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按键进入停止模式则一切正常

参考资料

STM32Cube高效开发教程(基础篇)

文章来源:https://blog.csdn.net/lc_guo/article/details/135443459
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。