STM32学习笔记11-PWR电源控制

news2024/11/25 18:53:18

目录

PWR简介

电源框图

上电复位和掉电复位

可编程电压监测器

低功耗模式

模式选择

睡眠模式

停止模式

待机模式

低功耗模式应用

睡眠模式

停止模式

待机模式


PWR简介

  • PWR(Power Control)电源控制
  • PWR负责管理STM32内部的电源供电部分,可以实现可编程电压监测器和低功耗模式的功能
  • 可编程电压监测器(PVD)可以监控VDD电源电压,当VDD下降到PVD阀值以下或上升到PVD阀值之上时,PVD会触发中断,用于执行紧急关闭任务
  • 低功耗模式包括睡眠模式(Sleep)、停机模式(Stop)和待机模式(Standby),可在系统空闲时,降低STM32的功耗,延长设备使用时间

电源框图

上电复位和掉电复位

这个了解即可,这个意思是当VDD或者VDDA电压过低时内部电路直接产生复位,这个复位与不复位的界限之间设置了一个40mV的迟滞电压,大于上限POR时解除复位,小于下限PDR时复位。设置两个阈值就是防止电压在某个阈值附近波动时造成输出也来回抖动。下面的复位信号低电平有效。 

可编程电压监测器

了解即可,与上面差不多,都是监测VDD与VDDA的供电电压,PVD的区别就是首先它的阈值电压是可以使用程序指定的,PVD触发之后芯片还能正常工作,只不过电源电压过低该提醒一下用户了。电压过低为1,电压正常为0,是正逻辑。这个信号可以申请中断,在上升沿或者下降沿触发中断,提醒程序进行适当处理。中断申请通过外部中断实现。 

低功耗模式

首先睡眠模式,直接调用WFI或者WFE即可进入,这两个东西是内核的指令,对应库函数里有对应的函数,直接调用函数即可。其中WFI的意思是Wait For Interrupt等待中断,对应的唤醒条件是任一中断,调用WFI进入的睡眠模式任何外设发生任何中断,芯片都会立刻醒来。WFE意思是Wait For Event等待事件,对应的唤醒条件是唤醒事件,这个事件可以是外部中断配置为时间模式也可以是使能了中断但是没有配置NVIC,调用WFE进入的睡眠模式产生唤醒事件时就会立刻醒来。睡眠模式对电路的影响是只把CPU时钟关了,对其他电路没有任何操作,CPU时钟关了程序就会暂停,芯片功耗就会降低。

停机模式,如何进入呢?首先SLEEPDEEP位设置为1,告诉CPU你可以放心睡进入深度睡眠模式,另外PDDS这一位用来区分它是停机模式还是下面的待机模式,PDDS=0进入停机模式,PDDs=1进入待机模式,所以要进入停机模式PDDS要事先设置为0。LPDS用来设置最后这个电压调节器,是开启还是进入低功耗模式,LPDS=0电压调节器开启。这些位设置好最后再调用WFI或者WFE就可以进入停机模式了,然后停止模式唤醒是任一外部中断,前文睡眠模式是任一中断,选择停止模式要求就是只有外部中断才能唤醒了。对电路的影响是不仅CPU不能运行了,外设也运行不了,定时器正在定时的会暂停,串口收发数据也会暂停,不过由于没关闭电源,所以CPU和外设的寄存器数据都是维持原状的,HSI(内部高速时钟)和HSE(外部高速时钟)的振荡器关闭,LSI(内部低速时钟)和LSE(内部低速时钟)这两个并不会主动关闭,如果开启过这两个时钟还可以进行运行。 

