STM32实战总结:HAL之低功耗

低功耗的含义不必过多解释,一听就能懂。

低功耗对电池供电产品尤其重要。

STM32的有三种低功耗模式,即睡眠模式、停止模式和待机模式。

在我的印象中,停止不就是关机吗?但并不是。

在系统或电源复位以后,微控制器处于运行状态。当CPU不需继续运行时,可以利用多种低功耗模式来节省功耗,例如等待某个外部事件时。用户需要根据最低电源消耗最快速启动时间可用的唤醒源等条件,选定一个最佳的低功耗模式。

● 睡眠模式

仅Cortex™-M3内核停止,其他所有外设包括Cortex-M3核心的外设,如NVIC、系统时

(SysTick)等仍在运行。

● 停止模式

所有的时钟都已停止。

● 待机模式

1.8V电源关闭。

WFI:Wait For Interrupt,WFE:Wait For Event

WFI(Wait for interrupt)和WFE(Wait for event)是两个让ARM核进入low-power模式的指令,由ARM architecture定义,由ARM core实现。

WFI = wait for interrupt 等待中断,即下一次中断发生前都在此hold住不干活。

WFE = wait for event 等待事件,即下一次事件发生前都在此hold住不干活。

这是ARM里CMSIS内核中的指令:

cmsis_arm.cc里有如下说明

/**
\brief Wait For Interrupt
\details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs.
*/
#define __WFI __wfi

/**
\brief Wait For Event
\details Wait For Event is a hint instruction that permits the processor to enter
a low-power state until one of a number of events occurs.
*/
#define __WFE __wfe

WFI 或 WFE 命令,它们实质上都是内核指令,在库文件 core_cmInstr.h 中把这些指令封装成了函数。

对于这两个指令,我们应用时一般只需要知道,调用它们都能进入低功耗模式。__wfi及__wfe 是编译器内置的函数,函数内部使用调用了相应的汇编指令。其中 WFI指令决定了它需要用中断唤醒,而WFE 则决定了它可用事件来唤醒,关于它们更详细的区别可查阅《cortex-CM3/CM4权威指南》了解。

注:非低功耗状态下被称为运行模式。

run、sleep、stop、standby

从表中可以看到,这三种低功耗模式层层递进,运行的时钟或芯片功能越来越少,因而功耗越来越低。

此外,在运行模式下,可以通过以下方式中的一种降低功耗:

● 降低系统时钟

● 关闭APBAHB总线上未被使用的外设时钟。

在运行模式下,通过对预分频寄存器进行编程,可以降低任意一个系统时钟(SYSCLK

HCLKPCLK1PCLK2)的速度。进入睡眠模式前,也可以利用预分频器来降低外设的时钟。

睡眠模式

在睡眠模式中,仅关闭了内核时钟,内核停止运行,但其片上外设,CM3核心的外设全都还照常运行,在软件上表现为不再执行新的代码

这个状态会保留睡眠前的内核寄存器、内存的数据。

唤醒后 ,若由中断唤醒,先进入中断,退出中断服务程序后,接着执行 WFI 指令后的程序;若由事件唤醒,直接接着执行 WFE 后的程序。

唤醒延迟:无延迟。

停止模式

停止模式是在Cortex™-M3的深睡眠模式基础上结合了外设的时钟控制机制,在停止模式下电压调节器可运行在正常或低功耗模式。此时在1.8V供电区域的的所有时钟都被停止,PLLHSI和HSE RC振荡器的功能被禁止,SRAM和寄存器内容被保留下来。

在停止模式下,所有的I/O引脚都保持它们在运行模式时的状态。

在停止模式中,进一步关闭了其它所有的时钟,于是所有的外设都停止了工作,但由于其 1.8V 区域的部分电源没有关闭,还保留了内核的寄存器、内存的信息,所以从停止模式唤醒,并重新开启时钟后,还可以从上次停止处继续执行代码

唤醒后,若由中断唤醒,先进入中断,退出中断服务程序后,接着执行 WFI 指令后的程序;若由事件唤醒,直接接着执行 WFE 后的程序。停止模式唤醒后,STM32 会使用 HSI(f1 的 HSI 为 8M,f4 为 12M)作为系统时钟。所以,有必要在唤醒以后,在程序上重新配置系统时钟,将时钟切换回 HSE。

