PWR简介

PWR简介
-
电源监测 (PVD - 可编程电压监测器)
-
作用:实时监控VDD电源电压。
-
触发机制:当电压高于或低于设定的阈值时,会触发中断。
-
应用场景:用于执行紧急关闭任务,保护系统数据或硬件免受低电压影响(例如掉电检测)。
-
-
电源管理 (低功耗模式)
-
包含模式:睡眠模式 (Sleep)、停机模式 (Stop)、待机模式 (Standby)。(这三种模式的功耗依次递减)。
-
应用场景:在系统处于空闲状态时进入这些模式,以极大降低STM32的功耗,常用于电池供电的嵌入式设备以延长续航时间。
-
电源框图

四大供电区域解析
- VDD 供电区域(主供电区域)
-
连接引脚:VDD / VSS
-
包含模块:I/O电路、待机电路(唤醒逻辑、独立看门狗IWDG)、电压调节器。
-
核心作用 :这是STM32的主要供电来源。图中的电压调节器非常关键,它负责将外部输入的VDD电压(通常为2.0V~3.6V)降压,提供给1.8V的核心域。
- 1.8V 供电区域(核心数字域)
-
连接方式:不直接引出引脚,由上述的"电压调节器"降压供电。
-
包含模块:CPU核心、存储器(Flash、SRAM)、内置数字外设。
-
核心作用:这是芯片内部逻辑运行的核心区域,采用1.8V低电压运行以降低功耗。在低功耗模式下,电压调节器可以进入低功耗模式或关闭,从而极大降低整体功耗。
- VDDA 供电区域(模拟供电域)
-
连接引脚:VDDA / VSSA,以及参考电压 VREF+ / VREF-。
-
包含模块:A/D转换器、温度传感器、复位模块、PLL(锁相环)。
-
核心作用 :为对噪声敏感的模拟外设提供独立电源。注意图底部的备注 :
VDDA和VSSA必须分别连接到VDD和VSS。在实际硬件设计中,VDDA通常会通过磁珠或电感与VDD隔离,并加滤波电容,以保证ADC转换精度。 -
图注说明:VREF-从2.4V起至VDDA,VREF+用于设定ADC的参考电压。
- 后备供电区域(备份域)
-
连接引脚:VBAT
-
包含模块:LSE 32K晶体振荡器、后备寄存器、RCC BDCR寄存器、RTC(实时时钟)。
-
核心作用:当主电源VDD掉电时,可以通过VBAT引脚接入纽扣电池(如3V锂电池)继续为这部分供电,保证RTC持续走时,并保存后备寄存器的关键数据不丢失。
-
低电压检测器:图中显示低电压检测器连接了VDD和后备供电区域,它用于监控VDD电压,当电压低于阈值时触发中断或复位(呼应上一张PPT中提到的PVD功能)。
上电复位和掉电复位(POR+PDR)

这张图片展示了STM32微控制器中**上电复位(POR)和掉电复位(PDR)**的硬件工作机制。
核心概念解析
- 上电复位(POR - Power-On Reset)
-
定义 :当VDD/VDDA电压从0V开始上升,首次达到一个特定阈值(即图中的POR阈值)时,芯片才会解除复位状态,开始正常运行。
-
滞后时间(tRSTTEMPO) :图中标注了从电压到达POR阈值,到Reset信号真正拉高(解除复位)之间,有一段延迟时间
tRSTTEMPO。 -
作用:这段时间是为了让外部电源彻底稳定下来,同时也让芯片内部的振荡器(如HSE、HSI)和电压调节器有足够的时间起振和稳定。如果此时立即解除复位,CPU可能会在电源不稳定或时钟未就绪的情况下跑飞。
- 掉电复位(PDR - Power-Down Reset)
-
定义:当VDD/VDDA电压下降,且跌破PDR阈值时,复位信号(Reset)会立即被拉低(触发复位)。
-
作用:在电源电压不足以维持CPU和存储器正常工作时,强制芯片进入复位状态,防止内部逻辑出现乱码、数据损坏或Flash写入错误。
- 40mV 迟滞(Hysteresis)
-
现象:图中POR阈值高于PDR阈值,两者相差约40mV。
-
为什么需要迟滞?
如果POR和PDR是同一个阈值,当电源电压正好处于临界点且有微小波动(纹波)时,复位信号会频繁地在"复位"和"解除复位"之间疯狂跳动,导致系统崩溃。这40mV的电压差起到了"防抖动"的作用,确保在电压回落时,必须下跌一段明显的距离才会触发复位。
可编程电压监测器(Programmable Voltage Detector)

