
PWR简介低功耗模式说白了就是省电结构VDDA是模拟供电。VDD供电中电压调节器可以把电压降至1.8v给1.8v供电区域供电电压调节器就相当于1.8v区域的电源电压低可以降低功耗。RCC是复位与时钟控制器后备供电区域中RCC BDCR寄存器是RCC的寄存器叫备份域控制寄存器低电压检测器可以控制给后备区域的供电是VDD还是VBAT。上电复位和掉电复位当电压低于下限PDR时stm32复位停止操作高于上限POR时解除复位。上限和下限之间相差40mV这是为了防抖。解除复位也有一个滞后时间不会马上解除。阈值通常在1.9v左右。可编程电压检测器PVDPVD也是检测电压上限和下限之间相差100mV。电压低于下限或高于上限时PVD可以申请中断提醒用户PVD中断通道要借助外部中断EXTI因为只有外部中断可以唤醒停止模式。低功耗模式这三种低功耗模式从上到下越来越省电关闭部分越来越多越来越低功耗但也越来越难唤醒1.8v区域是芯片可以控制的VDD区域的VDD是外部输入芯片不能控制只能控制其中晶振后备区域更是独立。睡眠模式进入睡眠模式需要通过调用WFI或者WFEWFI就是等待中断所以唤醒是通过中断唤醒WFE就是等待事件唤醒通过事件唤醒。关闭了1.8v区域的CPU时钟但没有影响到其中的外设对VDD区域没有影响电压调节器是开启的所以1.8v区域没有掉电SRAM存储器和寄存器里的数据都还在。停机模式进入停机模式配置PDDS位为0PDDS1表示待机模式LPDS位配置电压调节器开启还是低功耗模式配置SLEEPDEEP1表示要进入深度睡眠最后调用WFI或者WFE。选择WFI则唤醒是通过外部中断的中断模式唤醒选择WFE则唤醒是通过外部中断的事件模式唤醒。停机模式关闭了1.8v区域的CPU和外设时钟既然CPU和外设都关闭了也就不需要VDD区域的HSI和HSE了它们也关闭了。电压调节器是开启或者低功耗模式区别就是低功耗模式更省电唤醒时间更久1.8v区域就没有掉电数据都还在。但是LSI,LSE没有关闭因为这是为RTC和看门狗准备的。待机模式进入待机模式配置PDDS位1SLEEPDEEP位1调用WFI或者WFE。只能通过WKUP引脚上升沿、RTC闹钟、NRST引脚复位、和独立看门狗复位来唤醒。几乎能关闭的都关闭了1.8v区域都关闭VDD区域HSE,HSI关闭电压调节器也关闭了所以数据都清零了。模式选择WFI和WFE是最后选择一旦执行后就会进入低功耗模式所以图中寄存器配置都要在选择WFI,WFE之前进行。三种模式细节睡眠模式时电压调节器没有关闭SRAM和寄存器数据都在所以唤醒后程序会从暂停的地方开始运行。停止模式时电压调节器也没有关闭SRAM和寄存器数据都在所以唤醒后程序也会从暂停地方开始运行。停止模式时HSI,HSE都被关闭但在唤醒后不会主动开启HSE会将HSI选为系统时钟所以唤醒后系统主频就不是72MHZ而是HSI的8MHZ停止模式需要唤醒后手动开启HSE。待机模式时电压调节器关闭SRAM数据丢失所以唤醒后程序从头开始运行从头开始程序会自动选择HSE。如果正常模式下电流为50mA,那么睡眠模式下电流就是30mA,停止模式下为50uA待机模式为5uA。睡眠模式串口接收数据代码下位机等待上位机发送数据可能偶尔才会发送但需要程序一直运行一直等待比较耗电。低功耗模式中睡眠模式关闭了CPU时钟程序停止运行外设时钟没有关闭USART依旧可以工作能及时接收到数据收到数据产生的中断也能唤醒睡眠模式。另外两个低功耗模式把外设时钟也关闭了就收不到数据了收到数据的中断也不能唤醒这两个模式所以选择睡眠模式搭配串口接收数据。主函数uint8_t RXdata; int main() { OLED_Init(); serial_init(); while(1) { RXdataserial_receive(); serial_send(RXdata); OLED_ShowHexNum(1,1,RXdata,2); OLED_ShowString(2,1,running); Delay_ms(100); OLED_ShowString(2,1, ); Delay_ms(100); //睡眠模式选择WFI中断唤醒还有两位SLEEPDEEP,SLEEPONEXTI需要用寄存器配置这里不配置就使用默认值0即立即睡眠 __WFI(); //上电程序运行到此就会进入睡眠running不再显示外设USART还在工作接收到数据产生中断唤醒后会先进入中断函数执行然后才会继续从这里执行程序接收数据running显示一下运行到此又进入睡眠 } }停止模式使用外部中断计次代码主函数//电平没有变化时程序依然在不断循环检测running一直在显示。使用停止模式running只在唤醒时显示外部中断可以唤醒。外部中断是不需要时钟的。进入停止模式需要PWR int main() { RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE); OLED_Init(); countsensor_init(); OLED_ShowString(1,1,count:); while(1) { OLED_ShowNum(1,7,countsensor_get(),4); OLED_ShowString(2,1,running); Delay_ms(100); OLED_ShowString(2,1, ); Delay_ms(100); PWR_EnterSTOPMode(PWR_Regulator_ON,PWR_STOPEntry_WFI);//电压调节器开启选择WFI。这个函数中已经配置好了SLEEPDEEP,PDDS和LPDS位。 //程序运行到此就进入了停止模式产生外部中断时唤醒进入中断函数执行后回到这里继续向下执行程序记一次数显示一次running后又运行到此进入停止模式 //注意第一次唤醒之后系统不会主动打开HSE时钟而是选择了HSI时钟所以之后running闪烁时间不对 SystemInit();//调用函数恢复使用HSE时钟 } }待机模式RTC闹钟、WKUP引脚代码//RTC闹钟触发和WKUP引脚上升沿可以唤醒待机模式进入待机模式需要PWR。 int main() { OLED_Init(); MYRTC_init(); RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE); PWR_WakeUpPinCmd(ENABLE);//WKUP引脚在PA0使能后强制为下拉输入不需要初始化PA0口。WKUP引脚输入高电平一次也会唤醒一次。 OLED_ShowString(1,1,CNT:);//计数器值 OLED_ShowString(2,1,ALR:);//闹钟值 uint32_t alarmRTC_GetCounter()10; RTC_SetAlarm(alarm);//设定闹钟值为当前计数值10 while(1) { OLED_ShowNum(2,5,alarm,10); OLED_ShowNum(1,5,RTC_GetCounter(),10); Delay_ms(500); //stm32待机如果外挂模块还在运行的话依然耗电所以stm32待机前应该把能关闭的外挂模块都关闭 OLED_Clear();//以OLED为例待机后清屏只有唤醒后程序从头开始运行后才会显示。 PWR_EnterSTANDBYMode();//进入待机模式闹钟触发和WKUP引脚上升沿时会唤醒程序从头开始执行。 //从头开始执行程序会自动执行SystemInit()函数选择HSE时钟不需要像停止模式那种手动开启 } }