历史上的今天
今天是:2024年10月29日(星期二)
2021年10月29日 | stm32专题三十二:stm32功耗模式
2021-10-29 来源:eefocus
stm32功耗模式
按功耗由高到低排列,STM32 具有运行、睡眠、停止和待机四种工作模式。上电复位后 STM32处于运行状态时,当内核不需要继续运行,就可以选择进入后面的三种低功耗模式降低功耗,这三种模式中,电源消耗不同、唤醒时间不同、唤醒源不同,用户需要根据应用需求,选择最佳的低功耗模式。三种低功耗的模式说明见下表。
睡眠模式下,任何中断都可以唤醒内核,外部 / 内部高速时钟保持打开,调压器保持打开,因此,内核只要被唤醒,就能马上正常的执行程序(优点:响应速度快;缺点:功耗比较大);
停止模式下,HSE和HSI被关闭,调压器可选开启或低功耗模式(若选为低功耗模式,则还需要加上调压器从低功耗切换至正常模式下的时间),外部中断唤醒内核。当内核被唤醒时,需要重新配置系统时钟使用外部 HSE 且 PLL 正常倍频(System_Init函数),这个过程就会消耗一定时间;否则程序会直接使用 HSI(不倍频) = 8MHz 作为系统时钟,此时系统运行的相当慢,一些对时钟要求较高的函数配置会无法运行(优点:工号较小;缺点:需要重新配置系统时钟,响应速度慢);
待机模式下,整个1.8V供电区域被关闭,调压器被关闭,只能特定方式唤醒。唤醒之后程序从最开始(启动文件)执行(优点:功耗最低;缺点,每次都是复位执行);
低功耗模式的区别
关于睡眠模式 停止模式 待机模式 的区别,可以分析如下代码:
while(1)
{
/*********执行任务***************************/
printf("rn STM32正常运行,亮绿灯rn");
LED_GREEN;
Delay(0x3FFFFF);
/*****任务执行完毕,进入睡眠降低功耗***********/
printf("rn 进入睡眠模式,按KEY1或KEY2按键可唤醒rn");
//使用红灯指示,进入睡眠状态
LED_RED;
//进入睡眠模式
__WFI(); //WFI指令进入睡眠
//等待中断唤醒 K1或K2按键中断
/***被唤醒,亮蓝灯指示***/
LED_BLUE;
Delay(0x1FFFFF);
printf("rn 已退出睡眠模式rn");
//继续执行while循环
}
}
睡眠 模式
当程序上电开始执行时,会一直执行到LED_RED,然后调用__WFI()指令进入睡眠模式,此时,内核停止工作,程序不再往下执行。而当中断来临时,内核被唤醒,程序继续执行while循环,当下一次执行到__WFI()时,再次进入睡眠状态,等待唤醒。
停止 模式
当程序上电开始执行时,会一直执行到LED_RED,然后调用__WFI()指令进入睡眠模式,此时,内核停止工作,程序不再往下执行。而当中断来临时,内核被唤醒,等待系统时钟配置成功(消耗时间),程序继续执行while循环,当下一次执行到__WFI()时,再次进入睡眠状态,等待唤醒。
待机模式
一旦进入待机模式,整个1.8V供电区域(内核 NVIC全部断电),只能通过几种特定的方式唤醒,此时,程序将从头开始执行(从启动文件那里开始执行)。
3种模式的详细描述和寄存器配置
1 睡眠模式(任意中断唤醒:systick中断,串口中断等...)

内核寄存器配置说明如下:

关于立即睡眠和退出后睡眠的区别(中文参考手册):

2 停止模式(外部中断唤醒),开启后会默认使用HSI作为系统时钟,通常我们为确保正常使用,还要重新开启HSE:
相关的寄存器配置:

电源控制寄存器,配置停止模式(正常 or 低功耗):
3 待机模式(WKUP[PA0引脚]、RTC、复位、IWDG看门狗),很类似于直接掉电:

相关的寄存器配置:
电源管理库函数
1 配置PVD检测函数 PWR_PVDLevelConfig ,其实就是写入PWR_CR寄存器的这几位:

