STM32F10x进入低功耗模式
目录
- STM32F10x进入低功耗模式
- 1 低功耗模式简介
- 2 睡眠模式详解
- 3 停止模式详解
- 4 待机模式详解
- 5 示例代码
- 5.1 标准库函数定义
- 5.2 进入低功耗模式参考代码
- 结束语
1 低功耗模式简介
在系统或电源复位以后,微控制器处于运行状态。当CPU不需继续运行时,可以利用多种低功耗模式来节省功耗,例如等待某个外部事件时。用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。
STM32F10x有三种低功耗模式:
1、睡眠模式
Cortex-M3内核停止,所有外设包括Cortex™-M3核心的外设,如NVIC、系统时钟(SysTick)等仍在运行
2、停止模式
所有的时钟都已停止
3、待机模式
1.8V电源关闭(CPU核心区域)
低功耗模式一览:
STM32电源框图:
此外,在运行模式下,可以通过以下方式中的一种降低功耗:
1、降低系统时钟。
2、关闭APB和AHB总线上未被使用的外设时钟。
2 睡眠模式详解
通过执行WFI或WFE指令可以进入睡眠状态。根据Cortex™-M3系统控制寄存器中的SLEEPONEXIT位的值,有两种选项可用于选择睡眠模式进入机制:
1、SLEEP-NOW:如果SLEEPONEXIT位被清除,当WFI或WFE被执行时,微控制器立即进入睡眠模式。
2、SLEEP-ON_EXIT:如果SLEEPONEXIT位被置位,系统从最低优先级的中断处理程序中退出时,微控制器就立即进入睡眠模式。
SLEEP-NOW模式一览:
SLEEP-ON_EXIT模式一览:
3 停止模式详解
停止模式是在Cortex™-M3的深睡眠模式基础上结合了外设的时钟控制机制,在停止模式下电压调节器可运行在正常或低功耗模式。
此时在1.8V供电区域的的所有时钟都被停止,PLL、HSI和HSE RC振荡器的功能被禁止,SRAM和寄存器内容被保留下来。
在停止模式下,所有的I/O引脚都保持它们在运行模式时的状态。
停止模式进入和退出的方法如下:
进入停止模式:
在停止模式下,通过设置电源控制寄存器(PWR_CR)的LPDS位使内部调节器进入低功耗模式,能够降低更多的功耗。
需要注意:
1、如果正在进行闪存编程,直到对内存访问完成,系统才进入停止模式。
2、如果正在进行对APB的访问,直到对APB访问完成,系统才进入停止模式。
3、在进入停止模式前,如果一些外设没有被关闭,那么外设仍然消耗电流,如串口、ADC、DAC等。
退出停止模式:
通过中断或者唤醒事件可以退出停止模式。
需要注意:
1、退出停止模式后,HSI RC振荡器被默认选为系统时钟。
2、当电压调节器处于低功耗模式下,当系统从停止模式退出时,将会有一段额外的启动延时。如果在停止模式期间保持内部调节器开启,则退出启动时间会缩短,但相应的功耗会增加。
4 待机模式详解
待机模式可实现系统的最低功耗。该模式是在Cortex-M3深睡眠模式时关闭电压调节器。整个1.8V供电区域被断电。PLL、HSI和HSE振荡器也被断电。SRAM和寄存器内容丢失。只有备份的寄存器和待机电路维持供电。
待机模式进入和退出的方法如下:
进入待机模式:
进入待机模式需要做到以下几点:
1、设置Cortex-M3系统控制寄存器中的SLEEPDEEP位。
2、清除电源控制寄存器(PWR_CR)中的PDDS位。
3、通过设置PWR_CR中LPDS位选择电压调节器的模式。
退出待机模式:
当一个外部复位(NRST引脚)、IWDG复位、WKUP引脚上的上升沿或RTC闹钟事件的上升沿发生时,微控制器从待机模式退出。从待机唤醒后,除了电源控制/状态寄存器(PWR_CSR),所有寄存器被复位。
从待机模式唤醒后的代码执行等同于复位后的执行(采样启动模式引脚、读取复位向量等)。电源控制/状态寄存器(PWR_CSR)将会指示内核由待机状态退出。
5 示例代码
5.1 标准库函数定义
睡眠模式标准库函数代码:
static __INLINE void __WFI() { __ASM ("wfi"); }
static __INLINE void __WFE() { __ASM ("wfe"); }
停机模式标准库函数代码:
/*** @brief Enters STOP mode.* @param PWR_Regulator: specifies the regulator state in STOP mode.* This parameter can be one of the following values:* @arg PWR_Regulator_ON: STOP mode with regulator ON* @arg PWR_Regulator_LowPower: STOP mode with regulator in low power mode* @param PWR_STOPEntry: specifies if STOP mode in entered with WFI or WFE instruction.* This parameter can be one of the following values:* @arg PWR_STOPEntry_WFI: enter STOP mode with WFI instruction* @arg PWR_STOPEntry_WFE: enter STOP mode with WFE instruction* @retval None*/
void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry)
{uint32_t tmpreg = 0;/* Check the parameters */assert_param(IS_PWR_REGULATOR(PWR_Regulator));assert_param(IS_PWR_STOP_ENTRY(PWR_STOPEntry));/* Select the regulator state in STOP mode ---------------------------------*/tmpreg = PWR->CR;/* Clear PDDS and LPDS bits */tmpreg &= CR_DS_MASK;/* Set LPDS bit according to PWR_Regulator value */tmpreg |= PWR_Regulator;/* Store the new value */PWR->CR = tmpreg;/* Set SLEEPDEEP bit of Cortex System Control Register */SCB->SCR |= SCB_SCR_SLEEPDEEP;/* Select STOP mode entry --------------------------------------------------*/if(PWR_STOPEntry == PWR_STOPEntry_WFI){ /* Request Wait For Interrupt */__WFI();}else{/* Request Wait For Event */__WFE();}/* Reset SLEEPDEEP bit of Cortex System Control Register */SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP);
}
待机模式标准库函数代码:
/*** @brief Enters STANDBY mode.* @param None* @retval None*/
void PWR_EnterSTANDBYMode(void)
{/* Clear Wake-up flag */PWR->CR |= PWR_CR_CWUF;/* Select STANDBY mode */PWR->CR |= PWR_CR_PDDS;/* Set SLEEPDEEP bit of Cortex System Control Register */SCB->SCR |= SCB_SCR_SLEEPDEEP;
/* This option is used to ensure that store operations are completed */
#if defined ( __CC_ARM )__force_stores();
#endif/* Request Wait For Interrupt */__WFI();
}
5.2 进入低功耗模式参考代码
低功耗模式参考代码:
#include "delay.h"
#include "sys.h"
#include "usart.h"#define KEY0 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4) //读取按键0
#define KEY1 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3) //读取按键1
#define KEY2 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2) //读取按键2
#define WK_UP GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) //读取按键3(WK_UP) uint8_t set_mcu_mode = 0; //设置MCU模式,0:运行状态,1:睡眠模式,2:停机模式,3:待机模式//外部中断0服务程序
void EXTI0_IRQHandler(void)
{delay_ms(10);//消抖if(WK_UP == 1) //WK_UP按键{ SystemInit(); //MCU被唤醒,重新配置系统时钟set_mcu_mode = 0;printf("MCU wake up\r\n");}EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中断标志位
}//外部中断2服务程序
void EXTI2_IRQHandler(void)
{delay_ms(10);//消抖if(KEY2 == 0) //按键KEY2{set_mcu_mode = 1; //需要进入睡眠模式printf("key2\r\n");} EXTI_ClearITPendingBit(EXTI_Line2); //清除LINE2上的中断标志位
}
//外部中断3服务程序
void EXTI3_IRQHandler(void)
{delay_ms(10);//消抖if(KEY1 == 0) //按键KEY1{ set_mcu_mode = 2; //需要进入停机模式printf("key1\r\n");} EXTI_ClearITPendingBit(EXTI_Line3); //清除LINE3上的中断标志位
}void EXTI4_IRQHandler(void)
{delay_ms(10);//消抖if(KEY0 == 0) //按键KEY0{set_mcu_mode = 3; //需要进入待机模式printf("key0\r\n");} EXTI_ClearITPendingBit(EXTI_Line4); //清除LINE4上的中断标志位
}//外部中断初始化
void EXTIX_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;EXTI_InitTypeDef EXTI_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOE, ENABLE);//使能PORTA,PORTE时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;//KEY0-KEY2GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE2,E3,E4GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//WK_UP KEY-->GPIOA0GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0设置成输入,默认下拉 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA0RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使能复用功能时钟//GPIOE2 中断线以及中断初始化配置 下降沿触发GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);EXTI_InitStructure.EXTI_Line=EXTI_Line2; //KEY2EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器//GPIOE3 中断线以及中断初始化配置 下降沿触发 GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);EXTI_InitStructure.EXTI_Line=EXTI_Line3; //KEY1EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器//GPIOE4 中断线以及中断初始化配置 下降沿触发 GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);EXTI_InitStructure.EXTI_Line=EXTI_Line4; //KEY0EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器//GPIOA0 中断线以及中断初始化配置 上升沿触发 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); EXTI_InitStructure.EXTI_Line=EXTI_Line0; //WK_UP KEYEXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //使能按键WK_UP所在的外部中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2, NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03; //子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //使能按键KEY2所在的外部中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2, NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级2NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //使能按键KEY1所在的外部中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //子优先级1 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn; //使能按键KEY0所在的外部中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; //子优先级0 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}void LED_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE); //使能PB,PE端口时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED0-->PB5 端口配置GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHzGPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB5GPIO_SetBits(GPIOB,GPIO_Pin_5); //PB5 输出高
}int main(void)
{ delay_init(); //延时函数初始化 uart_init(115200); //串口初始化为115200LED_Init(); //初始化与LED连接的硬件接口EXTIX_Init(); //外部中断初始化while(1){ if(set_mcu_mode > 0){switch (set_mcu_mode){case 1://进入睡眠模式printf("Enter sleep mode\r\n");__WFI();break;case 2://进入停机模式printf("Enter stop mode\r\n");PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI);break;case 3://进入待机模式printf("Enter standby mode\r\n");PWR_EnterSTANDBYMode();break;default:break;}}GPIO_ResetBits(GPIOB, GPIO_Pin_5); //点亮LED0delay_ms(200); GPIO_SetBits(GPIOB, GPIO_Pin_5); //关闭LED0delay_ms(200); }
}
示例代码测试结果:
1、MCU正常运行,LED0定时闪烁。
2、按下KEY0,MCU进入待机模式,LED0熄灭,再按下KEY3(WK_UP),MCU被唤醒继续运行。
3、按下KEY1,MCU进入停机模式,LED0熄灭,再按下KEY3(WK_UP),MCU被唤醒继续运行。
4、按下KEY2,MCU进入睡眠模式,LED0熄灭,再按下KEY3(WK_UP),MCU被唤醒继续运行。
结束语
上面的测试例子只是给大家做一个参考,实际上需要根据项目的具体需求去补充很多细节,比如进入低功耗模式的触发条件,唤醒的方式,以及进入睡眠之前对外设的处理,等等,这样才能保证在实现功能需求的同时,又能尽可能的把功耗降到最低。
好了,关于STM32如何进入低功耗模式就介绍到这里,如果你们有什么问题,欢迎评论区留言。
如果这篇文章能够帮到你,就…懂的。