唤醒延迟 :基础延迟为 HSI 振荡器的启动时间,若调压器工作在低功耗模式,还需要加上调压器从低功耗切换至正常模式下的时间,若 FLASH 工作在掉电模式,还需要加上 FLASH 从掉电模式唤醒的时间。

待机模式

待机模式可实现系统的最低功耗。该模式是在Cortex-M3深睡眠模式时关闭电压调节器。整个1.8V供电区域被断电。PLLHSIHSE振荡器也被断电。SRAM和寄存器内容丢失。只有备份的寄存器和待机电路维持供电。

它除了关闭所有的时钟,还把 1.8V 区域的电源也完全关闭了,也就是说,从待机模式唤醒后,由于没有之前代码的运行记录,只能对芯片复位,重新检测 boot 条件,从头开始执行程序。

在待机模式下,所有的I/O引脚处于高阻态,除了以下的引脚:

● 复位引脚(始终有效)

● 当被设置为防侵入或校准输出时的TAMPER引脚

● 被使能的唤醒引脚

不同模式下唤醒方式对比

功耗越低的低功耗,其唤醒条件越严苛。

- 睡眠模式下,任一一个中断都是可以唤醒的(针对调用 WFI 命令进入的睡眠);


- 停止模式下,是任一一个外部中断才能唤醒,注意是任一外部中断,不是任一中断;


- 待机模式又有所不同,外部中断并不能唤醒待机模式,比较常见的唤醒有:

1.WKUP 引脚上升沿(按下 PA0,使之出现上升沿,只要 PA0 出现一个上升沿即可唤醒单片机,而不管这个上升沿持续多长时间,软件上只需要在进入待机模式之前,将 PA0 配置为唤醒功能即可);

2.NRST 引脚复位(即按下复位按键),这种方式是让单片机重新复位了,这是硬件上的唤醒;

3. 单片机系统重新上电,这跟第 2 点是一样的,都是硬件复位。

低功耗模式下的自动唤醒

低功耗模式下的自动唤醒(AWU)

RTC可以在不需要依赖外部中断的情况下唤醒低功耗模式下的微控制器(自动唤醒模式)RTC提供一个可编程的时间基数,用于周期性从停止或待机模式下唤醒。通过对备份区域控制寄存器(RCC_BDCR)的RTCSEL[1:0]位的编程,三个RTC时钟源中的二个时钟源可以选作实现此功能。

● 低功耗32.768kHz外部晶振(LSE)

该时钟源提供了一个低功耗且精确的时间基准。(在典型情形下消耗小于1µA)

● 低功耗内部RC振荡器(LSI RC)

使用该时钟源,节省了一个32.768kHz晶振的成本。但是RC振荡器将少许增加电源消耗。

为了用RTC闹钟事件将系统从停止模式下唤醒,必须进行如下操作:

● 配置外部中断线17为上升沿触发。

● 配置RTC使其可产生RTC闹钟事件。

如果要从待机模式中唤醒,不必配置外部中断线17

更高端的单片机比如F4有自动唤醒,而F1没有直接的自动唤醒,但可以通过RTC的闹钟事件来实现自动唤醒。

相关HAL函数 

 

stm32f1xx_hal_pwr.h

/** @addtogroup PWR_Exported_Functions_Group1 Initialization and de-initialization functions 
  * @{
  */

/* Initialization and de-initialization functions *******************************/
void HAL_PWR_DeInit(void);
void HAL_PWR_EnableBkUpAccess(void);
void HAL_PWR_DisableBkUpAccess(void);

/**
  * @}
  */

/** @addtogroup PWR_Exported_Functions_Group2 Peripheral Control functions 
  * @{
  */

/* Peripheral Control functions  ************************************************/
void HAL_PWR_ConfigPVD(PWR_PVDTypeDef *sConfigPVD);
/* #define HAL_PWR_ConfigPVD 12*/
void HAL_PWR_EnablePVD(void);
void HAL_PWR_DisablePVD(void);