**可编程电压监测器(PVD)**的电压门限和输出波形图。
- PVD阈值与门限
-
可编程特性:与POR/PDR固定的硬件阈值不同,PVD的阈值(图中水平的虚线)是可以通过软件(配置PWR_CR寄存器的PLS位)进行选择的。
-
电压上升阶段(左侧) :当VDD/VDDA电压从0V上升,穿过设定的PVD阈值时,PVD输出信号会发生翻转(图中表现为从低电平跳变到高电平)。
-
电压下降阶段(右侧) :当电压从正常值下降,跌破PVD阈值时,PVD输出信号再次翻转(从高电平跳变到低电平)。
- 100mV 迟滞(Hysteresis)
-
图注 :图中明确标注了上升阈值和下降阈值之间相差
100 mV。 -
与POR/PDR的区别 :你上一张图中POR/PDR的迟滞是 40mV ,而PVD的迟滞是 100mV(具体数值以芯片数据手册为准,但通常PVD的迟滞更大)。
-
作用:同样是为了防抖动。当电压在阈值附近波动时,这100mV的压差能避免PVD输出信号频繁跳动,防止CPU被反复触发中断,从而保证系统稳定。
与PVD(可编程电压监测器)的区别
| 特性 | POR / PDR (本次图示) | PVD (可编程电压监测器) |
|---|---|---|
| 触发阈值 | 硬件固定,不可修改 | 软件可编程,可设置多个档位 |
| 作用 | 强制硬复位整个芯片 | 触发中断(或事件) |
| 应用场景 | 电源上电和掉电时的安全保护 | 掉电预警(如紧急保存数据到Flash)、低压检测 |
| 两者关系 | PVD的监测阈值通常高于PDR阈值。 | 当PVD中断触发时,系统还有时间做紧急处理,直到电压跌破PDR,发生强制复位。 |
低功耗模式

三种低功耗模式深度解析
- 睡眠模式 (Sleep) ------ 最轻度的"打盹"
-
进入方式 :执行
WFI(等待中断)或WFE(等待事件)指令。 -
唤醒条件 :任一中断 (WFI模式)或 唤醒事件(WFE模式)。唤醒速度最快,几乎无延迟。
-
时钟状态 :仅关闭CPU时钟 。对1.8V区域的其他外设时钟和ADC时钟无影响。VDD区域的时钟也无影响。
-
电压调节器 :开。
-
底层逻辑:CPU睡觉了,但所有外设(UART、SPI、ADC等)仍在正常运转。适合需要快速响应外部事件,但CPU暂时无事可做的场景。
- 停机模式 (Stop) ------ 深度休眠,保留上下文
-
进入方式 :配置
SLEEPDEEP位(内核寄存器)+PDDS位(选择Stop)+LPDS位(选择调压器状态),然后执行WFI或WFE。 -
唤醒条件 :任一外部中断(需提前在EXTI外部中断寄存器中配置使能)。
-
时钟状态 :关闭所有1.8V区域的时钟 (CPU和所有外设时钟停止)。同时关闭VDD区域的 HSI和HSE振荡器。
-
电压调节器 :开启或处于低功耗模式 (取决于
PWR_CR寄存器的LPDS位设定)。 -
底层逻辑 :系统时钟全停,但1.8V核心域仍有电(SRAM和寄存器数据保留)。唤醒后,程序从进入停机模式的下一条指令继续执行。这是兼顾低功耗和保留运行状态的理想选择。
- 待机模式 (Standby) ------ 最极致的省电,近似关机
-
进入方式 :配置
SLEEPDEEP位 +PDDS位(选择Standby),然后执行WFI或WFE。(注意:不需要配置LPDS了)。 -
唤醒条件:极其苛刻,只有四种方式:
-
WKUP引脚的上升沿 -
RTC闹钟事件
-
NRST引脚上的外部复位 -
IWDG(独立看门狗)复位
-
-
时钟状态:关闭所有1.8V区域时钟,关闭HSI和HSE。
-
电压调节器 :关。(对应《电源框图》中1.8V核心域彻底断电)
-
底层逻辑 :功耗最低(通常只有微安级)。因为电压调节器关闭,1.8V区域断电,SRAM和寄存器数据全部丢失 。唤醒后,系统相当于经历了一次复位,程序会从头开始执行(从Flash的启动文件开始)。只有后备供电区域(RTC、后备寄存器)还在工作。
模式选择