待机模式,进入和停机模式差不多,首先SLEEPDEEP位也是设置为1,即深度睡眠,然后RDDS置1,表示即将进入待机模式,最后调用WFI或者WFE就可以进入待机模式了。唤醒条件普通外设的中断和外部中断都无法唤醒待机模式,待机模式只有这几个指定的信号才能唤醒,第一个是WKUP引脚上升沿,第二个是RTC闹钟事件,第三个是NRST引脚上的外部复位意思就是按一下复位按键它也是能唤醒的,最后一个IWDG独立看门狗复位。对电路的操作基本上是能关的都关了,内部存储器和寄存器的数据全部丢失,但是和停止模式一样不会主动关闭LSI和LSE两个低速时钟,因为这两个时钟还要维持RTC和独立看门狗运行。

模式选择

  • 执行WFIWait For Interrupt)或者WFEWait For Event)指令后,STM32进入低功耗模式

 

睡眠模式

  • 执行完WFI/WFE指令后,STM32进入睡眠模式,程序暂停运行,唤醒后程序从暂停的地方继续运行
  • SLEEPONEXIT位决定STM32执行完WFIWFE后,是立刻进入睡眠,还是等STM32从最低优先级的中断处理程序中退出时进入睡眠
  • 在睡眠模式下,所有的I/O引脚都保持它们在运行模式时的状态
  • WFI指令进入睡眠模式,可被任意一个NVIC响应的中断唤醒
  • WFE指令进入睡眠模式,可被唤醒事件唤醒

停止模式

  • 执行完WFI/WFE指令后,STM32进入停止模式,程序暂停运行,唤醒后程序从暂停的地方继续运行
  • 1.8V供电区域的所有时钟都被停止,PLLHSIHSE被禁止,SRAM和寄存器内容被保留下来
  • 在停止模式下,所有的I/O引脚都保持它们在运行模式时的状态
  • 当一个中断或唤醒事件导致退出停止模式时,HSI被选为系统时钟
  • 当电压调节器处于低功耗模式下,系统从停止模式退出时,会有一段额外的启动延时
  • WFI指令进入停止模式,可被任意一个EXTI中断唤醒
  • WFE指令进入停止模式,可被任意一个EXTI事件唤醒

待机模式

  • 执行完WFI/WFE指令后,STM32进入停止模式,程序暂停运行,唤醒后程序从暂停的地方继续运行
  • 1.8V供电区域的所有时钟都被停止,PLLHSIHSE被禁止,SRAM和寄存器内容被保留下来
  • 在停止模式下,所有的I/O引脚都保持它们在运行模式时的状态
  • 当一个中断或唤醒事件导致退出停止模式时,HSI被选为系统时钟
  • 当电压调节器处于低功耗模式下,系统从停止模式退出时,会有一段额外的启动延时
  • WFI指令进入停止模式,可被任意一个EXTI中断唤醒
  • WFE指令进入停止模式,可被任意一个EXTI事件唤醒

低功耗模式应用

睡眠模式

在串口发送+接收工程的基础上加入低功耗代码,串口发送+接收见:STM32学习笔记09-USART串口通信CSDN

假设要用STM32做一个下位机,下位机接收电脑串口发送过来的指令,然后执行相应的功能,电脑随时都可能通过串口发送指令,也可以很久的不发指令,为了随时能响应指令,STM32就得时刻准备着,比如原来的代码主循环就一直在不断检查标志位,但是一直不发指令这样就没啥意义还费电,当然你可能说把这段代码放中断就好了,但是即使主循环是空的它CPU也是在不断耗电的,所以对这种靠中断触发,没有中断的时候就没什么事的代码我们就可以给它加入低功耗模式。

我们只需要在main.c的while循环最后加上__WFI()即可:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"

uint8_t RxData;

