当前位置: 首页 > news >正文

【STM32 学习笔记】PWR电源控制

在电子设备中,待机(Standby)和睡眠(Sleep)是两种不同的省电模式。 1. 待机模式(Standby Mode):在待机模式下,设备仍然保持一定程度的活动,但大部分功能处于暂停状态。在这里插入图片描述

电源

STM32的工作电压(VDD)为2.0~3.6V。通过内置的电压调节器提供所需的1.8V电源
当主电源VDD掉电后,通过VBAT脚为实时时钟(RTC)和备份寄存器提供电源
在这里插入图片描述
这张图展示了STM32微控制器(MCU)内部的电源分配方案。整个系统可分为三大主要供电区域:模拟部分供电(VDDA)、数字部分供电包括VDD供电区域和1.8v供电区域、后备供电(VBAT)。

  • 首先来看模拟部分供电,即VDDA区域,负责为模拟功能如AD转换器、温度传感器、复位模块及PLL锁相环提供电力。这些组件的正极连接至VDDA,而负极则连接至VSSA。特别地,AD转换器的参考电压输入端VREF+和VREF-通常会在在引脚多的型号里会单独引出来;而在像C8T6这样的少引脚型号中,它们已在芯片内部直接连接到VDDA和VSSA上。

  • 接下来是数字部分供电,该部分分为两个子区域:VDD供电区和1.8V供电区。VDD供电区包含了I/O电路、待机电路、唤醒逻辑和独立看门狗等功能。这部分电路的工作电压通常是3.3V。为了提高能效,STM32的设计采用了低压策略,因此大部分关键的内部电路,例如CPU、存储器和数字外设,实际上是以1.8V的较低电压运行。

关于1.8V供电区,它是由VDD通过内置的电压调节器降压得到的,提供给CPU核心、存储器和内置数字外设。当这些外设需要与外界进行交流时,才会通过I/O电路转换到3.3V。这种设计有助于显著降低系统的功耗,因为较低的电压意味着更低的功率消耗。
需要注意的是,STM32的工作电压(VDD)范围为2.0~3.6V,而1.8V电源是通过内置的电压调节器提供的

  • 最后讨论的是后备供电区域。此区域包括了LSE 32K晶体振荡器、后备寄存器、RCC BDCR寄存器和实时时钟(RTC)。RCC BDCR是RTC的控制寄存器之一,也属于后备区域的一部分,因此同样可以通过VBAT供电。此外,图中还显示了一个低电压检测器,它可以监测主电源VDD的状态,并在VDD失效时自动切换到VBAT供电模式,确保RTC和其他关键的后备功能即使在主电源断开的情况下也能继续工作。

电源管理器

上电复位和掉电复位,还有可编程电压监测器这两个内容了解即可

上电复位和掉电复位

在这里插入图片描述
上电复位和掉电复位的功能在于当VDD或VDDA的电压降至一定水平时,内部电路会自动触发复位操作,防止STM32在电压不稳定时进行错误操作。为此,系统设置了一个40毫伏的迟滞电压,以避免电压波动导致的不稳定。具体来说,当电压超过上限(POR阈值,即1.92V)时,系统解除复位状态;而当电压低于下限(PDR阈值,即1.88V)时,系统进入复位状态。这种设计采用了迟滞比较器,通过设定上下两个阈值,有效防止了电压在阈值附近波动时引起的输出抖动。

需要注意的是,复位信号是低电平有效,意味着在电压过低(前后两种情况)时,系统会进入复位状态,而在电压正常(中间状态)时,系统则不会复位。关于具体的电压阈值和复位滞后时间,可以参考STM32的数据手册,具体信息在5.3.3节“内嵌复位和电源控制模块特性”中有详细说明。根据数据手册,PDR的典型下限阈值是1.88V,而POR的典型上限阈值是1.92V,这40毫伏的迟滞阈值确保了电压稳定。简而言之,电压大于1.9V时系统上电,低于1.9V时系统掉电。此外,复位持续时间(TRSTTEMPO)的典型值为2.5毫秒。

这个复位持续时间很重要,实际产品这里经常出偶发问题又难以排查

可编程电压监测器

