一.低功耗模式介绍
系统提供了多个低功耗模式,可在 CPU 不需要运行时(例如等待外部事件时)节省功耗。由用户根据应用选择具体的低功耗模式,以在低功耗、短启动时间和可用唤醒源之间寻求最佳平衡。
当系统断电时,仍然可以通过电池供电保留备份域的数据。备份域中包含RTC实时时钟,4KB备份SRAM以及调压器,调压器为备份域和待机电路以外数字电路供电,输出电压约为1.2V。

器件有三个低功耗模式:
此外,可通过下列方法之一降低运行模式的功耗:
睡眠模式只是内核停止,外接还能继续工作,I/O管脚状态没有改变。
停止模式是在睡眠模式的基础上把所有的时钟都停止了,振荡器也被禁止。此时所有外设已经停止工作。
待机模式基于 Cortex®-M7 深度睡眠模式,此时内核停止,外设也停止工作,1.2V域断电。除备份域和待机电路中的寄存器外,其他全部停止工作,SRAM和寄存器内容将丢失。只是备份域中RTC继续工作,备份ARAM数据不会丢失继续保存。此时三种低功耗模式中,待机模式可达到最低功耗。

进入低功耗模式
当 MCU 执行 WFI(等待中断)或 WFE(等待事件)指令,或者当 Cortex®-M7 系统控制寄存器中的 SLEEPONEXIT 位在从 ISR 恢复期间置 1 时,将进入低功耗模式。仅当没有中断和事件挂起时,才能通过 WFI 或 WFE 进入低功耗模式。
退出低功耗模式
在睡眠和停止模式下, MCU 根据进入低功耗模式的方式退出低功耗模式。
如果使用 WFI 指令或从 ISR 恢复的方式进入低功耗模式,则通过 NVIC 应答的任何外设中断均可唤醒器件
如果使用 WFE 指令进入低功耗模式,则 MCU 会在事件发生时立即退出低功耗模式
在待机模式下, MCU 退出低功耗模式的方式包括:外部复位(NRST 引脚)、 IWDG(独立看门狗) 复位、已使能WKUPx 引脚之一的上升沿或者 RTC 事件。stm32F7xx有六个WKUP 引脚(PA0/PA2/PC1/PC13/PI8/PI11)。
二.实验例程
本章程序在串口printf工程的基础上修改,复制串口printf的工程,修改文件夹名。击STM32F746I.ioc打开STM32cubeMX的工程文件重新配置。RTC选择内部唤醒开启RTC。PA0(WAKEUP管脚)配置为中断外部中断引脚,同时配置LED管脚。

配置RTC时间和日期,其他为默认配置。Wake UP唤醒设置在程序中设置,在此不作设置。

开启外部中断0号线中断。

生成报告以及代码,编译程序。在stm32f7xx_hal_pwr.h头文件中可以看到低功耗控制函数。
下载这两个应用程序文件,c文件放在工程目录下Src文件夹中,头文件放在Inc文件中,并在工程中添加刚才的应用程序文件。