int main(void)
{
	OLED_Init();
	Serial_Init();
	
	Serial_SendByte(0x41);

	uint8_t MyArray[] = {0x42,0x43,0x44,0x45};
	Serial_SendArray(MyArray, 4);//发送数组

	Serial_SendString("\r\nNum1=");//发送字符串

	Serial_SendNumber(111,3);//发送数字(十进制显示)

	printf("\r\nNum2=%d",222);//printf封装1

	char String[100];
	sprintf(String, "\r\nNum3=%d",333);//printf封装2
	Serial_SendString(String);
	
	Serial_Printf("\r\nNum4=%d",444);//printf封装3
	Serial_Printf("\r\n");
	
	OLED_ShowString(1, 1, "RxData:");
	while(1)
	{
		/* 查询方法 */
//		if (USART_GetFlagStatus(USART1,USART_FLAG_RXNE) == SET)
//		{
//			RxData = USART_ReceiveData(USART1);
//			OLED_ShowHexNum(1, 1, RxData, 2);
//		}
		if(Serial_GetRxFlag() == 1)//接收
		{
			RxData = Serial_GetRxData();
			Serial_SendByte(RxData);//数据回传,接收到的数据回传到电脑
			OLED_ShowHexNum(1, 8, RxData, 2);
		}
		
		OLED_ShowString(2, 1, "Runing");
		Delay_ms(100);
		OLED_ShowString(2, 1, "      ");
		Delay_ms(100);
		
		__WFI();
		
	}
}


执行流程是首先初始化把串口配置好,接着发送各个数据一次,进入主循环后,检查标志位,Running闪烁一次,主循环的最后执行WFI,这时候CPU就会立刻进入睡眠模式,程序停在WFI指令这里,这时CPU睡眠但是各个外设比如USART还在工作状态,等到我们用串口助手发送数据时USART外设收到数据产生中断唤醒CPU,睡眠模式唤醒之后程序在暂停的地方继续运行,唤醒之后中断立刻申请,再跳回while循环开头之前先进入USART中断函数,中断函数里读取数据、置RxFlag、清除RXNE,之后回到主循环,这时RxFlag刚刚置1所以if成立,执行数据回传和显示,唤醒的功能执行之后Runing闪烁一次,最后程序又来到WFI的位置,这是一个新的睡眠指令,CPU再次进入睡眠模式。

停止模式

停止模式只能通过外部中断触发唤醒,所以和停止模式相关的代码肯定得用外部中断。我们在对射式红外传感器计次的代码上进行:STM32学习笔记03-EXTI外部中断

下载程序要按住复位键,按下载,再松手复位键。

先看几个库函数:

void PWR_WakeUpPinCmd(FunctionalState NewState);//使能位于PA0位置的WKUP引脚,配合待机模式使用
void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry);//进入停止模式,调用这个函数就可以进入停止模式了
void PWR_EnterSTANDBYMode(void);//进入待机模式,调用这个函数就可以进入待机模式了

接下来我们加入停止模式的代码,首先要开启PWR时钟:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "CountSensor.h"

uint8_t Key_Num;

int main(void)
{
	OLED_Init();
	CountSensor_Init();
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//开启时钟
	
	OLED_ShowString(1,1,"count:");
	while(1)
	{
		OLED_ShowNum(1,7,Get_CountSensor_count(),5);
		
		OLED_ShowString(2, 1, "Runing");
		Delay_ms(100);
		OLED_ShowString(2, 1, "      ");
		Delay_ms(100);
		
		PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI);
		//退出停止模式时,HSI被选为系统时钟,也就是在我们首次复位后SystemInit函数里的配置是HSE*9的72MHz主频
		SystemInit();//进入停止模式再退出时默认时钟就变成HSI了,HSI是8M,所以我们退出停止模式后重新调用SystemInit配置72MHz主频
	}
	
}

 执行流程与上一个类似。

待机模式

我们在实时时钟代码上加入待机模式:STM32学习笔记10-RTC实时时钟

我们的主要任务就是,第一设置RTC闹钟,第二进入待机模式,第三使用闹钟信号唤醒待机模式。

首先精简一下main布局:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyRTC.h"

