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

STM32的PWR

我们使用手机的时候屏幕亮起,我们页面进入操作不同APP。而当我们不需要使用时,如果手机屏幕一直维持亮起状态,那么手机电量是不是用的很快。所以一般情况下,我们使用手机后,它会自动息屏,或者我们把它关机掉。PWR也是这一相似作用,为了 在性能与功耗之间做出平衡,提供电源管理手段,使系统在满足运行需求的同时,尽可能节能、稳定、安全运行。

从上电到运行:STM32 的供电和启动流程

当 VDD 上电时:

步骤模块/行为说明
1电源电压上升VDD 通常为 3.3V,逐步达到稳态
2复位电路监控 VDD(POR/PDR)POR(上电复位)和 PDR(掉电复位)确保电压稳定前不让系统启动
3内部复位激活,MCU 初始化时钟未启用,CPU处于复位状态
4等待 VDD 稳定后,释放复位系统从复位状态进入主程序启动流程
5程序执行 Reset_Handler → main()启动汇编初始化,跳转到主函数

掉电检测器(PDR)与上电复位(POR)

机制触发条件作用
POR(Power-On Reset)VDD 从 0V 上升超过阈值(约 1.8V)确保芯片只在电压稳定后开始运行
PDR(Power-Down Reset)VDD 跌落低于阈值(~2.0V)在掉电或电压不稳时强制系统复位
BOR(Brown-Out Reset)更精细的电压跌落监控有些 STM32 系列才有(F1 没有)

POR/PDR 是硬件级别电压检测电路,在 MCU 最开始的电源稳定过程中发挥作用,不依赖软件配置,也无法屏蔽。

PVD(Programmable Voltage Detector)详解

PVD 是一个可编程门限的电压比较器,作用是:

在 VDD 跌落之前发出中断预警

比 PDR 反应更早,允许用户软件自行保存数据/进入低功耗模式

时钟 & PVD 初始化函数

void PVD_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);       // 打开 PWR 时钟PWR_PVDLevelConfig(PWR_PVDLevel_2V9);                      // 设置门限电压为 2.9VPWR_PVDCmd(ENABLE);                                        // 使能 PVDEXTI_InitTypeDef EXTI_InitStructure;EXTI_ClearITPendingBit(EXTI_Line16);                       // 清除 EXTI16 的挂起标志EXTI_InitStructure.EXTI_Line = EXTI_Line16;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;  // 电压上升/下降都触发EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = PVD_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
}

中断服务函数(显示 VDD 状态)

