【STM32笔记】深入了解STM32的低功耗模式
一. 低功耗模式
在嵌入式系统设计中,嵌入式系统被广泛的应用在便携式和移动性较强的产品,然而有一些产品并不都是有着充足的电源供应,为了尽可能地延长电池使用时间,这个时候就要考虑降低功率消耗了。
在系统或电源复位以后,微控制器处于运行的状态,当CPU不需要继续运行时,可以利用多种低功耗模式来降低节省功耗。在STM32F103系列芯片中提供了睡眠模式,停止模式和待机模式三种模式。此外,在运行模式下还可以通过降低系统是时钟或关闭APB和AHB总线上未被使用的外设时钟的方式来降低功耗。
此外,在运行模式下,可以通过以下方式中的一种降低功耗

当然在使用低功耗模式时,需要注意仔细配置和管理,在使用STM32的低功耗模式时,需要注意以下几点:
1.在进入低功耗模式之前,需要关闭未使用的外设和时钟,最大程度地降低功耗。
2.在唤醒后,需要重新初始化某一些外设和时钟。
3.低功耗模式需要进行合理的功耗管理和唤醒源选择,以防止设备在必要时未能及时的唤醒,或者时功耗没有达到预期的水平。
二. 睡眠模式
在此模式下,CPU停止工作,但SRAM保持内容。可以通过中断或特定事件唤醒,唤醒后回到睡眠的位置向后执行。
1. 进入睡眠模式
通过执行WFI或WFE指令执行睡眠模式。根据Cortex-M3系统控制寄存器中的SLEEPOONEXIT位的值有两种选项可以用于选择睡眠模式进入该机制。当进入睡眠模式后,所有的I/O引脚都保持它们在运行模式时的状态。
2. 退出睡眠模式
如果是执行WFI指令进入的睡眠模式,任意一个被嵌套向量中断控制器响应的外设中断都能将系统从睡眠模式唤醒。
如果执行WFE指令进入睡眠模式,则一旦发生唤醒事件时,微处理器都将从睡眠模式退出。唤醒事件可以通过下述方式产生:


打开STM32CubeMX,先配置好基础设置。
将PA0设置为外部中断0,通过触发外部中断唤醒STM32

同时使能外部中断通道0