int main(void)
{
	OLED_Init();
	MyRTC_Init();
	
	OLED_ShowString(1, 1, "CNT :");
	OLED_ShowString(2, 1, "ALR :");
	OLED_ShowString(3, 1, "ALRF:");

	while(1)
	{

		OLED_ShowNum(1, 6,RTC_GetCounter(), 10);
	}
}

首先设定闹钟为10秒后,随着CNT增大,CNT会与ALR相等,然后触发闹钟标志位置1,如果开启了闹钟中断那还会进一步进入中断函数,这个代码我们就不开中断了,直接显示闹钟标志位,看看闹钟响的时候标志位会不会置1。

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyRTC.h"

int main(void)
{
	OLED_Init();
	MyRTC_Init();
	
	OLED_ShowString(1, 1, "CNT :");
	OLED_ShowString(2, 1, "ALR :");
	OLED_ShowString(3, 1, "ALRF:");
	
	uint32_t Alarm = RTC_GetCounter() + 10;//设定闹钟为10秒后
	RTC_SetAlarm(Alarm);
	OLED_ShowNum(2, 6, Alarm, 10);//闹钟显示
	
	while(1)
	{
		OLED_ShowNum(1, 6,RTC_GetCounter(), 10);
		OLED_ShowNum(3, 6,RTC_GetFlagStatus(RTC_FLAG_ALR), 1);//显示闹钟标志位
		
		OLED_ShowString(4, 1, "Runing");
		Delay_ms(100);
		OLED_ShowString(4, 1, "      ");
		Delay_ms(100);
	}
}

 接下来加入待机模式代码:

要进入待机模式,我们需要使用PWR外设,使用PWR外设之前要开启时钟。

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyRTC.h"

int main(void)
{
	OLED_Init();
	MyRTC_Init();
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//开启PWR时钟
	
	OLED_ShowString(1, 1, "CNT :");
	OLED_ShowString(2, 1, "ALR :");
	OLED_ShowString(3, 1, "ALRF:");
	
	uint32_t Alarm = RTC_GetCounter() + 10;//设定闹钟为10秒后
	RTC_SetAlarm(Alarm);
	OLED_ShowNum(2, 6, Alarm, 10);//闹钟显示
	
	while(1)
	{
		OLED_ShowNum(1, 6,RTC_GetCounter(), 10);
		OLED_ShowNum(3, 6,RTC_GetFlagStatus(RTC_FLAG_ALR), 1);//显示闹钟标志位
		
		OLED_ShowString(4, 1, "Runing");
		Delay_ms(100);
		OLED_ShowString(4, 1, "      ");
		Delay_ms(100);
		
		PWR_EnterSTANDBYMode();//进入待机模式
	}
}

经过实测,很多芯片唤醒后ALEF并不会置1,不必纠结能唤醒就没问题。每次唤醒闹钟值都重新设定,通过这一现象我们可以确定待机模式唤醒后程序是从头开始执行,因为我们闹钟设定的代码在while循环之前,如果不是从头开始那闹钟值也不会更新。在进入待机模式之后,高速时钟也都会关闭,在退出待机模式时,程序从头开始执行在程序刚开始的时候自动调用SystemInit初始化时钟,所以待机模式我们就不用像停止模式那样自己调用SystemInit了。

待机模式对标的是极度省电,光STM32自己一个省电那也不行,所以一般进入待机模式之前我们要尽可能把外挂模块都关掉,这个需要精心设计硬件电路,可以选一个带有使能端的稳压器实现或者自己设计电路把其他模块的供电加一个开关。程序我们就简单模拟一下,在进入待机模式之前OLED_Clear清屏一下。

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyRTC.h"

