阳江专业手机网站制作公司,甘肃网站建设制作商,郑州网站zhi zuo,2021智慧树互联网与营销创新在电子设备中#xff0c;待机#xff08;Standby#xff09;和睡眠#xff08;Sleep#xff09;是两种不同的省电模式。 1. 待机模式#xff08;Standby Mode#xff09;#xff1a;在待机模式下#xff0c;设备仍然保持一定程度的活动#xff0c;但大部分功能处于暂…在电子设备中待机Standby和睡眠Sleep是两种不同的省电模式。 1. 待机模式Standby Mode在待机模式下设备仍然保持一定程度的活动但大部分功能处于暂停状态。
电源
STM32的工作电压(VDD)为2.03.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.03.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模式下任何中断都能唤醒CPUWFE模式下则需要一个特定的事件来唤醒。唤醒后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进入低功耗模式就说这两个指令是最终开启低功耗模式的触发条件配置其他的寄存器都要在这两个指令之前 。 以下是基于配置流程的详细说明
执行WFI或WFE指令这两个指令是启动低功耗模式的触发点。在执行这两个指令之前需要配置好相关的寄存器。判断sleep deep位这一位决定了是进入浅睡眠还是深度睡眠模式。 如果sleep deep位为0则进入睡眠模式。如果sleep deep位为1则进入深度睡眠模式即停机模式或待机模式。 睡眠模式的细分在睡眠模式下SLEEPONEXIT位可以进一步细分模式。 当SLEEPONEXIT位为0时执行WFI或WFE后立即进入睡眠模式。当SLEEPONEXIT位为1时执行WFI或WFE后会等待当前中断处理完成后才进入睡眠模式。这种情况适用于中断处理中还有一些紧急任务需要完成。 深度睡眠模式的判断对于深度睡眠模式需要进一步判断PDDS位。 如果PDDS位为0则进入停机模式。如果PDDS位为1则进入待机模式。 停机模式的进一步配置在停机模式下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.hint 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.hint 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循环去掉也是可以的}
}