—–睡眠模式(外部中断唤醒)
在mian.c文件中添加如下代码
上电后,LED小灯以每一秒翻转电平6次后进入睡眠模式,当有外部中断触发后,退出睡眠模式,LED小灯继续亮灭。如此反复。
/* Infinite loop */
/* USER CODE BEGIN WHILE */
unsigned int timer = 0;
while (1)
{
// 睡眠模式 外部中断唤醒睡眠模式
HAL_Delay(1000);
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_4);
if(timer == 5){
HAL_SuspendTick(); // 停止系统滴答定时器 这个函数可以自行去go to查找一下或者在stm32f1xx_hal.c文件中查找一下
HAL_PWR_EnterSLEEPMode(0,PWR_SLEEPENTRY_WFI); // 开启STM32的睡眠模式 这个函数可以自行去go to查找一下或者在stm32f1xx_hal_pwr.c文件中查找一下
HAL_ResumeTick(); // 启用系统滴答定时器 这个函数可以自行去go to查找一下或者在stm32f1xx_hal.c文件中查找一下
timer = 0;
}
timer++;
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
—–睡眠模式(外部中断唤醒,但是只处理中断服务函数)
在mian.c文件中添加如下代码
上电后,LED小灯以每一秒翻转电平6次后进入睡眠模式后,当有外部中断触发后,退出睡眠模式,执行外部中断回调函数需要执行的操作,执行完之后再进入睡眠模式。
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// 睡眠模式 外部中断唤醒但是只响应中断服务函数 将翻转电平函数放在外部中断处理函数中
HAL_Delay(1000);
if(timer == 5){
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_4);
HAL_SuspendTick(); // 停止系统滴答定时器
HAL_PWR_EnableSleepOnExit(); // 使能睡眠模式只响应外部中断触发睡眠模式失效,中断服务函数结束后再进入睡眠模式 这个函数可以自行去go to查找一下或者在stm32f1xx_hal_pwr.c文件中查找一下
HAL_PWR_EnterSLEEPMode(0,PWR_SLEEPENTRY_WFI); // 开启STM32的睡眠模式
HAL_ResumeTick(); // 启用系统滴答定时器
timer = 0;
}
timer++;
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
在main.c文件中写入外部中断回调处理函数要做的操作
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
if(GPIO_Pin == GPIO_PIN_0){
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_4);
}
}
/* USER CODE END PFP */
—–睡眠模式(外部事件唤醒)
在mian.c文件中添加如下代码
上电后,LED小灯以每一秒翻转电平6次后进入睡眠模式,当有外部事件触发后,退出睡眠模式,LED小灯继续亮灭。如此反复。
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// 睡眠模式 外部事件唤醒睡眠模式 需要将外部中断线设置为外部事件中断模式
HAL_Delay(1000);
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_4);
if(timer == 5){
HAL_SuspendTick(); // 停止系统滴答定时器
HAL_PWR_EnterSLEEPMode(0,PWR_SLEEPENTRY_WFE); // 开启STM32的睡眠模式
HAL_ResumeTick(); // 启用系统滴答定时器
timer = 0;
}
timer++;
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
三. 停止模式
在此模式下,关闭所有1.8V区域的时钟,同时HSI和HSE RC振荡器也关闭,但SRAM和寄存器保持内容不丢失。可以通过任一外部中断、RTC或特定事件唤醒,唤醒后回到被停止的代码处向后执行,但是要重新初始化时钟和外设。
1. 进入停止模式
在停止模式下,通过设置电源控制寄存器(PWR_CR)的LPDS位使内部调节器进入低功耗模式,能够降低更多的功耗。如果在进入ADC和DAC没有被关闭,则这些外设仍然消耗电流。可以通过设置寄存器ADC_CR2的ADON位和寄存器DAC_CR的ENx位为0可关闭这2个外设。
2. 退出停止模式
当一个中断或唤醒事件导致退出停止模式时,HSI RC振荡器被选为系统时钟。当电压调节器处于低功耗模式下,当系统从停止模式退出时,将会有一段额外的启动延时。如果在停止模式期间保持内部调节器开启,则退出启动时间会缩短,但相应的功耗会增加。
—–停止模式(外部中断唤醒)
在mian.c文件中添加如下代码
上电后,LED小灯以每一秒翻转电平6次后进入停止模式,当有外部中断触发后,退出停止模式,LED小灯继续亮灭。如此反复。
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// 停止模式 外部中断唤醒停止模式 电压调节器为低功耗模式
HAL_Delay(1000);
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_4);
if(timer == 5){
HAL_SuspendTick(); // 停止系统滴答定时器
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON,PWR_STOPENTRY_WFI); // 电压调节器为低功耗模式,开启STM32的停止模式
SystemClock_Config(); // 重新配置系统时钟
HAL_ResumeTick(); // 启用系统滴答定时器
timer = 0;
}
timer++;
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
—–停止模式(外部事件唤醒)
在mian.c文件中添加如下代码
上电后,LED小灯以每一秒翻转电平6次后进入停止模式,当有外部事件触发后,退出停止模式,LED小灯继续亮灭。如此反复。
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// 停止模式 外部事件唤醒停止模式 需要将外部中断线设置为外部事件中断
HAL_Delay(1000);
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_4);
if(timer == 5){
HAL_SuspendTick(); // 停止系统滴答定时器
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON,PWR_STOPENTRY_WFE); // 电压调节器为低功耗模式,开启STM32的停止模式
SystemClock_Config(); // 重新配置系统时钟
HAL_ResumeTick(); // 启用系统滴答定时器
timer = 0;
}
timer++;
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
四. 待机模式
在此模式下,时关闭电压调节器。整个1.8V供电区域被断电。PLL、HSI和HSE振荡器也被断电。SRAM和寄存器内容丢失。只有备份的寄存器和待机电路维持供电,当一个外部复位(NRST脚)、IWDG复位、WKUP引脚(PA0)上的上升沿或RTC闹钟事件的上升沿发生时,微控制器才可从待机模式退出。
1. 进入待机模式
2. 退出待机模式
—–待机模式(外部事件唤醒)
在mian.c文件中添加如下代码
上电后,LED小灯以每一秒翻转电平6次后进入停止模式,当有外部中断触发后,退出待机模式,LED小灯继续亮灭。如此反复。
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// 待机模式 WKUP唤醒待机模式(上升沿) 当触发唤醒时其效果相当与按下了开发板的复位键 注意:需要手动将按键PA0设置为SYS_WKUP模式(STM32CubeMX配置的SYS_WKUP无法使用)
HAL_Delay(1000);
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_4);
if(timer == 5){
SET_BIT(PWR->CR,PWR_CR_CWUF_Msk);
HAL_PWR_EnterSTANDBYMode(); // 开启STM32的待机模式
timer = 0;
}
timer++;
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
}
/* USER CODE BEGIN 2 */
// 待机模式
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1); // 将PA0设置为SYS_WKUP模式
SET_BIT(PWR->CR,PWR_CR_CSBF_Msk); // 清除唤醒位标志 SET_BIT 宏定义函数是用于在寄存器中设置某个特定的位。
SET_BIT(PWR->CR,PWR_CR_CWUF_Msk); // 清除待机位标志
/* USER CODE END 2 */