int main(void)
{
	OLED_Init();
	MyRTC_Init();
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//开启PWR时钟
	
	OLED_ShowString(1, 1, "CNT :");
	OLED_ShowString(2, 1, "ALR :");
	OLED_ShowString(3, 1, "ALRF:");
	
	uint32_t Alarm = RTC_GetCounter() + 10;//设定闹钟为10秒后
	RTC_SetAlarm(Alarm);
	OLED_ShowNum(2, 6, Alarm, 10);//闹钟显示
	
	while(1)
	{
		OLED_ShowNum(1, 6,RTC_GetCounter(), 10);
		OLED_ShowNum(3, 6,RTC_GetFlagStatus(RTC_FLAG_ALR), 1);//显示闹钟标志位
		
		OLED_ShowString(4, 1, "Runing");
		Delay_ms(100);
		OLED_ShowString(4, 1, "      ");
		Delay_ms(100);
		
		OLED_ShowString(4, 9, "STANDBY");//待机模式提示信息
		Delay_ms(1000);
		OLED_ShowString(4, 9, "       ");
		Delay_ms(1000);
		
		OLED_Clear();//清屏模拟OLED关电
		
		PWR_EnterSTANDBYMode();//进入待机模式
	}
}

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

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

相关文章

Unity新输入系统结构概览

本文仅作笔记学习和分享,不用做任何商业用途 本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正 在学习新输入系统之前,我们需要对其构成有个印象 1.输入动作(Inputaction) 是定义输…

队列---学生信息输入输出

作业:链栈,自己实现一遍,但是节点存储不是整数,存储学生信息(年龄,分数,姓名)三级引用。 1、建立学生信息结构体,将data改为学生信息结构体类型。 2、循环入栈和入队。…

RPC 和 HTTP 理解

网上充斥着各类类似于这样的文章:rpc 比 http 快了多少倍?既然有了 http,为什么还要用 rpc 调用等等。遇到这类文章,说明对 http 和 rpc 是由理解误区的。 这里再次重复强调一遍,通信协议不是 rpc 最重要的部分&#x…

KubeSphere 部署 Kafka 集群实战指南

本文档将详细阐述如何利用 Helm 这一强大的工具,快速而高效地在 K8s 集群上安装并配置一个 Kafka 集群。 实战服务器配置(架构 1:1 复刻小规模生产环境,配置略有不同) 主机名IPCPU内存系统盘数据盘用途ksp-registry192.168.9.904840200Harbor 镜像仓库…

命令行参数环境变量

目录 前言: 命令行参数: 现象: 这些参数的意义: 为什么要这么做? 这些事是谁做的呢? 环境变量 现象: 创建环境变量: 结合程序理解: 前言: 我们在前…

R语言里认识机器学习

下面内容摘录自: 1章2节:关于人工智能、机器学习、统计学连和机器学习、R 与 ChatGPT 的探究-CSDN博客文章浏览阅读1k次。在现代科技发展的浪潮中,人工智能(AI)、机器学习(ML)、统计学、R 编程…

网络通信(TCP/UDP协议 三次握手四次挥手 )

三、TCP协议与UDP协议 1、TCP/IP、TCP、 UDP是什么 TCP/IP协议是一个协议簇,里面包括很多协议的, UDP只是其中的一个, 之所以命名为TCP/IP协议, 因为TCP、 IP协议是两个很重要的协议,就用他两命名了,而TCP…

告别知云单一选择,这些文献翻译工具同样值得信赖!

在翻译领域,知云文献翻译以其专业度和便捷性赢得了众多用户的青睐,但市场上还有许多其他翻译工具同样值得关注。本文将为您推荐几款优秀的翻译工具。 Foxit在线翻译 链接: https://fanyi.pdf365.cn/ Foxit在线翻译以其高效的翻译速度和准…

创建第一个Qt项目

创建第一个QT项目 创建工程名称一般不要有特殊符号,不要有中文 项目工程保存路径可修改,路径不要带中文 Base class中的三个选项 QMainWindow:主窗口类,包括菜单栏、工具栏、状态栏。 QWidget:可以创建一个空白的窗口,是所有界…

嵌入式软件--数据结构与算法 DAY 13