PVD的工作原理与前述的上电复位和掉电复位类似,都是监测VDD和VDDA的供电电压。然而,PVD的独特之处在于其阈值电压是可以编程设定的,提供了更大的灵活性。
在这里插入图片描述
根据数据手册中的相关表格,可以通过配置PLS寄存器的3个位来选择PVD的阈值。这些阈值的选择范围大约在2.2V到2.9V之间,且PVD的上限和下限阈值之间的迟滞电压为100毫伏。值得注意的是,PVD的监测电压范围高于上电和掉电复位的阈值。
在这里插入图片描述
为了更直观地理解,可以想象一个电压从3.3V的正常供电逐渐降低的情景。当电压降至2.9V至2.2V之间时,就进入了PVD的监测范围。在这个范围内,您可以设置一个警告线,以便在电压进一步降低至1.9V以下,即复位电路的检测范围时,系统可以采取行动。
当PVD被触发时,微控制器仍然可以正常工作,但这是对用户的一个提醒,表明电源电压已经过低。PVD的输出是正逻辑,即电压过低时输出为1,电压正常时输出为0。这个信号可以用来申请中断,在电压上升或下降时触发,从而提醒程序进行相应的处理。
关于PVD的中断申请,它通过外部中断实现。在EXTI(外部中断)的基本结构图中,可以看到PVD的输出信号是如何接入的。因此,如果想要使用PVD,记得正确配置外部中断。
另外,尽管RTC有自己的中断系统,但为了在低功耗模式下唤醒停止模式,只有外部中断能够实现这一点。这也是为什么其他设备,如USB和ETH的唤醒信号,也要通过外部中断来唤醒停止模式。理解这一点对于低功耗设计至关重要。

低功耗模式

在这里插入图片描述
STM32F10xxx有三种低功耗模式:

睡眠模式

在这里插入图片描述

要进入睡眠模式,只需直接调用WFI(等待中断)或WFE(等待事件)指令,这两个都是内核指令,对应的库函数中也提供了相应的调用方法。WFI的作用是让CPU进入睡眠状态,直到有中断发生时唤醒;而WFE则是让CPU等待一个特定的事件来唤醒。唤醒条件分别是:WFI模式下,任何中断都能唤醒CPU;WFE模式下,则需要一个特定的事件来唤醒。唤醒后,WFI通常需要处理中断服务函数,而WFE则可能直接继续执行。

睡眠模式对电路的影响有限,主要表现在关闭了CPU时钟,而其他时钟和ADC时钟不受影响。电压调节器保持开启状态,因此,睡眠模式主要是通过停止CPU时钟来降低功耗。关闭时钟意味着所有的运算和时序操作暂停,但寄存器和存储器中的数据得以保持。睡眠模式的唤醒条件相对宽松,任何中断都能唤醒CPU,因此,它相当于是在保持身体其他部分工作的情况下,大脑稍作休息,省电程度评为一般。

在这里插入图片描述
在这里插入图片描述

停机模式

在这里插入图片描述

要进入停机模式,首先需要将sleepdeep位设置为1,指示CPU进入深度睡眠。PDDS位用于区分停机模式或待机模式,PDDS为0时进入停机模式。之后LPDS位用于控制电压调节器是保持开启还是进入低功耗模式(RPDS等于电压调节器开启,RPDS等于1电压调节器进入低功耗v)。

设置好这些位后,调用WFI或WFE即可进入停机模式。停机模式的唤醒条件比睡眠模式苛刻,只有外部中断能够唤醒。这意味着,如PVD、RTC闹钟、USB唤醒、ETH唤醒等通过外部中断的信号可以唤醒系统。停机模式关闭了所有1.8伏区域的时钟,包括HSI和HSE振荡器,但LSI和LSE振荡器保持运行。电压调节器可以选择开启或低功耗模式,后者更省电但唤醒时间更长。停机模式相当于整个人的工作完全停止,只有外部中断才能唤醒,省电程度评为非常省电。

注意
在这里插入图片描述
系统从停止模式被中断或唤醒事件唤醒时,HSI(内部高速时钟)会被自动选为系统时钟。这是因为,在我们的程序中,默认在SystemInit函数里配置的是使用HSE(外部高速时钟),并通过PLL(锁相环)倍频来获得72MHz的主频。然而,一旦进入停止模式,PLL和HSE都会停止工作。

因此,当系统从停止模式唤醒时,它不会自动通过PLL倍频来恢复到原来的72MHz主频,而是直接使用HSI的8MHz作为主频。如果忽略这一点,就可能会出现以下现象:程序刚上电时运行在72MHz的主频,但进入停止模式并在唤醒之后,主频会降为8MHz。不止慢9倍这么简单,带时序的外设基本上都出问题。

为了避免这种情况,我们通常需要在停止模式唤醒后的第一时间重新启动HSE,并将主频重新配置为72MHz。这一操作并不复杂,因为相关的配置函数已经为我们准备好了。我们只需要在唤醒后调用SystemInit函数,即可完成主频的重新配置。这样,系统就能恢复到停止模式之前的工作状态,确保程序的正常运行。

待机模式

在这里插入图片描述

