STM32F4_待机唤醒详解

本文详细介绍了STM32单片机的低功耗模式,包括降低系统时钟速度、外设时钟门控,以及睡眠、停止和待机模式的进入和退出。在睡眠模式中,CPU停止而外设继续运行;停止模式下,所有时钟停止,1.2V域断电;待机模式则是最低功耗,1.2V域完全断电。文章还提到了唤醒事件和中断在不同模式下的作用,以及如何配置库函数进入待机模式。
摘要由CSDN通过智能技术生成

目录

1. 低功耗模式

1.1 降低系统时钟速度

1.2 外设时钟门控

2. 睡眠模式

2.1 进入睡眠模式

2.2 退出休眠模式

3. 停止模式

3.1 进入停止模式

3.2 退出停止模式

4. 待机模式

4.1 进入待机模式

4.2 退出待机模式

4.3 电源控制寄存器:PWR_CR

4.4 电源控制/状态寄存器:PWR_CSR

5. 库函数配置进入待机模式

6. 实验程序


        在学习STM32待机唤醒功能之前,我们首先来系统的学习32单片机的低功耗模式,这将对于我们理解睡眠/停止/待机模式有很大的帮助。

1. 低功耗模式

        默认情况下,系统复位或者上电复位后,MCU微控制器进入运行模式。在运行模式下,CPU通过HCLK提供时钟,并且执行程序代码。系统提供了多个低功耗模式,可在CPU不需要运行时(例如等待外部事件时)节省功耗。由用户根据应用选择具体的低功耗模式,以在低功耗、短启动时间和可用唤醒源之间寻求最佳平衡。

STM32有三种低功耗模式

  • 睡眠模式(Cortex -M4F内核停止,外设保持运行)
  • 停止模式(所有时钟都停止)
  • 待机模式(1.2V域断电)

此外,还可以通过其他方式降低功耗:

        1. 降低系统时钟速度

        2. 不使用APBx和AHBx外设时,将对应的外设时钟关闭

其中:嵌入式线性调压器为备份域和待机电路以外的所有数字电路供电。调压器输出电压约为1.2V。

1.1 降低系统时钟速度

        在运行模式下,可以通过对预分频寄存器编程来降低系统时钟(SYSCLK、HCLK、PCLK1和PCLK2)速度。进入睡眠模式之前,也可以使用这些预分频器降低外设速度。

1.2 外设时钟门控

        在运行模式下,可以随时的停止各个外设和存储器的HCLKx和PCLKx以降低功耗。要进一步的降低睡眠模式的功耗,可在执行WFI或者WFE指令之前禁止外设时钟。

        外设时钟门控由AHB1外设时钟使能寄存器RCC_AHB1ENR、AHB2外设时钟使能寄存器RCC_AHB2ENR和AHB3外设时钟使能寄存器RCC_AHB3ENR进行控制。

        在睡眠模式下,复位RCC_AHBxLPENR和RCC_APBxLPENR寄存器中的对应位可以自动禁止外设时钟。

2. 睡眠模式

2.1 进入睡眠模式

        执行WFI(等待中断)或者WFE(等待事件)指令即可进入睡眠模式。根据M4F内核系统控制寄存器中的SLEEPONEXIT位的设置,可以通过两种方案选择睡眠模式进入机制。

立即休眠:如果SLEEPONEXIT位清零,MCU将在执行WFI和WFE指令时立即进入睡眠模式。

退出时休眠:如果SLEEPONEXIT位置1,MCU将在退出优先级最低的ISR时立即进入睡眠模式。(ISR的全称是Interrupt Service Routines,也就是中断服务,中断是有NVIC中断优先级的,这里的意思就是当执行完中断中优先级最低的中断以后进入休眠)

2.2 退出休眠模式

因为进入睡眠模式是由指令WFI和指令WFE控制的。所以退出休眠模式也应该从这两方面入手。

如果使用WFI指令进入睡眠模式,则通过中断控制器NVIC确认的任意外设中断都会将器件从睡眠模式唤醒。

如果使用WFE指令进入睡眠模式,MCU将在有事件发生时立即退出睡眠模式。