在嵌入式中,对算法的要求不高,但顺序查找和冒泡排序是经典算法,必须掌握。 1.算法定义 算法是一个用于解决特定问题的有限指令序列(计算机可以执行的操作)。通俗的理解就是可以解决特定问题的方法。 2.时间复杂度 …

手动和torch.nn实现卷积神经网络、空洞卷积、残差网络

一、数据集 1. 分类问题 数据集——车辆分类数据 ⚫输入图片,输出对应的类别 ⚫共1358张车辆图片 ⚫分别属于汽车、客车和货车三类 ⚫汽车:779张 ⚫客车:218张 ⚫货车:360张 ⚫每个类别随机取20-30%当作测试集 ⚫各图片的大小不一,需要将图片拉伸到相同大小 汽车 …

three.js 安装方法、基础简介、创建基础场景

threejs简介 Three.js是一个基于JavaScript编写的开源3D图形库,‌利用WebGL技术在网页上渲染3D图形。‌ 它提供了许多高级功能,‌如几何体、‌纹理、‌光照、‌阴影等,‌使得开发者能够快速创建复杂且逼真的3D场景。‌ threejs提供了丰富的功…

云原生日志Loki

1. Loki简介 1.1 Loki介绍 Loki是 Grafana Labs 团队最新的开源项目,是一个水平可扩展,高可用性,多租户的日志聚合系统。它的设计非常经济高效且易于操作,因为它不会为日志内容编制索引,而是为每个日志流编制一组标签…

关于Vue项目npm快捷键,点击run启动报错,及npm i也报错的解决办法

1.配置idea的npm 2.点击运行按钮 3.结果 分析原因及问题: npm i npm run dev 由于是刚刚从gitlab新拉的前端代码,可能没有用命令install过类似于没有编译过,所以执行一下上面的命令 结果报错如下: F:\tbyf\qjyy\hip-manager-ui&…

SpringBoot整合MyBatis-Plus完整详细版(提供Gitee源码)

前言:本篇文章完整详细介绍了SpringBoot整合MyBatis-Plus的完整过程,这边我的SpringBoot版本是2.4版本、JDK1.8和Maven3.8.1版本,跟着文章一步步走就可以了,MyBatis-Plus整合非常方便,也是现在企业开发中经常会用的一个…

学习笔记第二十四天

1.exec族函数的区别 int exec l(const char *path, const char *arg, ...); int exec l p(const char *file, const char *arg, ...); int exec l e(const char *path, const char *arg,..., char * const envp[]); int exec v(const char *path, char *const argv[]); …

1011 World Cup Betting

题目 解释 题目讲的就是,给你三行数,每一行包含3个浮点小数,让你找到最大的那个小数,然后如果最后的小数是第一个,输出W,是第二个,输出T,是第三个,输出L,最后…

Day37 | 188.买卖股票的最佳时机IV 309.最佳买卖股票时机含冷冻期 714.买卖股票的最佳时机含手续费

语言 Java 188.买卖股票的最佳时机IV 买卖股票的最佳时机IV 题目 给你一个整数数组 prices 和一个整数 k ,其中 prices[i] 是某支给定的股票在第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。也就是说,你最多…

Broken: Gallery靶机复现

靶机设置 靶机设置为NAT模式 靶机IP发现 nmap 192.168.112.0/24 靶机IP为192.168.112.142 目录扫描 dirsearch 192.168.112.142 访问浏览器 发现文件页面 查看后发现都没什么用 getshell hydra -L rockyou.txt -P rockyou.txt 192.168.112.142 ssh 尝试爆破ssh账号密码…

互联网应用主流框架整合【Redis常用技术】

和其他大部分NoSQL不同,Redis是支持事务的,尽管没有数据库那么强大,但非常有用,在某些高并发但又要保证高度一致性的场景下,代替数据库事务非常有效;在Redis的机制中,允许通过流水线一次性发给R…