进入待机模式的步骤与停机模式相似,但PDDS位需设置为1。待机模式的唤醒条件最为严格,普通外设中断和外部中断都无法唤醒,只有特定的信号,如wake up引脚的上升沿、RTC闹钟事件、NRST引脚的外部复位和IWDG独立看门狗复位,才能唤醒。待机模式几乎关闭了所有电路,包括1.8伏区域的时钟和电压调节器,这意味着内部存储器和寄存器的数据会丢失。但与停机模式一样,LSI和LSE振荡器保持运行以支持RTC和独立看门狗。待机模式相当于彻底下班,除非有紧急事项,否则不会返回工作,省电程度评为极为省电。

在这里插入图片描述

在之前的讨论中,我们提到了多个与低功耗模式相关的寄存器位,这些模式还有一些更细致的划分。例如,睡眠模式中有SLEEP-NOW和SLEEP-ON-EXIT的区别,停机模式中则有电压调节器开启与低功耗模式的区别。了解如何配置这些模式对我们理解程序有很大帮助。
首先这里有一句,执行WFI等待中断或者WFE等待事件指令后,STM32进入低功耗模式,就说这两个指令是最终开启低功耗模式的触发条件,配置其他的寄存器都要在这两个指令之前
以下是基于配置流程的详细说明:

  1. 执行WFI或WFE指令:这两个指令是启动低功耗模式的触发点。在执行这两个指令之前,需要配置好相关的寄存器。
  2. 判断sleep deep位:这一位决定了是进入浅睡眠还是深度睡眠模式。
    • 如果sleep deep位为0,则进入睡眠模式。
    • 如果sleep deep位为1,则进入深度睡眠模式,即停机模式或待机模式。
  3. 睡眠模式的细分:在睡眠模式下,SLEEPONEXIT位可以进一步细分模式。
    • 当SLEEPONEXIT位为0时,执行WFI或WFE后立即进入睡眠模式。
    • 当SLEEPONEXIT位为1时,执行WFI或WFE后会等待当前中断处理完成后才进入睡眠模式。这种情况适用于中断处理中还有一些紧急任务需要完成。
  4. 深度睡眠模式的判断:对于深度睡眠模式,需要进一步判断PDDS位。
    • 如果PDDS位为0,则进入停机模式。
    • 如果PDDS位为1,则进入待机模式。
  5. 停机模式的进一步配置:在停机模式下,LPDS位决定了电压调节器的工作状态。
    • 如果LPDS位为0,则电压调节器保持开启状态。
    • 如果LPDS位为1,则电压调节器进入低功耗模式,虽然更省电,但唤醒延迟更长。

【手册/天书讲解环节请看VCR】

【system_stm32f10x.c/.h文件讲解】

代码实战:修改主频&睡眠模式&停止模式&待机模式

  • 修改主频
    请添加图片描述
    在这里插入图片描述

最好不要去中途改主频,因为那些外设初始化时都是根据SystemCoreClock来的,就运行一次,主频改完后得重新配置外设初始化那些

  • 睡眠模式+串口发送+接收
    在这里插入图片描述

main.c