唤醒事件可以通过以下方式产生:

        在外设的控制寄存器使能一个中断,但不在NVIC中使能,同时使能M4F内核系统控制寄存器中的SEVONPEND位。当MCU从WFE恢复时,需要清除相应外设的中断挂起位和外设NVIC中断通道挂起位(在NVIC中断清除挂起寄存器中)。

        配置一个外部或者内部EXTI线为事件模式。当CPU从WFE恢复时,因为对应事件线的挂起位没有被置位,不必清除相应外设的中断挂起位或NVIC中断通道挂起位。

3. 停止模式

        停止模式基于M4内核深度睡眠模式与外设时钟门控。调压器既可以配置为正常模式,也可以配置为低功耗模式。在停止模式下,1.2V域中的所有时钟都会停止,PLL、HSI和HSE RC振荡器也会被禁止。内部SRAM和寄存器内容将会被保留。

        将PWR_CR电源控制寄存器中的FPDS位置1后,Flash闪存还会在器件进入停止模式时进入掉电状态。Flash处于掉电模式时,将器件从停止模式唤醒将需要额外的启动延时。

3.1 进入停止模式

要进一步降低停止模式的功耗,可将内部调压器设置为低功耗模式。通过对STM32F4的PWR电源控制寄存器(PWR_CR)的LPDS位进行配置

如果正在进行Flash编程,停止模式的进入将延迟到存储器访问结束后执行。

如果正在访问APB域,停止模式的进入则延迟到APB访问结束后执行。

在停止模式下,可以通过对各个控制位进行编程来选择以下功能:

        独立看门狗IWDG:IWDG通过写入其密钥寄存器或使用硬件选项来启动。而且一旦启动便无法停止,除非复位。

        实时时钟RTC:通过RCC备份域控制寄存器RCC_BDCR中的RTCEN位进行配置。

        内部RC振荡器(LSI RC):通过RCC时钟控制和状态寄存器(RCC_CSR)中的LSION位进行配置。

        外部32.768KHz振荡器(LSE OSC):通过RCC备份域控制寄存器RCC_BDCR中的LSEON位进行配置。

在停止模式下,ADC和DAC也会产生功耗,除非在进入停止模式前将其禁止。要禁用这些转换器,必须将ADC_CR2寄存器的ADON位和DAC_CR寄存器中的ENx位都清零。

3.2 退出停止模式

通过发出中断或者唤醒事件退出停止模式时,将选择HSI RC振荡器作为系统时钟。

4. 待机模式

        待机模式下可达到最低功耗。待机模式基于M4内核深度睡眠模式,该模式在深度睡眠模式时关闭电压调节器。因此1.2V域断电。PLL、HSI振荡器也将关闭。除备份域(RTC寄存器、RTC备份寄存器和备份SRAM)和待机电路中的寄存器外,SRAM和寄存器内容都将丢失。

4.1 进入待机模式

在待机模式下,可以通过对各控制位进行编程来选择以下功能:

●独立的看门狗 (IWDG):IWDG 通过写入其密钥寄存器或使用硬件选项来启动。而且一 旦启动便无法停止,除非复位。

●实时时钟 (RTC):通过备份域控制寄存器 (RCC_BDCR) 中的 RTCEN 位进行配置。

●内部 RC 振荡器 (LSI RC):通过控制/状态寄存器 (RCC_CSR) 中的 LSION 位进行配置。

●外部 32.768 kHz 振荡器 (LSE OSC):通过备份域控制寄存器 (RCC_BDCR) 中的 LSEON 位进行配置。