当你执行 WFI 或 WFE 指令后,STM32会根据寄存器(内核SCR寄存器和PWR_CR寄存器)的不同配置,决定最终进入哪一种低功耗模式。
触发入口
一切低功耗模式的起点,都是CPU执行了 WFI(Wait For Interrupt) 或 WFE(Wait For Event) 指令。
第一层判断:SLEEPDEEP 位(内核系统控制寄存器 SCR)
这决定了系统是进入"普通睡眠"还是"深度睡眠"。
-
SLEEPDEEP = 0➡️ 进入【睡眠模式 (Sleep)】此时内核停止,但所有外设时钟正常。根据
SLEEPONEXIT位又分为两种:-
SLEEPONEXIT = 0➡️ 睡眠模式(立刻睡眠) :执行WFI指令后,CPU立即进入睡眠。
-
SLEEPONEXIT = 1➡️ 睡眠模式(等待中断退出) :执行WFI指令后,系统不会立即睡眠。如果此时正在执行一个中断服务函数(ISR),会等这个ISR执行完毕并退出时,才进入睡眠。(此模式常用于中断处理完后自动休眠的场景)。
-
-
SLEEPDEEP = 1➡️ 进入【深度睡眠模式(停机/待机)】此时内核及大部分外设时钟关闭。
第二层判断:PDDS 位(电源控制寄存器 PWR_CR)
在深度睡眠的前提下,PDDS 决定了是进入停机模式还是待机模式。
-
PDDS = 0➡️ 进入【停机模式 (Stop)】此时1.8V核心域不断电,SRAM和寄存器数据保留。进一步由
LPDS决定电压调节器的状态:-
LPDS = 0➡️ 停机模式(电压调节器开启):功耗略高,但唤醒后系统恢复极快。 -
LPDS = 1➡️ 停机模式(电压调节器低功耗):功耗更低,但唤醒时需要等待电压调节器稳定,唤醒延迟更长。
-
-
PDDS = 1➡️ 进入【待机模式 (Standby)】此时电压调节器关断,1.8V核心域断电,SRAM和寄存器数据全部丢失。唤醒后相当于复位重启
睡眠模式