标准库函数源码:
/**
* @brief Configures the voltage threshold detected by the Power Voltage Detector(PVD).
* @param PWR_PVDLevel: specifies the PVD detection level
* This parameter can be one of the following values:
* @arg PWR_PVDLevel_2V2: PVD detection level set to 2.2V
* @arg PWR_PVDLevel_2V3: PVD detection level set to 2.3V
* @arg PWR_PVDLevel_2V4: PVD detection level set to 2.4V
* @arg PWR_PVDLevel_2V5: PVD detection level set to 2.5V
* @arg PWR_PVDLevel_2V6: PVD detection level set to 2.6V
* @arg PWR_PVDLevel_2V7: PVD detection level set to 2.7V
* @arg PWR_PVDLevel_2V8: PVD detection level set to 2.8V
* @arg PWR_PVDLevel_2V9: PVD detection level set to 2.9V
* @retval None
*/
void PWR_PVDLevelConfig(uint32_t PWR_PVDLevel)
{
uint32_t tmpreg = 0;
/* Check the parameters */
assert_param(IS_PWR_PVD_LEVEL(PWR_PVDLevel));
tmpreg = PWR->CR;
/* Clear PLS[7:5] bits */
tmpreg &= CR_PLS_MASK;
/* Set PLS[7:5] bits according to PWR_PVDLevel value */
tmpreg |= PWR_PVDLevel;
/* Store the new value */
PWR->CR = tmpreg;
}
2 WFI 与 WFE 命令:
/* ################### Compiler specific Intrinsics ########################### */
#if defined ( __CC_ARM ) /*------------------RealView Compiler -----------------*/
/* ARM armcc specific functions */
#define __enable_fault_irq __enable_fiq
#define __disable_fault_irq __disable_fiq
#define __NOP __nop
#define __WFI __wfi
#define __WFE __wfe
#define __SEV __sev
#define __ISB() __isb(0)
#define __DSB() __dsb(0)
#define __DMB() __dmb(0)
#define __REV __rev
#define __RBIT __rbit
#define __LDREXB(ptr) ((unsigned char ) __ldrex(ptr))
#define __LDREXH(ptr) ((unsigned short) __ldrex(ptr))
#define __LDREXW(ptr) ((unsigned int ) __ldrex(ptr))
#define __STREXB(value, ptr) __strex(value, ptr)
#define __STREXH(value, ptr) __strex(value, ptr)
#define __STREXW(value, ptr) __strex(value, ptr)
3 进入停止模式
配置PWR_CR寄存器的这两个位,以及SLEEPDEEP位。

/**
* @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();
}
/* 以下的程序是当重新唤醒时才执行的,清除 SLEEPDEEP 位的状态 */
SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP);
}
在执行最后一句代码前,系统由于调用了__WFI 或 __WFE,已经进入了停止模式,因此,这句清除SLEEPDEEP 位并不会执行。而当内核重新被唤醒时,才会清除SLEEPDEEP位,方便使用。
SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP);

4 进入待机模式(很简单):
/**
* @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();
}
PVD电源监控
实际上,PVD监测的是VDD的电压,也就是stm32的供电电压。当我们调节(降低VDD电压)时,PVD一旦监测到小于设置的阈值,就会产生PVD中断。

标准库中,关于PVD的函数:
1 监测电压等级配置
/**
* @brief Configures the voltage threshold detected by the Power Voltage Detector(PVD).
* @param PWR_PVDLevel: specifies the PVD detection level
* This parameter can be one of the following values:
* @arg PWR_PVDLevel_2V2: PVD detection level set to 2.2V
* @arg PWR_PVDLevel_2V3: PVD detection level set to 2.3V
* @arg PWR_PVDLevel_2V4: PVD detection level set to 2.4V
* @arg PWR_PVDLevel_2V5: PVD detection level set to 2.5V
* @arg PWR_PVDLevel_2V6: PVD detection level set to 2.6V
* @arg PWR_PVDLevel_2V7: PVD detection level set to 2.7V
* @arg PWR_PVDLevel_2V8: PVD detection level set to 2.8V
* @arg PWR_PVDLevel_2V9: PVD detection level set to 2.9V
* @retval None
*/
void PWR_PVDLevelConfig(uint32_t PWR_PVDLevel)
{
uint32_t tmpreg = 0;
/* Check the parameters */
assert_param(IS_PWR_PVD_LEVEL(PWR_PVDLevel));
tmpreg = PWR->CR;
/* Clear PLS[7:5] bits */
tmpreg &= CR_PLS_MASK;
/* Set PLS[7:5] bits according to PWR_PVDLevel value */
tmpreg |= PWR_PVDLevel;
/* Store the new value */
PWR->CR = tmpreg;
}
2 PVD监测使能函数
/**
* @brief Enables or disables the Power Voltage Detector(PVD).
* @param NewState: new state of the PVD.
* This parameter can be: ENABLE or DISABLE.
* @retval None
*/
void PWR_PVDCmd(FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_FUNCTIONAL_STATE(NewState));
*(__IO uint32_t *) CR_PVDE_BB = (uint32_t)NewState;
}
整个配置的过程其实很简单:
/**
* @brief 配置PVD.
* @param None
* @retval None
*/
void PVD_Config(void)
上一篇:stm32专题三十一:电源管理
史海拾趣
|
信任你没有见过这样的摩托车,从侧面看就像是一个轮子,其实它有2个并排的轮子,左右平衡容易控制一些,但这样的怪异摩托车前后平衡感到还是很难节制的,看到这个摩托车的第一感到就是担心在快速行进当中,因为平衡没有控制好而向前栽倒。这款叫Uno ...… 查看全部问答> |
|
wince5.0 USB HOST 只能插入两个U盘,怀疑是wince驱动的问题,希望探讨一下! 如题,我在wince5.0下接两个U盘可以正常工作,但接第三个U盘时会跳出输入驱动名称的对话框,而且供电电流是足够的,现在在研究wince的USB HOST驱动,还没发现什么问题,希望有研究过的可以指点一下!… 查看全部问答> |
|
1. 不要看到别人的回复,第一句话就说:给个代码吧!你应该想想为什么。当你自己想出来再参考别人的提示,你就知道自己和别人思路的差异。 2. 初学者请不要看太多的书那会误人子弟的。先找一本好书系统的学习。很多人用了很久都是只对部分功能熟悉 ...… 查看全部问答> |