4.2 退出待机模式

        检测到外部复位(NRST引脚)、IWDG引脚、WKUP引脚上升沿、RTC闹钟、入侵事件或时间戳事件时,微控制器退出待机模式。从待机模式唤醒后,除PWR电源控制/状态寄存器PWR_CSR外,所有寄存器都将复位。

        从待机模式唤醒后,程序将按照复位(启动引脚采样、复位向量已获取等)后的方式重新执行。PWR电源控制/状态寄存器PWR_CSR中的SBF状态标志指示MCU已处于待机模式。

        从待机模式唤醒后的代码执行等同于复位后的执行(采样启动模式引脚,读取复位向量等)。电源控制/状态寄存器PER_CSR将会指示内核由待机状态退出。意思就是说从待机模式退出后等同于按下开发板上的复位键,执行相对于的代码。

        在进入待机模式后,除了复位引脚、RTC_AF1引脚(PC13)(如果针对入侵、时间戳、RTC闹钟输出或RTC时钟校准输出进行了配置)和WK_UP(PA0)(如果使能了)等引脚外,其他所有IO引脚都将处于高阻态。

        总结:在这三种低功耗模式中,最低功耗的是待机模式,在此模式下,最低只需要2.2uA左右的电流。停机模式是次低功耗的,其典型的电流消耗在350uA左右。最后就是睡眠模式了。

4.3 电源控制寄存器:PWR_CR

通过对进入待机模式的学习,我们已经清楚了需要将电源控制寄存器PWR_CR的 位1 和 位2 置1,使器件在CPU进入深度睡眠时进入待机模式,并且将WUF唤醒标志清零。

4.4 电源控制/状态寄存器:PWR_CSR

这里我们需要 位8 置1,从待机模式中唤醒器件;也可以通过位0来检测是否收到了唤醒标志。

5. 库函数配置进入待机模式

首先注意:对于已经使能了RTC中断或者RTC唤醒中断的情况,必须先禁止中断,清除相关中断标志位,清除唤醒中断WK_UP,等一切都完成以后,再次使能中断,进入低功耗模式。具体如下:

1. 禁止RTC中断(ALRAIE、ALRBIE闹钟A和B、WUTIE、TAMPIE和TSIE等)

2. 清零对应中断标志位

3. 清除PWR唤醒(WUF)标志(通过设置PWR_CR的CWUF位实现)

4. 重新使能RTC对应中断

5. 进入低功耗模式

1. 使能电源时钟

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);     //使能PWR外设时钟

2. 设置WK_UP(也就是PA0引脚,KEY_UP按键)引脚作为唤醒源

PWR_WakeUpPinCmd(ENABLE);            //使能KEY_UP按键唤醒功能 ,用KEY_UP将CPU从待机模式唤醒

3. 设置SLEERDEEP(深度睡眠)位,设置PDDS位,执行WFI指令,进入待机模式

进入待机模式,首先设置SLEEPDEEP位,接着通过PWR_CR设置PDDS位,使得CPU进入深度睡眠时进入待机模式,最后执行WFI指令开始进入待机模式,并等待WK_UP(KEY_UP)中断的到来;

void PWR_EnterSTANDBYMode(void); //进入待机模式

4. 编写WK_UP中断函数

通过WK_UP中断(PA0中断)来唤醒CPU,同时通过该函数进入待机模式。

6. 实验程序

        该实验程序实现功能:长按3秒KEY_UP按键开机,通过LED0指示灯指示程序开始运行,再次长按按键,进入待机模式,LED0关闭,程序停止运行。类似于手机开关机。

6.1 main.c

#include "stm32f4xx.h"
#include "delay.h"
#include "usart.h"
#include "LED.h"
#include "lcd.h"
#include "usmart.h"
#include "Key.h"
#include "WKUP.h"

//LCD状态设置函数
void led_set(u8 sta)//只要工程目录下有usmart调试函数,主函数就必须调用这两个函数
{
	LED1=sta;
}
//函数参数调用测试函数
void test_fun(void(*ledset)(u8),u8 sta)
{
	led_set(sta);
}

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统分组中断优先级2
	delay_init(168);
	uart_init(115200);//这里切记先初始化串口,否则无法显示实验现象
	LED_Init();
	LCD_Init();
	WKUP_Init();
	POINT_COLOR=RED;
	LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");
	LCD_ShowString(30,70,200,16,16,"WKUP Test");
	LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
	LCD_ShowString(30,110,200,16,16,"2023/20/23");
	LCD_ShowString(30,130,200,16,16,"WK_UP:Standby/WK_UP");
	while(1)
	{
		LED0=!LED0;
		delay_ms(250);
	}
}