- 唤醒机制("断点续传")
第一点强调了睡眠模式的一大优势:程序暂停,唤醒后从暂停处继续运行。
- 这与后面的"待机模式"形成了鲜明对比(待机模式唤醒后等同于复位,程序从头开始)。这意味着在睡眠模式下,所有的变量、堆栈、程序上下文都被完整保留。
- SLEEPONEXIT 位的巧妙用法
-
SLEEPONEXIT = 0(立刻睡眠) :执行WFI指令后,CPU立刻停止工作(进入睡眠)。适合主循环中
while(1){ ... __WFI(); }的结构。 -
SLEEPONEXIT = 1(退出中断时睡眠) :CPU执行WFI后,如果当前正在处理中断(比如刚处理完某个突发事件),它会先执行完当前中断,一直退到最低优先级的中断处理完后,才进入睡眠。这种模式特别适合"事件驱动型"程序:平时睡眠,发生中断唤醒处理,处理完中断后自动再次进入睡眠,无需在代码里到处写WFI指令。
- I/O 引脚状态保持
进入睡眠模式后,所有的外设时钟依然在运行,I/O引脚的状态保持不变。这意味着:
-
如果你在睡眠前让某个引脚输出高电平(比如驱动LED),睡眠期间它依然保持高电平。
-
这非常适合那些需要维持特定硬件状态(如片选信号、外设使能引脚),仅仅是为了等待某个外部输入信号而短暂降低功耗的场景。
4.WFI vs WFE 的本质区别
-
WFI (Wait For Interrupt) :依靠**中断(Interrupt)**唤醒。这个中断必须是被NVIC(嵌套向量中断控制器)管理的,且优先级要满足条件。中断触发后,CPU会被唤醒,进入中断服务函数(ISR),执行完ISR后继续执行WFI后面的代码。
-
WFE (Wait For Event) :依靠事件(Event) 唤醒。事件是STM32内部的一种硬件信号机制。发生外部事件时,CPU会被唤醒,但不一定会去执行中断服务函数(取决于中断是否使能)。(注:在STM32中,使用
SEVONPEND和EXTI的配置,WFE也可以被中断唤醒,但从原理上,事件机制可以让CPU在没有中断开销的情况下醒来,速度更快,功耗更低)。
停止模式

- 依然保持"断点续传"
第一点与睡眠模式一致:SRAM和寄存器内容保留,唤醒后程序从进入停止模式的下一条指令继续执行。这意味着你的全局变量、堆栈状态都不会丢失。
- 功耗大幅下降(时钟全停)
第二点是与睡眠模式的核心区别:进入Stop模式后,1.8V核心域的所有时钟都被停止,PLL、HSI和HSE都被关闭。
-
睡眠模式只是CPU睡觉,外设还在跑(mA级功耗)。
-
停止模式是系统时钟全停,仅保留内部低速时钟(LSI/LSE)给IWDG或RTC。功耗通常会降到微安(μA)级别。
- IO引脚状态保持
与睡眠模式一样,Stop模式下IO引脚依然保持进入前的状态(不会变成高阻态)。这一点在控制外部硬件(如保持某个片选信号拉低)时非常有用。
- 极重要考点:唤醒后系统时钟变为HSI
幻灯片中明确提到:"当一个中断或唤醒事件导致退出停止模式时,HSI被选为系统时钟"。
-
实战现象:很多初学者从Stop模式唤醒后,发现串口乱码、定时器不准、程序跑得慢。这是因为唤醒后,硬件默认将系统时钟切回了内部的HSI(通常为8MHz或16MHz),而你原本依赖的HSE(外部晶振)和PLL倍频配置已经丢失。
-
解决办法 :唤醒后,必须在代码的最前端(比如中断服务函数退出前或主循环开头)重新调用系统时钟配置函数(如
SystemInit()或手动配置RCC),等待HSE稳定并重新使能PLL。
- 唤醒延时(LPDS的作用)
结合之前的配置图,如果 LPDS=1(电压调节器处于低功耗模式),主调压器需要从低功耗状态唤醒,电压爬升需要时间。因此,系统退出Stop模式时会有额外的启动延时(通常几十微秒)。
- 如果项目对唤醒响应时间要求极其苛刻(比如需要极速响应外部脉冲),必须将
LPDS设为0(调压器保持开启),牺牲一点点功耗换取极速唤醒。
- 唤醒源:只能靠 EXTI
与睡眠模式的"任意NVIC中断唤醒"不同,Stop模式的唤醒源被严格限制在 EXTI(外部中断/事件控制器)。
-
这意味着在进入Stop模式前,你必须把唤醒源(如按键引脚、RTC闹钟、UART RX引脚)配置为外部中断模式,并使能对应的EXTI线。
-
WFI对应 EXTI中断,WFE对应 EXTI事件。
待机模式

