多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

15.PWR电源控制

15.PWR电源控制 PWR简介PWR简介电源监测 (PVD - 可编程电压监测器)作用实时监控VDD电源电压。触发机制当电压高于或低于设定的阈值时会触发中断。应用场景用于执行紧急关闭任务保护系统数据或硬件免受低电压影响例如掉电检测。电源管理 (低功耗模式)包含模式睡眠模式 (Sleep)、停机模式 (Stop)、待机模式 (Standby)。这三种模式的功耗依次递减。应用场景在系统处于空闲状态时进入这些模式以极大降低STM32的功耗常用于电池供电的嵌入式设备以延长续航时间。电源框图四大供电区域解析1. VDD 供电区域主供电区域连接引脚VDD / VSS包含模块I/O电路、待机电路唤醒逻辑、独立看门狗IWDG、电压调节器。核心作用这是STM32的主要供电来源。图中的电压调节器非常关键它负责将外部输入的VDD电压通常为2.0V~3.6V降压提供给1.8V的核心域。2. 1.8V 供电区域核心数字域连接方式不直接引出引脚由上述的“电压调节器”降压供电。包含模块CPU核心、存储器Flash、SRAM、内置数字外设。核心作用这是芯片内部逻辑运行的核心区域采用1.8V低电压运行以降低功耗。在低功耗模式下电压调节器可以进入低功耗模式或关闭从而极大降低整体功耗。3. VDDA 供电区域模拟供电域连接引脚VDDA / VSSA以及参考电压 VREF / VREF-。包含模块A/D转换器、温度传感器、复位模块、PLL锁相环。核心作用为对噪声敏感的模拟外设提供独立电源。注意图底部的备注VDDA和VSSA必须分别连接到VDD和VSS。在实际硬件设计中VDDA通常会通过磁珠或电感与VDD隔离并加滤波电容以保证ADC转换精度。图注说明VREF-从2.4V起至VDDAVREF用于设定ADC的参考电压。4. 后备供电区域备份域连接引脚VBAT包含模块LSE 32K晶体振荡器、后备寄存器、RCC BDCR寄存器、RTC实时时钟。核心作用当主电源VDD掉电时可以通过VBAT引脚接入纽扣电池如3V锂电池继续为这部分供电保证RTC持续走时并保存后备寄存器的关键数据不丢失。低电压检测器图中显示低电压检测器连接了VDD和后备供电区域它用于监控VDD电压当电压低于阈值时触发中断或复位呼应上一张PPT中提到的PVD功能。上电复位和掉电复位PORPDR这张图片展示了STM32微控制器中上电复位POR和掉电复位PDR的硬件工作机制。核心概念解析1. 上电复位POR - Power-On Reset定义当VDD/VDDA电压从0V开始上升首次达到一个特定阈值即图中的POR阈值时芯片才会解除复位状态开始正常运行。滞后时间tRSTTEMPO图中标注了从电压到达POR阈值到Reset信号真正拉高解除复位之间有一段延迟时间tRSTTEMPO。作用这段时间是为了让外部电源彻底稳定下来同时也让芯片内部的振荡器如HSE、HSI和电压调节器有足够的时间起振和稳定。如果此时立即解除复位CPU可能会在电源不稳定或时钟未就绪的情况下跑飞。2. 掉电复位PDR - Power-Down Reset定义当VDD/VDDA电压下降且跌破PDR阈值时复位信号Reset会立即被拉低触发复位。作用在电源电压不足以维持CPU和存储器正常工作时强制芯片进入复位状态防止内部逻辑出现乱码、数据损坏或Flash写入错误。3. 40mV 迟滞Hysteresis现象图中POR阈值高于PDR阈值两者相差约40mV。为什么需要迟滞如果POR和PDR是同一个阈值当电源电压正好处于临界点且有微小波动纹波时复位信号会频繁地在“复位”和“解除复位”之间疯狂跳动导致系统崩溃。这40mV的电压差起到了“防抖动”的作用确保在电压回落时必须下跌一段明显的距离才会触发复位。可编程电压监测器Programmable Voltage Detector可编程电压监测器PVD的电压门限和输出波形图。1. PVD阈值与门限可编程特性与POR/PDR固定的硬件阈值不同PVD的阈值图中水平的虚线是可以通过软件配置PWR_CR寄存器的PLS位进行选择的。电压上升阶段左侧当VDD/VDDA电压从0V上升穿过设定的PVD阈值时PVD输出信号会发生翻转图中表现为从低电平跳变到高电平。电压下降阶段右侧当电压从正常值下降跌破PVD阈值时PVD输出信号再次翻转从高电平跳变到低电平。2. 100mV 迟滞Hysteresis图注图中明确标注了上升阈值和下降阈值之间相差100 mV。与POR/PDR的区别你上一张图中POR/PDR的迟滞是40mV而PVD的迟滞是100mV具体数值以芯片数据手册为准但通常PVD的迟滞更大。作用同样是为了防抖动。当电压在阈值附近波动时这100mV的压差能避免PVD输出信号频繁跳动防止CPU被反复触发中断从而保证系统稳定。与PVD可编程电压监测器的区别特性POR / PDR (本次图示)PVD (可编程电压监测器)触发阈值硬件固定不可修改软件可编程可设置多个档位作用强制硬复位整个芯片触发中断或事件应用场景电源上电和掉电时的安全保护掉电预警如紧急保存数据到Flash、低压检测两者关系PVD的监测阈值通常高于PDR阈值。当PVD中断触发时系统还有时间做紧急处理直到电压跌破PDR发生强制复位。低功耗模式三种低功耗模式深度解析1. 睡眠模式 (Sleep) —— 最轻度的“打盹”进入方式执行WFI等待中断或WFE等待事件指令。唤醒条件任一中断WFI模式或唤醒事件WFE模式。唤醒速度最快几乎无延迟。时钟状态仅关闭CPU时钟。对1.8V区域的其他外设时钟和ADC时钟无影响。VDD区域的时钟也无影响。电压调节器开。底层逻辑CPU睡觉了但所有外设UART、SPI、ADC等仍在正常运转。适合需要快速响应外部事件但CPU暂时无事可做的场景。2. 停机模式 (Stop) —— 深度休眠保留上下文进入方式配置SLEEPDEEP位内核寄存器PDDS位选择StopLPDS位选择调压器状态然后执行WFI或WFE。唤醒条件任一外部中断需提前在EXTI外部中断寄存器中配置使能。时钟状态关闭所有1.8V区域的时钟CPU和所有外设时钟停止。同时关闭VDD区域的HSI和HSE振荡器。电压调节器开启或处于低功耗模式取决于PWR_CR寄存器的LPDS位设定。底层逻辑系统时钟全停但1.8V核心域仍有电SRAM和寄存器数据保留。唤醒后程序从进入停机模式的下一条指令继续执行。这是兼顾低功耗和保留运行状态的理想选择。3. 待机模式 (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执行了WFIWait For Interrupt或WFEWait 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和寄存器数据全部丢失。唤醒后相当于复位重启睡眠模式1. 唤醒机制“断点续传”第一点强调了睡眠模式的一大优势程序暂停唤醒后从暂停处继续运行。这与后面的“待机模式”形成了鲜明对比待机模式唤醒后等同于复位程序从头开始。这意味着在睡眠模式下所有的变量、堆栈、程序上下文都被完整保留。2. SLEEPONEXIT 位的巧妙用法SLEEPONEXIT 0立刻睡眠执行WFI指令后CPU立刻停止工作进入睡眠。适合主循环中while(1){ ... __WFI(); }的结构。SLEEPONEXIT 1退出中断时睡眠CPU执行WFI后如果当前正在处理中断比如刚处理完某个突发事件它会先执行完当前中断一直退到最低优先级的中断处理完后才进入睡眠。这种模式特别适合“事件驱动型”程序平时睡眠发生中断唤醒处理处理完中断后自动再次进入睡眠无需在代码里到处写WFI指令。3. 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在没有中断开销的情况下醒来速度更快功耗更低。停止模式1. 依然保持“断点续传”第一点与睡眠模式一致SRAM和寄存器内容保留唤醒后程序从进入停止模式的下一条指令继续执行。这意味着你的全局变量、堆栈状态都不会丢失。2. 功耗大幅下降时钟全停第二点是与睡眠模式的核心区别进入Stop模式后1.8V核心域的所有时钟都被停止PLL、HSI和HSE都被关闭。睡眠模式只是CPU睡觉外设还在跑mA级功耗。停止模式是系统时钟全停仅保留内部低速时钟LSI/LSE给IWDG或RTC。功耗通常会降到微安μA级别。3. IO引脚状态保持与睡眠模式一样Stop模式下IO引脚依然保持进入前的状态不会变成高阻态。这一点在控制外部硬件如保持某个片选信号拉低时非常有用。4. 极重要考点唤醒后系统时钟变为HSI幻灯片中明确提到“当一个中断或唤醒事件导致退出停止模式时HSI被选为系统时钟”。实战现象很多初学者从Stop模式唤醒后发现串口乱码、定时器不准、程序跑得慢。这是因为唤醒后硬件默认将系统时钟切回了内部的HSI通常为8MHz或16MHz而你原本依赖的HSE外部晶振和PLL倍频配置已经丢失。解决办法唤醒后必须在代码的最前端比如中断服务函数退出前或主循环开头重新调用系统时钟配置函数如SystemInit()或手动配置RCC等待HSE稳定并重新使能PLL。5. 唤醒延时LPDS的作用结合之前的配置图如果LPDS1电压调节器处于低功耗模式主调压器需要从低功耗状态唤醒电压爬升需要时间。因此系统退出Stop模式时会有额外的启动延时通常几十微秒。如果项目对唤醒响应时间要求极其苛刻比如需要极速响应外部脉冲必须将LPDS设为0调压器保持开启牺牲一点点功耗换取极速唤醒。6. 唤醒源只能靠 EXTI与睡眠模式的“任意NVIC中断唤醒”不同Stop模式的唤醒源被严格限制在EXTI外部中断/事件控制器。这意味着在进入Stop模式前你必须把唤醒源如按键引脚、RTC闹钟、UART RX引脚配置为外部中断模式并使能对应的EXTI线。WFI对应 EXTI中断WFE对应 EXTI事件。待机模式1. 唤醒即复位程序从头开始这与睡眠和停止模式截然不同。因为唤醒后相当于执行了一次系统复位程序会回到main函数的起点重新初始化所有外设。所以如果进入待机前有未保存的数据它们将永久丢失。2. 彻底断电与数据丢失结合之前的《电源框图》待机模式下电压调节器关闭1.8V核心域完全掉电。SRAM和普通寄存器内容丢失。备份区域VBAT域RTC、LSE、后备寄存器、待机电路维持供电。如果你外接了纽扣电池到VBAT引脚RTC时间依然会走。3. I/O引脚变为高阻态睡眠和停止模式下I/O保持原状态但在待机模式下I/O变成了高阻态浮空输入。实战避坑如果外部电路有上拉电阻或控制着某个关键使能引脚如电机驱动器的使能进入待机后这个引脚由于高阻态电压可能变得不确定导致外部硬件误动作或产生漏电流。在进入待机前务必在软件中将关键IO配置为安全的上下拉状态或者加外部下拉电阻。4. 苛刻的唤醒条件待机模式只能通过以下四种方式唤醒WKUP引脚的上升沿通常是PA0需提前配置。RTC闹钟事件常用于定时唤醒。NRST引脚外部复位按下复位键。IWDG独立看门狗复位看门狗溢出。三模式功耗对比特性睡眠模式 (Sleep)停止模式 (Stop)待机模式 (Standby)功耗mA级μA级亚μA级最低1.8V核心域供电供电断电电压调节器开启开启或低功耗关闭SRAM/寄存器保留保留丢失I/O引脚状态保持保持高阻态浮空唤醒源任意NVIC中断仅EXTI中断/事件WKUP、RTC、NRST、IWDG唤醒后程序继续执行继续执行从头开始复位典型唤醒时间极快较快较慢类似重新上电示例修改主频在这里修改用是否注释就可以了#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闪烁#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(); } }对射红外传感器停止模式#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” 闪一下然后再次进入睡眠。1. 上电初始化后OLED 第一行显示Count:和计数值按常见OLED_ShowNum写法可能是Count:00000。第二行先显示Running约 100ms 后清空再延时 100ms。然后执行PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI);进入停止模式。此时 MCU 停止运行OLED 保持最后显示内容第一行是当前 Count第二行是空白。所以睡眠期间不会看到 Running 持续闪烁屏幕基本静止。2. 对射红外传感器触发一次如果红外传感器接到 EXTI 外部中断并且中断使能会作为唤醒源把 MCU 从 STOP 模式唤醒。中断服务函数里执行Count。唤醒后继续执行PWR_EnterSTOPMode后面的SystemInit()然后回到while(1)开头。OLED 第一行更新为新的 Count例如Count:00001。第二行Running显示 100ms然后清空 100ms。再次进入 STOP 模式。现象就是每触发一次红外Count 加 1屏幕更新一次同时第二行 “Running” 闪一下然后继续睡眠。3. 按键按下如果按键也配置为 EXTI 中断并能唤醒 STOP 模式按键中断里把 Count 清 0。MCU 唤醒后 OLED 显示Count:00000。第二行Running闪一下。再次进入 STOP 模式。现象就是按键按下后 Count 清零屏幕更新为 0Running 闪一下然后继续睡眠。4. 没有触发时MCU 一直停在 STOP 模式。OLED 保持最后画面第二行是空白。不会周期性刷新也不会一直闪Running。实时时钟睡眠模式#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 秒一次
返回列表