6.2 WKUP.c

#include "stm32f4xx.h"                 
#include "WKUP.h"
#include "Key.h"
#include "LED.h"
#include "delay.h"

//系统进入待机模式
void Sys_Enter_Standby(void)
{
	while(WKUP_KD);//while循环内设置为空,等待KEY_UP按键松开,跳过while循环
	
	RCC_AHB1PeriphResetCmd(0x04FF,ENABLE);//复位所有IO口
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//使能PWR电源时钟
	
	PWR_BackupAccessCmd(ENABLE);//使能后备域寄存器,RTC实时时钟中介绍过该寄存器
	
	RTC_ITConfig(RTC_IT_ALRB|RTC_IT_ALRA|RTC_IT_TS|RTC_IT_WUT,DISABLE);//禁止RTC相关中断,这些中断可能在RTC实验中开启了
	RTC_ClearITPendingBit(RTC_IT_ALRB|RTC_IT_ALRA|RTC_IT_TS|RTC_IT_WUT);//清除相关中断标志位
	
	PWR_ClearFlag(PWR_FLAG_WU);//清除Wake_up唤醒标志
	
	PWR_WakeUpPinCmd(ENABLE);//使能KEY_UP按键唤醒功能 ,用KEY_UP将CPU从待机模式唤醒
	
	PWR_EnterSTANDBYMode();//进入待机模式
}
//检测WKUP脚的信号
//返回值1:连续按下3s以上
//	    0:错误的触发
u8 Check_WKUP(void)
{
	u8 t=0;//记录时间
	u8 tx=0;//记录松开的次数
	LED0=0;//LED0点亮
	while(1)
	{
		if(WKUP_KD)//KEY_UP按键按下
		{
			t++; //记录KEY_UP按键按下的时间,需要去判断这个时间的长短,就跟我们的手机关机一样,不会只是按一下电源键就关机了,需要按下保持一段时间
			tx=0; //只要进入if循环语句,那么按键就一直被按下,所以松开次数始终都是零
		}
		else   //松开KEY_UP
		{
			tx++;//松开的次数++
			if(tx>3)//如果松开的次数大于3,超过90s内没有WKUP信号
			{
				LED0=1; //LED0熄灭
				return 0;//错误按键,返回
                //这里的错误的意思是:还是我们手机关机的例子,假设需要长按电源键5秒关机,如果我们在5秒内频繁的松开按键,就一定不会关机了;直接一点,松开一次按键就不会关机了
                //也就表示用户取消了关机,return 0;
			}
		}
		delay_ms(30);
		if(t>=100)//按下超过3秒钟  表示按键超过了预设的时间,那么进入待机模式
		{
			LED0=0; 
			return 1;//按键3s以上了,进入待机模式
		}
	}
}
//中断,检测到PA0脚上的一个上升沿
//中断线0上的中断检测
void EXTI0_IRQHandler(void)
{
	EXTI_ClearITPendingBit(EXTI_Line0);//清除LINE0上的中断标志位
	if(Check_WKUP())//表示检测3秒以上的函数返回值为1
	{
		Sys_Enter_Standby();//进入待机模式
	}
}
//PA0 KEY_UP 唤醒中断初始化
void WKUP_Init(void)
{
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//使能GPIOA时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);//使能SYSCFG时钟
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN;//按键的模式是输入
	GPIO_InitStructure.GPIO_OType=GPIO_OType_OD;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_DOWN;//按键KEY_UP下拉
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	if(Check_WKUP()==0) //也是和我们手机开机一样,手机开机也是需要长按电源键,如果在长按电源键的期间,频繁的松开电源键,此时手机是开不开机的;
//开发板也是这样,初始化时先检测如果是非正常开机,那么直接进入待机模式
	{
		Sys_Enter_Standby();//不是正常的开机,进入待机模式
	}
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);//PA0连接到中断线0
	
	EXTI_InitTypeDef EXTI_InitStructure;
	EXTI_InitStructure.EXTI_Line=EXTI_Line0;
	EXTI_InitStructure.EXTI_LineCmd=ENABLE;
	EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;//上升沿触发
	EXTI_Init(&EXTI_InitStructure);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQn;//外部中断0
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x02;
	NVIC_Init(&NVIC_InitStructure);
}