- 唤醒即复位(程序从头开始)
这与睡眠和停止模式截然不同。因为唤醒后相当于执行了一次系统复位,程序会回到 main 函数的起点,重新初始化所有外设。所以,如果进入待机前有未保存的数据,它们将永久丢失。
- 彻底断电与数据丢失
结合之前的《电源框图》,待机模式下电压调节器关闭,1.8V核心域完全掉电。
-
SRAM和普通寄存器:内容丢失。
-
备份区域(VBAT域) :RTC、LSE、后备寄存器、待机电路维持供电。如果你外接了纽扣电池到
VBAT引脚,RTC时间依然会走。
- I/O引脚变为高阻态
睡眠和停止模式下,I/O保持原状态;但在待机模式下,I/O变成了高阻态(浮空输入)。
- 实战避坑 :如果外部电路有上拉电阻或控制着某个关键使能引脚(如电机驱动器的使能),进入待机后,这个引脚由于高阻态,电压可能变得不确定,导致外部硬件误动作或产生漏电流。在进入待机前,务必在软件中将关键IO配置为安全的上下拉状态,或者加外部下拉电阻。
- 苛刻的唤醒条件
待机模式只能通过以下四种方式唤醒:
-
WKUP引脚的上升沿(通常是PA0,需提前配置)。
-
RTC闹钟事件(常用于定时唤醒)。
-
NRST引脚外部复位(按下复位键)。
-
IWDG独立看门狗复位(看门狗溢出)。
三模式功耗对比
| 特性 | 睡眠模式 (Sleep) | 停止模式 (Stop) | 待机模式 (Standby) |
|---|---|---|---|
| 功耗 | mA级 | μA级 | 亚μA级(最低) |
| 1.8V核心域 | 供电 | 供电 | 断电 |
| 电压调节器 | 开启 | 开启或低功耗 | 关闭 |
| SRAM/寄存器 | 保留 | 保留 | 丢失 |
| I/O引脚状态 | 保持 | 保持 | 高阻态(浮空) |
| 唤醒源 | 任意NVIC中断 | 仅EXTI中断/事件 | WKUP、RTC、NRST、IWDG |
| 唤醒后程序 | 继续执行 | 继续执行 | 从头开始(复位) |
| 典型唤醒时间 | 极快 | 较快 | 较慢(类似重新上电) |
示例:
修改主频
在这里修改,用是否注释就可以了