打开stm32fxx_lp_modes.c文件中,里面有五个低功耗测试程序。在stm32fxx_lp_modes.h文件中,可以看到函数声明和宏定义低功耗模式。而已通过去掉相应行的注释选择一种低功耗模式。
| 01 | /* Exported constants --------------------------------------------------------*/ |
| 02 | #if !defined (SLEEP_MODE) && !defined (STOP_MODE) && !defined (STANDBY_MODE) |
| 03 | && !defined (STANDBY_RTC_MODE) && !defined (STANDBY_BKPSRAM_MODE) |
| 04 | /* Uncomment the corresponding line to select the STM32F7xx Low Power mode */ |
| 08 | //#define STANDBY_RTC_MODE |
| 09 | //#define STANDBY_BKPSRAM_MODE |
| 12 | #if !defined (SLEEP_MODE) && !defined (STOP_MODE) && !defined (STANDBY_MODE) |
| 13 | && !defined (STANDBY_RTC_MODE) && !defined (STANDBY_BKPSRAM_MODE) |
| 14 | #error "Please select first the target STM32F7xx Low Power mode to be measured (in stm32f7xx_lp_modes.h file)" |
| 17 | /* Exported macro ------------------------------------------------------------*/ |
| 18 | /* Exported functions ------------------------------------------------------- */ |
| 19 | void SleepMode_Measure(void); |
| 20 | void StopMode_Measure(void); |
| 21 | void StandbyMode_Measure(void); |
| 22 | void StandbyRTCMode_Measure(void); |
| 23 | void StandbyBKPSRAMMode_Measure(void); |
在这里补充一下C语言的语法知识.#if ... #endif为调节编译语句,只有满足条件时才编译中间部分的语句。
第一个#if #endif语句的意思是如果没有宏定义相应低功耗模式的则编译中间的宏定义。
第二个#if #endif语句的意思是如果还是没有相应的低功耗模式宏定义,则提示错误。此时编译程序时会提示上面的错误提示信息。
在main.c文件前面添加头文件,定义用户按键标志变化和声明错误处理函数。
| 01 | /* USER CODE BEGIN Includes */ |
| 02 | #include "stm32f7xx_lp_modes.h" |
| 03 | /* USER CODE END Includes */ |
| 05 | /* USER CODE BEGIN PV */ |
| 06 | /* Private variables ---------------------------------------------------------*/ |
| 07 | __IO uint8_t UserButtonStatus = 0; |
| 10 | /* Private function prototypes -----------------------------------------------*/ |
| 11 | void SystemClock_Config(void); |
| 13 | /* USER CODE BEGIN PFP */ |
| 14 | /* Private function prototypes -----------------------------------------------*/ |
| 15 | void Error_Handler(void); |
| 16 | /* USER CODE END PFP */ |
在main.c文件后面添加外部中断回调函数和错误处理函数。中断回调函数将按键标志位置1,错误处理函数打印错误信息,然后进行while循环。
| 01 | /* USER CODE BEGIN 4 */ |
| 03 | * @brief This function is executed in case of error occurrence. |
| 07 | void Error_Handler(void) |
| 09 | printf("something wrong !!!rn"); |
| 15 | * @brief EXTI line detection callbacks |
| 16 | * @param GPIO_Pin: Specifies the pins connected EXTI line |
| 19 | void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) |
在main.c主函数中添加应用测试程序。程序中不断读取用户按键标志,同时LED1不断闪烁。但有WAKEUP按键按下时,跳出循环,然后等待按键释放,关闭LED1。最后根据stm32fxx_lp_modes.h中的宏定义,进入对应的低功耗模式测试函数。
| 01 | /* USER CODE BEGIN 2 */ |
| 02 | printf("rn******** STM32F7 LowPower Test *******rn"); |
| 06 | /* USER CODE BEGIN WHILE */ |
| 09 | /* USER CODE END WHILE */ |
| 11 | /* USER CODE BEGIN 3 */ |
| 12 | printf("Press WAKEUP button to enter LP modes rnrn"); |
| 16 | /* Wait until USER button is pressed to enter the Low Power mode */ |
| 17 | while(UserButtonStatus == 0x00) |
| 20 | HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin); |
| 26 | /* Loop while User button is maintained pressed */ |
| 27 | while(HAL_GPIO_ReadPin(WAKEUP_GPIO_Port,WAKEUP_Pin) != RESET) |
| 32 | HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_RESET); |
| 34 | #if defined (SLEEP_MODE) |
| 36 | - System Running at PLL (216MHz) |
| 38 | - Instruction and Data caches ON |
| 40 | - Code running from Internal FLASH |
| 41 | - All peripherals disabled. |
| 42 | - Wake-up using EXTI Line (USER Button) |
| 44 | printf("SleepMode!rnPress WAKE_UP button to wake up ...rn"); |
| 46 | printf("rnSLEEP_MODE wake up,system running continue ... rn"); |
| 48 | #elif defined (STOP_MODE) |
| 51 | - Regulator in LP mode |
| 52 | - HSI, HSE OFF and LSI OFF if not used as RTC Clock source |
| 54 | - FLASH in deep power down mode |
| 55 | - Automatic Wake-up using RTC clocked by LSI (after ~20s) |
| 57 | printf("StopMode!rnAutomatic Wake-up using RTC clocked by LSI (after ~20s) ...rn"); |
| 59 | MX_USART1_UART_Init(); |
| 60 | printf("rnStopMode wake up ,system running continue rn"); |
| 62 | #elif defined (STANDBY_MODE) |
| 64 | - Backup SRAM and RTC OFF |
| 66 | - Wake-up using WakeUp Pin (PI.11) |
| 68 | printf("StandbyMode!rnPress WAKE_UP button to wake up ...rn"); |
| 69 | StandbyMode_Measure(); |
| 70 | printf("StandbyMode wake up ,this will never be running ,something wrong!! rn"); |
| 71 | #elif defined (STANDBY_RTC_MODE) |
| 72 | /* STANDBY Mode with RTC on LSI Entry |
| 74 | - IWDG OFF and LSI OFF if not used as RTC Clock source |
| 76 | - Automatic Wake-up using RTC clocked by LSI (after ~20s) |
| 78 | printf("StandbyRTCMode!rnPress WAKE_UP button to wake up ...rn"); |
| 79 | StandbyRTCMode_Measure(); |
| 80 | printf("StandbyMode wake up ,this will never be running ,something wrong!! rn"); |
| 82 | #elif defined (STANDBY_BKPSRAM_MODE) |
| 86 | - Wake-up using WakeUp Pin (PI.11) |
| 88 | printf("StandbyBKPSRAMMode!rnPress WAKE_UP button to wake up ...rn"); |
| 89 | StandbyBKPSRAMMode_Measure(); |
| 90 | printf("StandbyBKPSRAMMode wake up ,this will never be running ,something wrong!! rn"); |
此处也用到条件编译语句。例如stm32fxx_lp_modes.h头文件中宏定义STOP_MODE。则程序编译的时候只会编译STOP_MODE选项中的语句。其他的语句不会编译进程序,不会写入stm32的flash中。可以在stm32fxx_lp_modes.h头开启不同的宏选择编译对应不同的语句。
下面我们来详细分析一下各种低功耗模式的运行流程。
1.SLEEP_MODE
php代码:
| 02 | * @brief This function configures the system to enter Sleep mode for |
| 03 | * current consumption measurement purpose. |
| 06 | * - System Running at PLL (216MHz) |
| 07 | * - Flash 5 wait state |
| 08 | * - Instruction and Data caches ON |
| 10 | * - Code running from Internal FLASH |
| 11 | * - Wakeup using EXTI Line (USER Button) |
| 15 | void SleepMode_Measure(void) |
| 18 | /* Suspend Tick increment to prevent wakeup by Systick interrupt. |
| 19 | Otherwise the Systick interrupt will wake up the device within 1ms (HAL time base) */ |
| 22 | /* Request to enter SLEEP mode */ |
| 23 | HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI); |
| 25 | /* Resume Tick interrupt if disabled prior to sleep mode entry */ |
睡眠模式Cortex®-M7 内核停止,程序以WFI指令进入睡眠模式,所以只要产生任意中断都会退出睡眠模式。所以进入睡眠模式前先调用HAL_SuspendTick()函数挂起系统滴答定时器,否则将会被系统滴答定时器(SysTick)中断在1ms内唤醒。程序运行到HAL_PWR_EnterSLEEPMode()函数时,系统进入睡眠模式,程序停止运行。当按下WAKEUP按键时,触发外部中断0,此时系统被唤醒。继续执行HAL_ResumeTick()语句回复系统滴答定时器。