STM32——PWR
一、PWR
1.1PWR简介
PWR(Power Control)电源控制
PWR负责管理STM32内部的电源供电部分,可以实现可编程电压监测器和低功耗模式的功能
可编程电压监测器(PVD)可以监控VDD电源电压,当VDD下降到PVD阀值以下或上升到PVD阀值之上时,PVD会触发中断,用于执行紧急关闭任务
低功耗模式包括睡眠模式(Sleep)、停机模式(Stop)和待机模式(Standby)(功耗逐级降低,唤醒时间逐级变长),可在系统空闲时,降低STM32的功耗,延长设备使用时间
1.2电源框图
1. VDDA供电区 (模拟电源域)
功能:为芯片内部所有模拟模块供电的独立电源区域。
供电引脚:由独立的 VDDA 和 VSSA 引脚供电。
主要负载:
模数转换器 (ADC)
数模转换器 (DAC)(如果支持)
内部RC振荡器 (HSI, LSI)、锁相环 (PLL)
电压参考缓冲 (VREF+ / VREF-)(在某些型号上由VDDA引出)
设计要点:
必须连接:即使不使用任何模拟功能,VDDA也必须连接到VDD(通常通过一个磁珠或低阻值电阻隔离),否则芯片无法正常工作。
去耦和滤波:为了获得最佳的ADC性能,VDDA和VSSA必须并联高频和低频去耦电容(例如100nF + 1uF),并尽可能靠近芯片引脚,以滤除来自数字电路的噪声。
电源质量:ADC的转换精度直接依赖于VDDA的电压稳定性和纯净度。如果VDDA上有噪声,ADC的读数也会产生波动。
2. VDD供电区
来源:直接从芯片的
VDD
/VSS
引脚接入。供电目标:
I/O 引脚:所有数字I/O口的驱动电源。
部分模拟电路:虽然模拟部分主要由VDDA供电,但一些与I/O相关的模拟逻辑(如输入保护二极管)也可能连接到VDD。
待机电路(唤醒逻辑,IWDG)
电压调节器:连接1.8V供电区域
特点:这是芯片的主电源入口。在设计PCB时,必须在每个
VDD
引脚附近放置一个去耦电容(通常100nF),以滤除高频噪声,提供稳定电流。
3. 1.8V供电区域 (数字电源域)
功能:芯片数字核心逻辑的供电区域,是芯片运行的主要动力源。
供电来源:
在大多数STM32(除某些超低功耗型号外)中,VDD电压(如3.3V)并不直接供给内核。
而是通过一个内部电压调节器(稳压器)将VDD降压到一个稳定的1.8V(或1.2V,取决于产品系列和工作频率),再为这个区域供电。
主要负载:
CPU内核 (Cortex-M系列核心)
数字外设 (如GPIO、SPI, I2C, USART, Timers等)
内部SRAM和Flash存储器
设计要点:
VDD引脚:为整个数字部分供电,包括I/O口和内部稳压器。需要良好的去耦。
低功耗模式:在停止等模式下,PWR可以关闭或降低该稳压器的输出,以大幅降低静态功耗。
此1.8V区域在芯片内部产生,用户无法直接从外部测量或供电。
4. 后备供电区 (Backup Domain)
功能:一个独立的供电区域,用于在主电源(VDD/VBAT)丢失时,保存最关键的数据和维持最基本的时基功能。
供电来源:由一个特殊的电源选择电路控制,其电源来自:
VDD(当主电源存在时)
VBAT(当低电压检测器检测到主电源VDD断开时,自动切换到VBAT引脚)
主要负载:
实时时钟 (RTC):即使主MCU断电,RTC也可以继续走时。
备份寄存器 (Backup Registers):一小块由VBAT维持的SRAM,通常为16-32字节,用于存储关键数据(如设备序列号、校准参数、运行状态等)。
唤醒逻辑:用于从待机模式通过RTC闹钟或WKUP引脚唤醒整个系统。
设计要点:
VBAT引脚:必须连接。如果应用中没有备用电池(如纽扣电池),强烈建议将VBAT引脚通过一个100nF电容连接到VSS,并同时通过一个二极管(如1N4148)连接到VDD。这样可以确保主电源存在时由VDD为备份域供电,主电源断开时则由电容短暂维持(时间很短,仅用于安全关机)。
写保护:要修改备份域中的寄存器(RTC配置、备份寄存器),必须先取消其写保护。
域隔离:备份域与其他域通过特殊的开关隔离,只有在特定条件下才能被访问,这进一步保证了其数据安全。
5. 总结与关键注意事项
供电区域 | 来源 | 供电目标 | 设计要点 |
---|---|---|---|
VDD | 外部电源 | I/O引脚,部分内部逻辑 | 充分去耦,每个VDD引脚一个100nF电容 |
VDDA | 独立清洁电源 | ADC, DAC, VREF+ | 必须通过磁珠/电感与VDD隔离,加强滤波 |
1.8V域 | 内部LDO(来自VDD) | CPU, 内存, 数字外设 | 低功耗模式的控制核心 |
VBAT | 外部电池 | RTC, 备份寄存器, LSE | 保证主电源掉电后关键功能不丢失 |
1.3上电复位(POR)和掉电复位(PDR)
基本概念
上电复位(Power-On Reset, POR):在芯片从无电到上电的过程中,当供电电压VDD从0V开始上升,达到一个特定的触发阈值(VPOR) 时,芯片会产生一个复位信号,将整个系统保持在复位状态,直到电源电压稳定到一个可靠的水平。
掉电复位(Power-Down Reset, PDR):在芯片正常工作后,如果因为某种原因(如电源干扰、电池耗尽)导致VDD电压下降,当电压低于一个特定的触发阈值(VPDR) 时,芯片会产生一个复位信号,防止CPU和外设在电压不足的情况下执行错误操作。
在STM32中,POR和PDR电路通常被集成在一起,统称为POR/PDR电路。它们是一个完全由模拟硬件实现的功能,不需要任何软件配置,只要接了VDD电源就会自动工作。
POR的40mV迟滞(确保电源稳定和等待时钟稳定)
是什么:迟滞是一种经典的电路设计技术,用于防止比较器在阈值点附近因噪声或微小波动而产生反复翻转(振荡)。
如何工作:
VPOR_up (上升阈值):当VDD电压从0V开始上升时,必须达到VPOR(例如,约1.8V)这个阈值点,POR电路才会解除复位信号。
VPOR_down (下降阈值):当VDD电压从正常值下降时,必须降到比VPOR低40mV(例如,约1.76V)的点,POR电路才会重新断言(Assert)复位信号。
1.4可编程电压监测器(预警)
基本概念
可编程电压监测器(Programmable Voltage Detector, PVD) 是一个可以由软件配置的电源电压监测模块。它持续将VDD电压与一个由软件设定的阈值(PLS[2:0]
)进行比较。
PVD阈值
是什么:PVD的阈值不是固定的,而是由软件通过配置PWR_CR寄存器的
PLS[2:0]
位来动态选择的。阈值等级:STM32提供了多个可选的阈值,覆盖了一个常见的电压范围(例如,从2.0V到2.9V,具体范围和步进因产品系列而异)。这允许开发者根据实际供电电压(如3.3V系统或2.5V系统)来设置一个合理的预警点。
PVD的100mV迟滞(防止振荡,缓冲区)
是什么:与POR类似,PVD的比较器也内置了迟滞功能,但其迟滞电压典型值为100mV。
如何工作:
假设软件设置的PVD阈值是 2.8V。
下降沿:当VDD电压从高处下降到2.8V时,PVD输出触发,标志位置位,并可产生中断。
上升沿:之后,如果VDD电压又从低处回升,它必须达到 2.8V + 100mV = 2.9V 时,PVD输出才会解除,标志位清零,并可再次产生中断。
POR/PDR 与 PVD 的对比总结
特性 | POR/PDR | PVD |
---|---|---|
本质 | 硬件自动保护机制 | 软件可配置的预警机制 |
功能 | 保证可靠上电和防止欠压运行 | 监测电压变化,提供早期预警 |
控制 | 完全由模拟硬件实现,无需配置(固定1.9V) | 需要通过软件配置阈值和外部中断(2.2V~2.9V) |
响应 | 产生复位信号,触发系统复位,强制MCU重启 | 触发中断或事件,由软件决定如何处理 |
速度 | 响应极快,是最后防线 | 响应较快,但需软件处理时间 |
关系 | “最后的安全卫士” | “哨兵”,为卫士提供预警 |
迟滞 | 典型40mV,防止电源噪声导致反复复位 | 典型100mV,防止电压波动导致中断风暴 |
1.5低功耗模式
功耗从高到低,唤醒速度从快到慢:睡眠→停止→待机
1.睡眠模式 (Sleep Mode)
实现机制:执行
WFI
(Wait for Interrupt)或WFE
(Wait for Event)指令后,内核停止执行,CPU时钟关闭。但所有外设的时钟仍然正常运行,NVIC保持工作。功耗:功耗降低主要来自CPU核心本身。整体功耗相对较高。
唤醒:
任何外设中断(如果使用
WFI
)或事件(如果使用WFE
)都可唤醒。唤醒时间极短,几乎无延迟,因为时钟系统仍在运行,CPU恢复时钟后即可继续执行下一条指令。
适用场景:处理完任务后,短暂等待下一次中断,且对唤醒延迟要求极高的场合。
睡眠模式注意点:
- 执行完WFI/WFE指令后,STM32进入睡眠模式,程序暂停运行,唤醒后程序从暂停的地方继续运行
- SLEEPONEXIT位决定STM32执行完WFI或WFE后,是立刻进入睡眠,还是等STM32从最低优先级的中断处理程序中退出时进入睡眠
- 在睡眠模式下,所有的I/O引脚都保持它们在运行模式时的状态
- WFI指令进入睡眠模式,可被任意一个NVIC响应的中断唤醒
- WFE指令进入睡眠模式,可被唤醒事件唤醒
2. 停止模式 (Stop Mode)
实现机制:
PDDS位=0,停止模式
SLEEPDEEP=1
关闭整个1.8V供电区域的时钟,包括CPU和所有外设的时钟。
可选择关闭内部主稳压器(LPDS位=0,电压调节器开启,LPDS位=1,调压器进入低功耗模式),以进一步省电。
可选是否保留IO口状态。
所有寄存器和SRAM的内容保持不变。
功耗:功耗显著降低,可达微安(µA)级别。
唤醒:
由外部复位(NRST引脚)、RTC闹钟/事件、RTC入侵事件、RTC唤醒事件、多个EXTI线(外部中断,对应特定引脚)唤醒。
唤醒后,系统时钟默认切换为HSI(内部多速RC振荡器),需要软件重新配置时钟树到想要的速度。程序从停止指令后的下一条指令开始执行。
适用场景:需要长时间休眠、定期唤醒采样、且需保持当前程序上下文(变量值)的场合。是平衡功耗和灵活性的最佳选择。
停止模式注意点:
- 执行完WFI/WFE指令后,STM32进入停止模式,程序暂停运行,唤醒后程序从暂停的地方继续运行
- 1.8V供电区域的所有时钟都被停止,PLL、HSI和HSE被禁止,SRAM和寄存器内容被保留下来
- 在停止模式下,所有的I/O引脚都保持它们在运行模式时的状态
- 当一个中断或唤醒事件导致退出停止模式时,HSI被选为系统时钟
- 当电压调节器处于低功耗模式下,系统从停止模式退出时,会有一段额外的启动延时
- WFI指令进入停止模式,可被任意一个EXTI中断唤醒
3. 待机模式 (Standby Mode)
实现机制:
PDDS位=1,待机模式
SLEEPDEEP=1
最彻底的模式。关闭1.8V供电区域(整个数字电路域)。
除了备份域(RTC、备份寄存器)和唤醒逻辑,其他部分全部断电。
SRAM和寄存器内容全部丢失(备份寄存器除外)。
功耗:功耗最低,可达微安(µA)甚至纳安(nA)级别。
唤醒:
由外部复位(NRST引脚)、RTC闹钟/事件、RTC入侵事件、WKUP引脚(PA0)的上升沿、独立看门狗(IWDG)复位唤醒。
唤醒后相当于一次软复位,芯片从头开始执行程序(复位向量地址0x0000_0000)。可以通过检查PWR_CSR寄存器的
SBF
(Standby Flag)标志位来判断是否由待机模式唤醒。
适用场景:需要极低功耗、长时间休眠,且每次唤醒都作为一次全新启动的场合。例如,每天只上报一次数据的远程传感器。
待机模式注意点:
- 执行完WFI/WFE指令后,STM32进入待机模式,唤醒后程序从头开始运行
- 整个1.8V供电区域被断电,PLL、HSI和HSE也被断电,SRAM和寄存器内容丢失,只有备份的寄存器和待机电路维持供电
- 在待机模式下,所有的I/O引脚变为高阻态(浮空输入)
- WKUP引脚的上升沿、RTC闹钟事件的上升沿、NRST引脚上外部复位、IWDG复位退出待机模式
4. 模式选择
执行WFI(Wait For Interrupt)或者WFE(Wait For Event)指令后,STM32进入低功耗模式
5. 模式对比总结表
特性 | 睡眠模式 (Sleep) | 停止模式 (Stop) | 待机模式 (Standby) |
---|---|---|---|
功耗 | 中 | 低 | 极低 |
唤醒时间 | 极短 (仅CPU恢复时钟) | 短 (需时钟重启) | 长 (完全复位) |
程序执行上下文 | 保持 (从下条指令继续) | 保持 (从下条指令继续) | 丢失 (从头开始执行) |
SRAM/寄存器内容 | 保持 | 保持 | 丢失 (备份域除外) |
时钟状态 | 仅CPU时钟停 | 所有1.8V域时钟停 | 1.8V域断电 |
主要唤醒源 | 任意中断/事件 | EXTI线、RTC事件 | WKUP引脚、RTC事件、NRST |
应用场景 | 短暂空闲,快速响应 | 定期采样,保持状态 | 超长待机,复位启动 |
6. 重要设计注意事项
GPIO配置:在进入Stop/Standby模式前,必须将所有不用的GPIO设置为模拟输入模式。悬空的IO引脚如果被配置为浮空输入,会因漏电流而显著增加功耗。
未使用外设:关闭所有不需要的外设时钟。
调试接口:低功耗模式可能会禁用调试器(如ST-Link)的连接。通常唤醒后才能重新连接。有些模式支持“调试驻留”功能,允许在低功耗下保持调试连接,但会略微增加功耗。
测量功耗:精确测量功耗时,需将调试器断开,仅通过电源供电进行测量。
二、修改主频频率代码
文件system_stm32f10.c中
此文件是只读文件,若要修改,需要打开工程文件夹,打开文件所在位置,右键——属性——只读选项去除
#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)#if是预编译,用来兼容不同型号的设备
若define后面有效,就else上面有效
否则#else,即下面代码有效我的设备时F10F3C8T6 中容量,非超值系列,因此查看else下方代码,由此来修改主频频率
此时主频频率时72MHz/* #define SYSCLK_FREQ_HSE HSE_VALUE */#define SYSCLK_FREQ_24MHz 24000000
#else
/* #define SYSCLK_FREQ_HSE HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz 24000000 */
/* #define SYSCLK_FREQ_36MHz 36000000 */
/* #define SYSCLK_FREQ_48MHz 48000000 */
/* #define SYSCLK_FREQ_56MHz 56000000 */
#define SYSCLK_FREQ_72MHz 72000000
#endif主程序代码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);}
}
配置时钟的流程:
①system_Init()函数→启动HSI+各种缺省配置——调用SetSysClock()分配函数
②SetSysClock()分配函数→选择解除不同的宏定义,从而执行不同的配置参数SerSysClockTo72等函数——进行配置主频频率(例:To72——HSE锁相环输入——HSE9倍频——HSE锁相环输出位主频——主频72M)
三、睡眠模式+串口发送接收
(再次运行需要按住复位键俩秒+点击运行+松手)
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "serial.h"
#include "stdio.h"
uint16_t Rxdata;在此工程基础上,加一个低功耗的代码假设用STM32做一个下位机
下位机接收电脑串口发送过来的指令,后执行相应的功能
电脑随时都可能通过串口发送指令靠中断触发,没有中断就无用的代码,可以加入一个低功耗模式——睡眠模式,其他模式都不行int main(void)
{ OLED_Init();serial_init();OLED_ShowString(1,1,"RXdata:");while(1){if(serial_getRxfalg()==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);--------------------------------------------------------------------------------SCB->SCR=0x………………//此种寄存器方式配置
__WFI();//中断唤醒}
}
仅需加入__WFI即可进入睡眠模式
若想要配置深度睡眠模式还是睡眠模式,可以查看手册STM32F10XXX.Cortex-M3编程手册——4.4.6System control register(SCB_SCR),在程序中,用操作寄存器的方式实现
SEVEONPEND=0,事件唤醒睡眠模式需要配置的位
SLEEPDEEP=0,睡眠模式;=1,深度睡眠模式
SLEEPONEXIT=0,立刻睡眠;=1,等中断结束睡眠
程序执行流程:
①初始化,串口配置好,进入主循环,检查标志位,Running闪烁一次,在主循环最后执行__WFI(),执行WFI,CPU立刻睡眠
②CPU睡眠,各个外设运行状态,等到串口发送数据,USART接收到数据,产生中断,唤醒CPU,睡眠模式唤醒后,程序在暂停的地方继续运行
③因此,程序运行到WFI之后,但唤醒之后,终端立刻申请,所以程序在条回到while循环开头之前,先进入USART中断函数,读取数据,置R下Flag,清除RXNE,回到主循环开头,此时RxFlag刚置1,if成立,执行数据回传和显示功能
④唤醒功能执行完,Running闪烁一次,程序再次来到WFI位置,CPU再次进入睡眠……
四、停止模式+对射式红外传感器计次
4.1PWR外设库函数:
1.恢复缺省配置
void PWR_DeInit(void);
2.使能后备区域的访问
void PWR_BackupAccessCmd(FunctionalState NewState);
3.与PVD相关的函数,PVD使能
void PWR_PVDCmd(FunctionalState NewState);
4.与PVD相关的函数,配置PVD的阈值电压
void PWR_PVDLevelConfig(uint32_t PWR_PVDLevel);
5.使能位于PA0位置的WakeUp引脚(待机模式用Wakeup上升沿唤醒)
void PWR_WakeUpPinCmd(FunctionalState NewState);
6.进入停止模式
void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry);
7.进入待机模式
void PWR_EnterSTANDBYMode(void);
8.获取标志位
FlagStatus PWR_GetFlagStatus(uint32_t PWR_FLAG);
9.清除标志位
void PWR_ClearFlag(uint32_t PWR_FLAG);
4.2代码书写
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "countSensor.h"外部中断不需要时钟
在硬件层面没有EXTI,只有内部中断和外部中断,
外部中断可用停机模式,内部中断只能用睡眠模式
在代码里无EXTI时钟参数,这就是EXTI能在时钟关闭的情况下工作的原因int main(void)
{ OLED_Init();CountSensor_Init();
--------------------------------------------------------------------------------------RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);OLED_ShowString(1,1,"count");while(1){ OLED_ShowSignedNum(1,7,count,5);OLED_ShowString(2,1,"Running");Delay_ms(500);OLED_ShowString(2,1," ");Delay_ms(500);---------------------------------------------------------------------------------------PWR_EnterSTOPMode(PWR_Regulator_ON,PWR_STOPEntry_WFI);/*复位后第一个Running很快,后面就变慢了是因为推出停止模式后,HSI被选为系统时钟SystemInit函数里配置的是72M主频,后续的HSI是8M,因此运行时间变慢只需要在后面重新调用SystemInit函数,重新启动HSE,配置72M主频即可*/SystemInit();}}
五、待机模式+实时时钟
任务一、设定闹钟
在while上设定,每次复位后设定闹钟值
任务二、加入待机模式
使用PWR外设之前,开启时钟,确保代码独立性
任务三、
wakeup引脚唤醒功能,随时用GPIO引脚,但不需要GPIO初始化
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "My_RTC.h"int main(void)
{ OLED_Init();MyRTC_Init();RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);OLED_ShowString(1, 1, "CNT:");//秒计数器OLED_ShowString(2, 1, "ALR:");//闹钟值OLED_ShowString(3, 1, "ALRF:");//闹钟标志位/*使能WKUP引脚*/PWR_WakeUpPinCmd(ENABLE);//使能位于PA0的WKUP引脚,WKUP引脚上升沿唤醒待机模式uint32_t Alarm=RTC_GetCounter()+10;RTC_SetAlarm(Alarm);//只写寄存器OLED_ShowNum(2,6,Alarm,10);while(1){OLED_ShowNum(1, 6, RTC_GetCounter(), 10); //显示32位的秒计数器/*闹钟标志位是否置1*/OLED_ShowNum(3,6,RTC_GetFlagStatus(RTC_FLAG_ALR),1);OLED_ShowString(4,1,"Running");Delay_ms(500);OLED_ShowString(4,1," ");Delay_ms(500);OLED_ShowString(4, 9, "STANDBY");//OLED闪烁STANDBY,指示即将进入待机模式Delay_ms(1000);OLED_ShowString(4, 9, " ");Delay_ms(100);OLED_Clear();//OLED清屏,模拟关闭外部所有的耗电设备,以达到极度省电//STM32进入待机模式之前,要把外部接入的模块能停的都停掉,能断电的都断掉,以最大化的省电PWR_EnterSTANDBYMode();//程序从头开始执行//注意:复位+下载+松手}
}