cpp
#include "stm32f10x.h"
#include "Delay.h"
#include "OLED.h"
int main(void)
{
OLED_Init();
OLED_ShowString(1, 1, "SYSCLK:");
OLED_ShowNum(1, 8, SystemCoreClock, 8);
while(1)
{
OLED_ShowString(2, 1, "Running");
Delay_ms(500);
OLED_ShowString(2, 1, " ");
Delay_ms(500);
}
return 0;
}
串口发送+睡眠模式
芯片平时处于睡眠状态,只有发送数据时期才runing闪烁
cpp
#include "stm32f10x.h"
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include "stdio.h"
int main(void)
{
OLED_Init();
SerialInit();
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_0);
uint16_t data;
while (1)
{
// if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)
// {
// data = USART_ReceiveData(USART1);
//
// OLED_ShowHexNum(1, 1, data, 2);
// SendByte(data);
// }轮循式接收
if(GetRxDataWithCheck(&data)==1)
{
OLED_ShowHexNum(1,1,data,4);
SendByte(data);
}
OLED_ShowString(2, 1, "Running");
Delay_ms(100);
OLED_ShowString(2, 1, " ");
Delay_ms(100);
//进入睡眠模式
__WFI();
}
}
对射红外传感器+停止模式
cpp
#include "stm32f10x.h"
#include "delay.h"
#include "oled.h"
#include "CountSensor.h"
int main(void)
{
//初始化
OLED_Init();
//开启PWR时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
OLED_ShowString(1, 1, "Count:");
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
count_sensor_init();
while(1)
{
OLED_ShowNum(1 , 7, CountSensor_Get(), 5);
OLED_ShowString(2, 1, "Running");
delay_ms(100);
OLED_ShowString(2, 1, " ");
delay_ms(100);
//进入停止模式
PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI);
//系统重新初始化
SystemInit();
}
return 0;
}
平时 MCU 在 STOP 停止模式,OLED 定格不刷新,第二行空白;每次红外触发或按键按下时唤醒一次,更新 Count,并让 "Running" 闪一下,然后再次进入睡眠。:
- 上电初始化后
-
OLED 第一行显示
Count:和计数值,按常见OLED_ShowNum写法可能是Count:00000。 -
第二行先显示
Running,约 100ms 后清空,再延时 100ms。 -
然后执行:
PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI);
进入停止模式。
-
此时 MCU 停止运行,OLED 保持最后显示内容:第一行是当前 Count,第二行是空白。
-
所以睡眠期间不会看到 Running 持续闪烁,屏幕基本静止。
- 对射红外传感器触发一次
-
如果红外传感器接到 EXTI 外部中断,并且中断使能,会作为唤醒源把 MCU 从 STOP 模式唤醒。
-
中断服务函数里执行
Count++。 -
唤醒后继续执行
PWR_EnterSTOPMode后面的SystemInit(),然后回到while(1)开头。 -
OLED 第一行更新为新的 Count,例如
Count:00001。 -
第二行
Running显示 100ms,然后清空 100ms。 -
再次进入 STOP 模式。
现象就是:每触发一次红外,Count 加 1,屏幕更新一次,同时第二行 "Running" 闪一下,然后继续睡眠。
- 按键按下
-
如果按键也配置为 EXTI 中断并能唤醒 STOP 模式:
-
按键中断里把 Count 清 0。
-
MCU 唤醒后 OLED 显示
Count:00000。 -
第二行
Running闪一下。 -
再次进入 STOP 模式。
-
现象就是:按键按下后 Count 清零,屏幕更新为 0,Running 闪一下,然后继续睡眠。
- 没有触发时
-
MCU 一直停在 STOP 模式。
-
OLED 保持最后画面,第二行是空白。
-
不会周期性刷新,也不会一直闪
Running。
实时时钟+睡眠模式
cpp
#include "stm32f10x.h"
#include "Delay.h"
#include "Oled.h"
#include "RTC.h"
int main(void)
{
uint32_t alarm = 0;
//初始化
OLED_Init();
rtc_init();
//开启PWR时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
OLED_ShowString(1, 1, "CNT: ");
OLED_ShowString(2, 1, "ALR: ");
OLED_ShowString(3, 1, "ALRF: ");
PWR_WakeUpPinCmd(ENABLE);
alarm = RTC_GetCounter() + 10;
RTC_SetAlarm(alarm);
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");
Delay_ms(100);
OLED_ShowString(4, 1, " ");
Delay_ms(1000);
OLED_ShowString(4, 9, "STANDBY");
Delay_ms(100);
OLED_ShowString(4, 9, " ");
Delay_ms(100);
OLED_Clear();
PWR_EnterSTANDBYMode();
}
return 0;
}
-
每次上电或唤醒后,屏幕会快速显示一下
Running和STANDBY,然后黑屏进入待机。 -
每隔 10 秒(或按下 WKUP 键)屏幕会再次闪烁一下,然后继续待机。
-
由于每次唤醒都重新设置闹钟为当前时间 +10 秒,所以表现为周期性唤醒(约 10 秒一次)