void PVD_IRQHandler(void)
{if (PWR_GetFlagStatus(PWR_FLAG_PVDO) == SET){OLED_ShowString(2, 1, "LOW VDD!");     // 电压低于门限}else{OLED_ShowString(2, 1, "VDD OK");       // 电压恢复}EXTI_ClearITPendingBit(EXTI_Line16);       // 清除中断标志位
}

主函数调用

int main(void)
{SystemInit();OLED_Init();OLED_ShowString(1, 1, "PVD Watchdog");PVD_Init();   // 初始化 PVD 监测while (1){// 其他逻辑处理……}
}
功能库函数说明
打开 PWRRCC_APB1PeriphClockCmd()启动 PWR 模块
开启 PVDPWR_PVDCmd(ENABLE)启用电压检测
设置门限PWR_PVDLevelConfig(PWR_PVDLevel_2V9)设置比较器参考电压
判断是否电压低PWR_GetFlagStatus(PWR_FLAG_PVDO)返回比较结果
清除中断EXTI_ClearITPendingBit(EXTI_Line16)清除 EXTI16 中断标志

硬件说明

项目说明
PVD 内部连接连接到 EXTI Line16,不能更换引脚
比较参考电压内部固定,有 8 个档位(2.2V ~ 2.9V)
比较器功能检测 VDD 与参考电压比较结果
响应时间非常快,硬件触发中断
唤醒功能可以作为唤醒源用于唤醒 Stop 模式下的 MCU(⚠️ 不是 Standby)

PWR 相关供电结构(STM32F103 为例)

STM32F1 系列包含以下供电模块:

模块说明
VDD主供电(通常 3.3V)
VDDA模拟电源(ADC/Comparator),需滤波
VSS数字地
VBAT实时时钟供电(RTC/备份寄存器),用于掉电后保持数据
VCAP1稳压输出电容(仅部分 STM32 有)

低功耗模式

睡眠模式

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

停止模式

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

待机模式

执行完WFI/WFE指令后,STM32进入待机模式,唤醒后程序从头开始运行
整个1.8V供电区域被断电,PLL、HSI和HSE也被断电,SRAM和寄存器内容丢失,只有备份的寄存器和待机电路维持供电
在待机模式下,所有的I/O引脚变为高阻态(浮空输入)
WKUP引脚的上升沿、RTC闹钟事件的上升沿、NRST引脚上外部复位、IWDG复位退出待机模式

举例一个工程包含低功耗所有关键功能

main()
│
├── 初始化外设(OLED、按键)
├── 显示当前状态
├── 判断是否从 Standby 唤醒
├── 初始化 PVD
├── 等待按键触发不同低功耗模式
│   ├── KEY1 → 进入 Sleep 模式
│   ├── KEY2 → 进入 Stop 模式(5秒后 RTC 唤醒)
│   └── KEY3 → 进入 Standby 模式(PA0 唤醒)
└── PVD 检测中断持续监控电压状态
#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_pwr.h"
#include "stm32f10x_exti.h"
#include "misc.h"
#include "OLED.h"
#include "Delay.h"
#include "Key.h"// 初始化 PVD 电压检测器,使用你库里的函数
void PVD_Init(void)
{// 1. 开启 PWR 模块时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);// 2. 设置 PVD 检测电压门限为 2.9VPWR_PVDLevelConfig(PWR_PVDLevel_2V9);// 3. 使能 PVD 功能PWR_PVDCmd(ENABLE);// 4. 配置 EXTI Line16(PVD 专用中断线)EXTI_ClearITPendingBit(EXTI_Line16);EXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line = EXTI_Line16;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; // 电压上下沿触发EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);// 5. 配置 PVD 中断 NVICNVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = PVD_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
}// 进入 Sleep 模式
void Enter_SleepMode(void)
{__WFI();  // 等待中断进入 Sleep,使用库函数无须额外操作
}// 进入 Stop 模式(低功耗调压模式)
void Enter_StopMode(void)
{// 使用你库里的函数进入 Stop 模式PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);// Stop 模式后,时钟需重设SystemInit();
}// 进入 Standby 模式(极限低功耗,掉电重启)
void Enter_StandbyMode(void)
{// 允许唤醒引脚 PA0 唤醒功能PWR_WakeUpPinCmd(ENABLE);// 进入 Standby 模式PWR_EnterSTANDBYMode();
}// PVD 中断处理函数(在 stm32f10x_it.c 中)
void PVD_IRQHandler(void)
{if (PWR_GetFlagStatus(PWR_FLAG_PVDO) == SET){OLED_ShowString(4, 1, "LOW VDD!  ");}else{OLED_ShowString(4, 1, "VDD OK    ");}EXTI_ClearITPendingBit(EXTI_Line16);
}int main(void)
{SystemInit();OLED_Init();Key_Init();PVD_Init();OLED_ShowString(1, 1, "Power Mode Demo");if (PWR_GetFlagStatus(PWR_FLAG_SB) == SET){PWR_ClearFlag(PWR_FLAG_SB);OLED_ShowString(2, 1, "Wake from STANDBY");}else{OLED_ShowString(2, 1, "Normal Power On");}while (1){uint8_t key = Key_GetNum();if (key == 1){OLED_ShowString(3, 1, "Enter SLEEP Mode ");Delay_ms(500);Enter_SleepMode();OLED_ShowString(3, 1, "Woke from SLEEP   ");}else if (key == 2){OLED_ShowString(3, 1, "Enter STOP Mode  ");Delay_ms(500);Enter_StopMode();OLED_ShowString(3, 1, "Woke from STOP   ");}else if (key == 3){OLED_ShowString(3, 1, "Enter STANDBY... ");Delay_ms(1000);Enter_StandbyMode();}}
}
库函数功能
PWR_BackupAccessCmd()开启对 RTC 和 BKP 寄存器的访问权限(修改 RTC 必须)
PWR_PVDCmd()开启/关闭 PVD 电压检测器
PWR_PVDLevelConfig()设置电压阈值(2.2V~2.9V)
PWR_WakeUpPinCmd()启用 PA0 唤醒引脚
PWR_EnterSTOPMode()进入 Stop 模式(可选低功耗 LDO)
PWR_EnterSTANDBYMode()进入 Standby 模式(极低功耗,掉电重启)
PWR_GetFlagStatus()查询 PWR 相关标志位(SB、WU、PVDO)
PWR_ClearFlag()清除 WakeUp 或 Standby 标志位

http://www.lryc.cn/news/612418.html

相关文章:

  • 引领GameFi 2.0新范式:D.Plan携手顶级财经媒体启动“龙珠创意秀”
  • ZYNQ实现FFT信号处理项目
  • Python科学计算:从基础到工程仿真的完整指南
  • 指挥中心自动化的演变
  • cygwin+php教程(swoole扩展+redis扩展)
  • Redis使用的常见问题及初步认识
  • JDK17新特性全解析
  • TFTP: Linux 系统安装 TFTP,文件系统启动后TFTP使用
  • win服务器系统10060问题解决
  • 【CSS】动态修改浏览器滚动条宽度
  • 楼宇自控系统对建筑碳中和目标的实现具重要价值
  • mysql死锁的常用解决办法
  • Java 里的Tree初认识
  • 【概念学习】什么是深度学习
  • 12、Docker Compose 安装 Redis
  • Effective C++ 条款25:考虑写出一个不抛异常的swap函数
  • 【前端开发】五. ES5和ES6对比
  • imx6ull-驱动开发篇11——gpio子系统
  • 常用排序方法
  • 排序算法归并排序
  • 单变量单步时序预测:CNN-BiGRU卷积神经网络结合双向门控循环单元
  • 202506 电子学会青少年等级考试机器人六级实际操作真题
  • 基于RPR模型的机械臂手写器simulink建模与仿真
  • Qt Frameless Widget跨平台无边框窗口
  • 机器学习-KNN​​
  • 云平台托管集群:EKS、GKE、AKS 深度解析与选型指南-第四章
  • iT 运维: WindoWs CMD 命令表
  • Flutter开发 Image组件使用示例
  • <form> + <iframe> 方式下载大文件的机制
  • 基于Github Pages搭建个人博客站点:hexo环境搭建、本地预览与发布