STM32F4_待机唤醒详解

news2024/10/6 10:31:48

目录

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/512994.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

‘OpenpyxlWriter‘ object has no attribute ‘save‘

使用read_sql(sql,conn)来获取数据库查询的结果, 在将处理完成的表格保存下来时,可能会显示如下错误: 将writer.save()改成writer._save()就可以解决这个问题了。

必须了解的mysql三大日志-binlog、redo log和undo log

目录 一,前言二,binlog-备份日志1,作用2,使用场景3,日志形式4,binlog刷盘时机 三,redo log-重做日志1,概念2,为什么需要redo log3,日志形式4,redo…

数据结构之树(一)

一.概念 边:一棵n个结点树有n-1条边 结点深度:从根到当前结点的路径的深度。 结点高度:从当前结点到叶子结点最长路径的长度。 树的性质 树中的结点总数等于所有结点的度1;m叉树中第i(i>1)层上至多可以有m^(i-1)个节点; 高…

互联网大厂手把手教你搭建数据服务中台(附下载链接)

摘要: 随着公司业务的发展,对于数据的需求会越来越多。怎么在业务系统中高效的使用数据,让业务系统处理大数据时化繁为简,数据服务化基本是必经之路。那么什么是数据服务化,简单理解就是数据SaaS,通过一些数据库语言把…

true or false?

有同学在星球问了这样一个问题。 代码是这样的: public class Main {private static final Main instance new Main();private boolean b a;private static boolean a initA();private static boolean c a;private static boolean initA() {return true;}priva…

洛谷B2099 矩阵交换行

矩阵交换行 题目描述 给定一个 5 5 5 \times 5 55 的矩阵(数学上,一个 r c r \times c rc 的矩阵是一个由 r r r 行 c c c 列元素排列成的矩形阵列),将第 n n n 行和第 m m m 行交换,输出交换后的结果。 输入格式 输入共 6 6 6 …

DataEase 本地源码启动详细教程

本教程将引导你通过本地源码部署的方式启动 DataEase,同时我还录制了相应的视频教程,你可以跟随视频进行操作: DataEase 本地源码启动_哔哩哔哩_bilibili 1、下载并安装IDEA开发工具 2、下载安装Mysql 5.7 以及 JDK 1.8 如果你使用的是wi…

使用pdf.js展示pdf文件(亲测可用)

简单的实现方式 如果只是电脑端,可通过 iframe 标签嵌套预览 ios手机端可通过 a 标签包裹点击跳转预览(安卓端不行) 安卓电脑ios的通用方法 资料 老版本github地址 全版本地址 获取当前客户端类型 judgeClient() {let client if (/(iPh…

鲁大师智能化评测新项目——鲁大师真续航测试1.0正式发布

随着社会的高速发展,人们出行的交通工具正变得多种多样,有电单车、摩托车、自行车、两轮平衡车、甚至滑板等。不过如我们所见,电动两轮车已经成为了大多数近途出行用户的选择,因电单车具有方便、快捷、灵活、小巧、易停放等优点而…

MySQL基础篇4

MySQL基础 1. 数据类型1.1 整数类型1.2 浮点类型1.3 定点数类型1.4 位类型1.5 日期时间类型1.6 文本字符串类型1.6.1 CHAR类型和VARCHAR类型1.6.2 TEXT类型 1.7 ENUM枚举类型1.8 SET类型1.9 二进制字符串类型1.10 JSON数据类型 2. 约束2.1 前置知识2.1.1 为什么需要约束2.1.2 约…

亚马逊云科技围绕需求发力,赋能医疗与生命科学行业数字化创新

2023年4月27日,亚马逊云科技医疗与生命科学行业峰会召开,会议汇聚了业界专家和思想领袖,共同探讨行业数字化转型和创新之道。作为全球医疗及生命科学行业云计算引领者,亚马逊云科技将围绕数据、算力和行业用户体验三大需求发力&am…

移远“5G+Wi-Fi 6”方案双重加速,为用户带来更具性价比的连网体验

近年来,人们对于高速宽带连接的需求猛增,这对网络传输速率、稳定性与时延都提出了更高的要求。在离开网络寸步难行的今天,插电即用、免拉宽带的5G CPE受到了广泛关注。 在地广人稀的部分海外市场,受制于光纤铺设成本、周期、路由规…

Day966.从组件团队到Spotify模型 -遗留系统现代化实战

从组件团队到Spotify模型 Hi,我是阿昌,今天学习记录的是关于从组件团队到Spotify模型的内容。 团队结构现代化。这个方向跟管理有关,但无论掌控全局的 CTO、架构师,还是身处遗留系统一线战队的队员,都有必要了解现代…

JavaScript - 基础+WebAPI(笔记)

前言: 求关注😭 本篇文章主要记录以下几部分: 基础: 输入输出语法;数据类型;运算符;流程控制 - 分支语句;流程控制 - 循环语句;数组 - 基础;函数 - 基础&…

idm下载器2024官方最新中文版免费下载

哈喽大家好呀,coco玛奇朵发现我已经有一阵子没有给大家分享windows软件了,今天给大家分享一款暗藏惊喜的windows软件,用过之后真的很难拒绝! 这是一个可以帮你提升下载速度的工具,有了它几秒就能帮你下载好各种资源。…

UNIAPP实战项目笔记64 当前用户修改收货地址的前端和后端

UNIAPP实战项目笔记64 当前用户修改收货地址的前端和后端 思路 默认地址的修改,先清空当前id下的所有默认地址,再将新地址设为默认 前端 将新值传给后端 后端接受值后更新处理 实例截图 代码 后端 index.js var express require(express); var route…

大数据Doris(十六):分桶Bucket和分区、分桶数量和数据量的建议

文章目录 分桶Bucket和分区、分桶数量和数据量的建议 一、分桶Bucket

机器学习随记(6)—K-means

1 K-means方案 K-means 算法是一种自动将相似数据点聚集在一起的方法。 具体来说,你得到了一个训练集{,...,},并且您希望将数据分组为几个有凝聚力的“集群”。 K-means 是一个迭代过程 首先猜测初始质心,然后改进这个猜测 反复将样本分配到…

Seurat -- Cluster the cells --第一部分

文章目录 briefKNN(k-nearest neighbor)简介部分SNN(shared nearest neighbor)简介部分Annoy算法理解Jaccard indexSeurat进行聚类的步骤可视化部分subcluster之间的marker gene具体参数 brief seurat 官方教程的解释如下&#x…

Hash碰撞

Hash碰撞 什么是Hash碰撞 Hash碰撞是指两个不同的输入值,经过哈希函数的处理后,得到相同的输出值,这种情况被称之为哈希碰撞。 例如:两个不同的对象(object1和object2的值)经过Hash函数计算后的&#xf…