6.3 WKUP.h

#ifndef _WKUP__H_
#define _WKUP__H_

#define WKUP_KD PAin(0)
void Sys_Enter_Standby(void);
u8 Check_WKUP(void);
void EXTI0_IRQHandler(void);
void WKUP_Init(void);

#endif

  • 7
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1设计要求 要求系统按如下方式进入和退出睡眠模式: 在系统启动2秒后,将RTC在3秒钟之后配置为产生一个报警事件,接着通过WFI指令使系统进入停机模式。 如果要唤醒系统到正常模式,可通过按Key按钮;否则,在3秒钟后,会产生RTC报警中断自动将系统唤醒。 一旦退出停机模式,系统时钟被配置成先前的状态(在停机模式下,外部高速振荡器HSE和PLL是不可用的)。 经过一段延时之后,系统将再次进入停机状态,并可按上述操作无限重复。 2 硬件电路设计 硬件电路采用与7.1小节应用实例一样硬件电路,可见图7-10。其中Key按钮用于通过PB9产生一个外部中断, LED1、LED2、LED3、LED4则用于显示处理器所处的模式和中断触发情况。 3 软件程序设计 根据任务要求,程序内容主要包括: (1) 配置GPIOB口,配置RTC,配置外部中断; (2) 配置PB口第9个引脚作为外部中断,下降延触发;配置RTC报警中断,上升沿触发; (3) 两个中断服务子程序的内容分别是:切换LED2和LED3灯的状态; 整个工程包含3个源文件:STM32F10x.s、stm32f10x_it.c和main.c,其中STM32F10x.s为启动代码,所有中断 服务子程序均在stm32f10x_it.c中,其它函数则在main.c中。下面分别介绍相关的函数,具体程序清单见参考程序。 函数SYSCLKConfig_STOP用于当处理器从停机模式唤醒之后,配置系统时钟、使能HSE和PLL,并以PLL作为系统时钟源。当处理器处理停机模式的时候,HSE、PLL是不可用的。 函数GPIO_Configuration用于配置GPIO的PC6、PC7、PC8、PC9和PB9。 函数EXTI_Configuration用于配置外部中断线9(PB9)和17(RTC报警)。 函数NVIC_Configuration配置NVIC及中断向量表,这里主要是配置外部中断线9和17。 函数EXTI9_5_IRQHandler处理按钮Key(PB9)所触发的中断,其主要作用是将LED2灯的状态翻转一次。 函数RTCAlarm_IRQHandler处理RTC报警所触发的中断,其主要作用事将LED3 灯的状态翻转一次,如果设置了唤醒标志则清除之。 运行过程: (1) 使用Keil uVision3 通过ULINK 2仿真器连接EduKit-M3实验平台,打开实验例程目录PWR_TEST子目录下的PWR.Uv2 例程,编译链接工程; (2) 选择软件调试模式,点击MDK 的Debug菜单,选择Start/Stop Debug Session项或Ctrl+F5键,在逻 辑分析仪中添加GPIOC_ODR.6、GPIOC_ODR.7、GPIOC_ODR.8、GPIOC_ODR.9,点击Run按钮即可在逻辑分析 仪中看到如图7-14,还可用Peripherals-General Port-GPIOB来模拟KEY按钮的动作; (3) 选择硬件调试模式,选择Start/Stop Debug Session项或Ctrl+F5键,下载程序并运行,观察LED灯 的变化情况。注意,当目标系统进入停机模式之后,将无法使用仿真器进行调试了; (4) 退出Debug模式,打开Flash菜单>Download,将程序下载到EduKit-M3实验平台的Flash中,按RESET键复位,观察 LED灯的情况,正常情况应为:系统处于运行模式时LED1亮、LED4灭;系统处于停机状态时LED1灭、LED4亮; 当按下KEY按钮时LED2灯状态发生反转;当发生RTC报警时LED3状态发生反转。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值