/* WakeUp pins configuration functions ****************************************/
void HAL_PWR_EnableWakeUpPin(uint32_t WakeUpPinx);
void HAL_PWR_DisableWakeUpPin(uint32_t WakeUpPinx);

/* Low Power modes configuration functions ************************************/
void HAL_PWR_EnterSTOPMode(uint32_t Regulator, uint8_t STOPEntry);
void HAL_PWR_EnterSLEEPMode(uint32_t Regulator, uint8_t SLEEPEntry);
void HAL_PWR_EnterSTANDBYMode(void);

void HAL_PWR_EnableSleepOnExit(void);
void HAL_PWR_DisableSleepOnExit(void);
void HAL_PWR_EnableSEVOnPend(void);
void HAL_PWR_DisableSEVOnPend(void);



void HAL_PWR_PVD_IRQHandler(void);
void HAL_PWR_PVDCallback(void);

Regulator是电压调节器的选项;STOPEntry是关于用WFI还是WFE的选项。

关键代码

/* Includes ------------------------------------------------------------------*/
#include "MyApplication.h"

/* Private define-------------------------------------------------------------*/

/* Private variables----------------------------------------------------------*/

/* Private function prototypes------------------------------------------------*/  
static void Sleep_Mode(void);   //睡眠模式
static void Stop_Mode(void);    //停机模式
static void Standby_Mode(void); //待机模式

/* Public variables-----------------------------------------------------------*/
LowPowerConsumption_t LowPowerConsumption = 
{
	FALSE,
	FALSE,
	FALSE,
	
	Sleep_Mode,
	Stop_Mode,   
	Standby_Mode
};

/*
	* @name   Sleep_Mode
	* @brief  睡眠模式
	* @param  None
	* @retval None      
*/
static void Sleep_Mode(void)
{
	/***Note:任意中断都可以将系统从睡眠模式中唤醒***/
	
	//关闭Systick与定时器中断,否则,进入睡眠模式后立马被唤醒
	HAL_SuspendTick();
	HAL_TIM_Base_Stop_IT(&htim6);
	//关闭外部中断0至2,只允许触摸按键4中断退出睡眠模式
	HAL_NVIC_DisableIRQ(EXTI0_IRQn);
	HAL_NVIC_DisableIRQ(EXTI1_IRQn);
	HAL_NVIC_DisableIRQ(EXTI2_IRQn);
	
	HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON,PWR_SLEEPENTRY_WFI);
	
	//恢复中断
	HAL_ResumeTick();
	HAL_TIM_Base_Start_IT(&htim6);
	HAL_NVIC_EnableIRQ(EXTI0_IRQn);
	HAL_NVIC_EnableIRQ(EXTI1_IRQn);
	HAL_NVIC_EnableIRQ(EXTI2_IRQn);
}

/*
	* @name   Stop_Mode
	* @brief  停机模式
	* @param  None
	* @retval None      
*/
static void Stop_Mode(void)
{
		/***Note:外部中断可将系统从停机模式中唤醒***/

	//关闭外部中断0至2,只允许触摸按键4中断退出停机模式
	HAL_NVIC_DisableIRQ(EXTI0_IRQn);
	HAL_NVIC_DisableIRQ(EXTI1_IRQn);
	HAL_NVIC_DisableIRQ(EXTI2_IRQn);
	
	HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON,PWR_STOPENTRY_WFI);
	
	//退出停止模式时,HSI RC振荡器被选为系统时钟
	//系统时钟需要重新初始化
	SystemClock_Config();
	//恢复中断
	HAL_NVIC_EnableIRQ(EXTI0_IRQn);
	HAL_NVIC_EnableIRQ(EXTI1_IRQn);
	HAL_NVIC_EnableIRQ(EXTI2_IRQn);
}

/*
	* @name   Standby_Mode
	* @brief  待机模式
	* @param  None
	* @retval None      
*/
static void Standby_Mode(void)
{
	HAL_PWR_EnterSTANDBYMode();
}
/********************************************************
  End Of File
********************************************************/

 

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值