#include "stm32f10x.h"                 // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include "LED.h"
uint8_t RxData;
uint8_t Pin_9, Pin_10;
int main(void)
{OLED_Init();Serial_Init();OLED_ShowString(1, 1, "RxData:");while (1){if (Serial_GetRxFlag() == 1){RxData = Serial_GetRxData();Serial_SendByte(RxData);OLED_ShowHexNum(1, 8, RxData, 2);}// 没有数据要发送但代码一直执行所以可以采用睡眠模式OLED_ShowString(2, 1, "Running...");Delay_ms(500);OLED_ShowString(2, 1, "         ");Delay_ms(500);__WFI(); // 进入睡眠,中断唤醒//执行WFI这时CPU会立刻睡眠,程序就停在了WFI指令这里,但是各个外设比如USRT还是工作状态//等到我们用串口助手发送数据时,USRT外设收到数据产生中断,唤醒CPU之后程序在暂停的地方继续运行}
}
  • 停止模式+对射式红外传感器计次
    在这里插入图片描述
    在这里插入图片描述

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "CountSensor.h"int main(void)
{/*模块初始化*/OLED_Init();			//OLED初始化CountSensor_Init();		//计数传感器初始化/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);		//开启PWR的时钟//停止模式和待机模式一定要记得开启/*显示静态字符串*/OLED_ShowString(1, 1, "Count:");while (1){OLED_ShowNum(1, 7, CountSensor_Get(), 5);			//OLED不断刷新显示CountSensor_Get的返回值OLED_ShowString(2, 1, "Running");					//OLED闪烁Running,指示当前主循环正在运行Delay_ms(100);OLED_ShowString(2, 1, "       ");Delay_ms(100);PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI);	//STM32进入停止模式,并等待中断唤醒SystemInit();										    //唤醒后,要重新配置时钟,重启HSE配置72M主频//退出停止模式时,HSI被选为系统时钟,也就是在我们首次复位后,SystemInit函数里配置的是HSE*9倍频的72M主频//所以复位后第一次Running闪烁很快,而之后进入停止模式,再退出时默认时钟就变成HSI了,HSI是8M,所以唤醒之后的程序运行就会明显变慢}
}
  • 待机模式+实时时钟
    在这里插入图片描述
    main.c
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyRTC.h"int main(void)
{/*模块初始化*/OLED_Init();		//OLED初始化MyRTC_Init();		//RTC初始化/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);		//开启PWR的时钟//停止模式和待机模式一定要记得开启,虽然MyRTC_Init里开启了,多次开启无所谓,防止其他没调用MyRTC_Init的场景   但时钟没开启外设就不会工作/*显示静态字符串*/OLED_ShowString(1, 1, "CNT :");//秒计数器OLED_ShowString(2, 1, "ALR :");//闹钟值OLED_ShowString(3, 1, "ALRF:");//闹钟标志位/*使能WKUP引脚*/PWR_WakeUpPinCmd(ENABLE);						//使能位于PA0的WKUP引脚,WKUP引脚上升沿唤醒待机模式//手册里PWR_CSR的寄存器描述,这里写了使能wake up引脚后,wake up引脚被强制为输入下拉的配置,所以不用再GPIO初始化了/*设定闹钟*/uint32_t Alarm = RTC_GetCounter() + 10;			//闹钟为唤醒后当前时间的后10sRTC_SetAlarm(Alarm);							//写入闹钟值到RTC的ALR寄存器 这个寄存器只写不可读,所以使用变量Alarm显示到OLED上OLED_ShowNum(2, 6, Alarm, 10);					//显示闹钟值while (1){OLED_ShowNum(1, 6, RTC_GetCounter(), 10);	//显示32位的秒计数器OLED_ShowNum(3, 6, RTC_GetFlagStatus(RTC_FLAG_ALR), 1);		//显示闹钟标志位OLED_ShowString(4, 1, "Running");			//OLED闪烁Running,指示当前主循环正在运行Delay_ms(100);OLED_ShowString(4, 1, "       ");Delay_ms(100);OLED_ShowString(4, 9, "STANDBY");			//OLED闪烁STANDBY,指示即将进入待机模式Delay_ms(1000);OLED_ShowString(4, 9, "       ");Delay_ms(100);OLED_Clear();								//OLED清屏,模拟关闭外部所有的耗电设备,以达到极度省电PWR_EnterSTANDBYMode();						//STM32进入停止模式,并等待指定的唤醒事件(WKUP上升沿或RTC闹钟)/*待机模式唤醒后,程序会重头开始运行*///待机模式之后的代码执行不到,下次继续从头开始 在程序刚开始的时候自动调用SystemInit初始化时钟,所以待机模式我们就不用像停止模式那样,自己调用SystemInit了//并且这个while循环,实际上也只有执行一遍的机会,把这个while循环去掉也是可以的}
}
http://www.lqws.cn/news/532765.html

相关文章:

  • Java 大视界 -- 基于 Java 的大数据可视化在智慧城市能源消耗动态监测与优化决策中的应用(324)
  • 【linux】全志Tina配置swupdate工具进行分区打包
  • 《PT100两线制温度测量系统设计:从电路原理到嵌入式实现》
  • 【嵌入式ARM汇编基础】-ELF文件格式内部结构详解(二)
  • 香港政府发表《香港数字资产发展政策宣言 2.0》,提出「LEAP」框架
  • 星型模式(Star Schema)
  • lua脚本为什么能保证原子性
  • 云效代码仓库导入自建gitlab中
  • Redis核心知识详解:从全局命令到高级数据结构
  • 首款SUV小米YU7、小米AI眼镜等新品重磅发布,玄戒O1超大规模量产
  • 湖北理元理律师事务所:科学债务优化如何守护民生底线
  • MySQL 总是差八个小时,如何破?
  • Linux中部署Jenkins保姆间教程
  • 爬虫005----Selenium框架
  • 9. 回文数
  • MySQL (二):范式设计
  • Linux服务器部署Leantime与cpolar构建低成本团队协作环境
  • LRU缓存C++
  • kubernetes》》k8s》》滚动发布 、金丝雀发布 、
  • 医疗AI专科子模型联邦集成编程分析
  • 第一章-人工智能概述-机器学习基础与应用(1/36)
  • 时序分析未完待续
  • DeepSeek16-open-webui Pipelines开发填坑
  • 什么是财务共享中心?一文讲清财务共享建设方案
  • dlib检测视频中的人脸并裁剪为图片保存
  • centos 7 安装NVIDIA Container Toolkit
  • 鸿蒙原子化服务与元服务:轻量化服务的未来之路
  • Spring Security 安全控制终极指南
  • postman接口功能测试
  • 【音视频】Ubuntu下配置ffmpeg库