stm32f103c8t6学习笔记(学习B站up江科大自化协)-PWR电源控制

PWR简介 

        ·PVD可用在电池供电或安全要求比较高的设备,如果供电电压在逐渐下降,在电压过低的情况下可能会导致内外电路出现不确定的错误。为了避免不必要的错误,可以在电源电压过低的情况下,提前发出警告并关闭较为危险的设备

        ·关闭的硬件越多越省电,不过唤醒就越麻烦

电源框图

        可将STM32内部的供电方案大致分为3部分:

        ·第一部分(最上边的):模拟部分供电,VDDA(VDD Analog)

        这部分电路供电的正极是VDDA,负极是VSSA,其中AD转换器还有两根参考电压的供电叫VREF+和VREF-,在引脚多的型号中会单独引出,在引脚少的设备(如c8t6)内部会接到VDDA和VSSA

        ·第二部分(中间的):数字部分供电,包括VDD供电区(左)和1.8V供电区(右)

        VDD供电区域的电压调节器降压到1.8V之后,提供给后边的1.8V供电区。STM32内部的关键电路基本是以1.8V低压运行的,当这些电路需要与外界交流的时候才会通过IO转换成3.3V。其中使用低压运行的目的是降低功耗,电压越低内部电路运行的功耗就越低

        ·第三部分(最下边的):后备供电VBAT(V Battery)

        RCC_BDCR是RCC寄存器,叫备份域控制寄存器,也是和后备区域有关的寄存器,可由VBAT供电。

        第二三部分中间有一个低电压检测器可以控制VBAT开关,VDD有电的时候由VDD供电,VDD没电时由VBAT供电

上电复位和掉电复位

         ·当VDD或VDDA电压过低时,内部电路直接产生复位,让stm32复位住不会乱操作

        ·在复位和不复位的界限之间设置了一个40mV的迟滞电压,大于上限POR(Power On Reset)时解除复位,小于下限PDR(Power Down Reset)时复位,是一个典型的迟滞比较器。设置两个阈值的作用,是为了防止电压在某个阈值附近波动时造成输出也来回抖动,

        ·复位信号时低电平有效,在前边后边电压过低时是复位的,中间电压正常不复位。

        ·关于POR、PDR和滞后时间可以参考数据手册(如下)

        下降沿PDR掉电复位的阈值下限典型值是1.88V,上升沿上电复位的阈值上限典型值是1.92V,1.92-1.88就是迟滞的阈值40mV。如果忽略迟滞的话,简单点说就是大于1.9上电,低于1.9掉电。

        最后一行是复位持续时间,典型时间是2.5ms 

可编程电压检测器

        ·简称PVD,也是用于检测VDD和VDDA的供电电压,和前边的区别在于PVD的阈值是可以程序指定的,可以自定义调节,根据手册,可选范围是2.2-2.9V左右,PVD上限和下限的迟滞电压是100mV,PVD的电压比上电掉电复位的电压高

        ·PVD触发后芯片还是能正常工作的,只不过是电源电压过低,可以对用户进行提醒。PVD的输出是正逻辑,电压过低时为1,电压正常时为0,这个信号可以去申请中断,在上升沿或下降沿时触发中断,PVD的中断申请是通过外部中断实现的,如果要使用PVD的话需要记得配置外部中断

        ·接到外部中断的还有RTC,RTC自己是由中断的,但是为什么还需要接到外部中断?由于低功耗模式设计的是只有外部中断可以唤醒停止模式,其他设备(USB、ETH等等,将其wakeup信号线接过来)也想唤醒停止模式的话都可以通过借道外部中断实现

低功耗模式

        ·在这个图中,从上到下的模式关闭的电路越来越多,也越来省电,也是越来越难唤醒

        ·关闭电路通常由两个做法,一个是关闭时钟,另一个是关闭电源,

        关闭时钟所有的运算和涉及时序的操作都会暂停,但是寄存器和存储器里保存的数据还可以维持不会丢失

        关闭电源就是电路直接断电,电路的操作和数据都会直接丢失,关闭电源会比关闭时钟更省电。图中电压调节器关就代表1.8V区域断电

睡眠模式:

        ·直接调用WFI或WFE即可进入,这两个是内核的指令,使用可以直接调用库函数,WFI(Wait For Interrupt等待中断),唤醒条件是任意中断,仍和外设发生任何中断时芯片都会立刻醒来,醒来一般第一时间处理中断函数。WFE(Wait For Event等待事件),这个事件可以是外部中断配置为事件模式,也可以是使能了中断但是没有配置NVIC,WFE唤醒醒来之后一般不需要进中断函数,直接从睡的地方继续运行

        ·睡眠模式对只讲CPU时钟关闭,程序不会继续运行,CPU不运行功耗就会降低,睡眠模式对其他电路没有任何操作

        ·一般可以在主循环的最后执行WFI、WFE,主循环执行一遍就睡眠,唤醒之后主循环会再执行一遍再睡眠,每唤醒一次主循环执行一遍

        ·如果在程序中执行点灯,灯点亮了进入睡眠,灯任然是亮的,GPIO引脚的电平在睡眠时是维持原样的

        ·唤醒事件可通过下述方式产生:

                ·在外设控制寄存器中使能一个中断,不在NVIC中使能,并且在内核的控制寄存器中SEVONPEND(Send Event On Pend)位,才能产生唤醒事件,在唤醒后要及时清除挂起位

                ·配置EXTI为事件模式 

停机模式:

        ·进入停机模式,先将SLEEPDEEP位置1,告诉CPU可以方向进入深度睡眠模式,

        PDDS这一位是用于区分是停机模式还是待机模式,PDDS = 0进入停机模式,PDDS = 1进入待机模式。要想进入停机模式要现将PDDS设置为0,

        LPDS用于设置最后的电压调节器是开启还是进入低功耗模式,LPDS = 1电压调节进入低功耗,LPDS = 0电压调节器开启。当把前边提到的位设置好了之后,再调用WFI或WFE芯片就可以进入停止模式了。

        停止模式的唤醒条件较为苛刻,因为在这个模式下芯片睡眠更深,关闭的东西更多。条件是任一外部中断,所有外设的中断都可以,以及前边提到的PVD、RTC闹钟、USB唤醒、ETH唤醒借道了外部中断,这四个信号也同样可以唤醒停止模式。

        停止模式对电路的操作有:关闭所有1.8V区的时钟,不仅CPU不能运行,外设也运行不了,正在定时的定时器会暂停,串口收发数据也会暂停,由于没关闭电源,CPU和外设的寄存器数据都是维持原状的。HSI和HSE的振荡器关闭,CPU和外设时钟都关闭的情况下,这两个高速时钟也没什么作用,所以会关闭。LSI内部低速时钟和LSE外部低速时钟并不会主动关闭,如果开启过这两个时钟可以继续运行。

        电压调节器可以开启或者选择低功耗模式,这个电压调节器是由LPDS位控制的,无论电压调节器是开启还是低功耗,都可以维持1.8V区域寄存器和存储器的数据内容,区别在于低功耗更省电,同时低功耗在唤醒时会花更多的时间,电压调节器开启的话更耗电一些但是唤醒更快

        ·睡眠模式和停止模式寄存器的内容都可以维持,唤醒后程序可以在暂停的地方继续运行

        ·高低电平维持暂停前一刻的状态

        ·程序默认在system_Init里的配置,是使用HSE外部高速时钟,通过PLL倍频得到72MHz主频,但是进入停止模式之后PLL和HSE都停止了,并且在退出停止模式的时候并不会自动帮我们再开启PLL和HSE,而是默认用HSI的8MHz作为主频,如果忽略这个问题会出现一个现象:程序刚上电的时候主频是72MHz,但是进入停止模式再唤醒的时候就变成8MHz的主频。在停止模式的唤醒之后第一时间就是重新启动HSE,配置主频为72MHz,只需调用System_Init即可

        ·电压调节器低功耗更省电,但是停止模式退出时会有一段额外的启动延时。 

待机模式:

        待机模式和停机模式类似,SLEEPDEEP置1,即将深度睡眠,PDDS置1表示即将进入待机模式,最后调用WFI或WFE就可以进入待机模式了。

        唤醒条件更为严格,普通外设的中断和外部中断都无法唤醒待机模式,只有指定的几个信号可以唤醒:

               ·WKUP引脚的上升沿,在引脚定义表里边可以看到WKUP的引脚位置在PA0

                 ·RTC闹钟事件,RTC闹钟可以唤醒待机模式,应用场景是芯片每隔一段时间工作一次

                ·NRST引脚上的外部复位,意思是按下复位键也可以唤醒

                ·IWDG独立看门狗复位

            待机模式对电路的操作:基本将能关的都关了,1.8V区域的时钟关闭,两个高速时钟关闭,电压调节器关闭,意味着1.8V区域的电源关闭,那么内部的存储器和寄存器数据全部丢失。同停止模式一样,并没有主动关闭LSI和LSE的低速时钟,因为这两个时钟需要维持RTC和独立看门狗的运行,所以不会关闭

        ·待机模式下唤醒,程序从头开始运行,因为待机模式把大部分电路的电源都断了,数据丢失,唤醒后程序无法继续运行,只能从头开始

        ·浮空输入对于输出而言,就是高阻态,假如提前点了灯,在进入待机模式之后无论这个灯市高电平点亮还是低电平点亮都会熄灭,GPIO对外不输出高低电平,也不流过电流 

模式选择:

        ·执行WFI和WFE指令后,STM32进入低功耗模式,也就是说这两个指令时开启低功耗的触发条件,配置其他的寄存器都需要在这两个指令之前。

        ·一旦WFI或WFE执行了,芯片要想知道进入哪种低功耗模式,会按这个流程图进行判断:

                ·首先看SLEEPDEEP位是1还是0,如果SLEEPDEEP位是0就是浅睡眠,对应睡眠模式,是1表示进入深度睡眠模式,对应停机或待机模式,

                ·在普通睡眠模式下,SLEEPONEXIT位 = 0 时,无论程序在哪里调用WFI/WFE,都会立刻进入睡眠,SLEEPONEXIT = 1时,执行WFI/WFE之后会等待中断退出,等待所有中断完成之后才进入睡眠。

                如果不在中断函数中调用WFI、WFE,实际上这两个功能的效果是一样的。可以将WFI、WFE放在主程序之中,主程序执行到的时候也代表中断处理完成了。如果想在中断函数中调用WFI、WFE,并且想中断结束后才睡眠,才需考虑(等待中断退出)这个模式

                ·进入深度睡眠模式,会继续判断PDDS这一位,如果PDDS = 0则进入停机模式,如果PDDS = 1则进入待机模式。

                在停机模式下会继续判断LPDS位,如果LPDS = 0,就是停机模式且电压调节器开启,LPDS = 1就是停机模式且电压调节器低功耗,电压调节器低功耗的特性是更省电,但是唤醒延迟更高

功能实现部分:

        ·实现功能前需要注意:如果文件图标带有钥匙标志,说明文件为只读,必须先解除只读才能修改程序

        ·解除只读的方法为:文件夹里找到文件 -->  文件  -->  右键  -->  取消只读  

        或者右键点击这个文件Open Contaning Folder直接跳转到文件所在的文件夹 

        进入文件夹之后点击属性

        将只读的勾去掉,然后回到keil里边看这个文件,可以发现小钥匙消失,意味着可以进入编辑状态

        ·芯片再三种低功耗的情况下是没办法下载程序的,下载成功后开始执行程序,芯片进入休眠时再次点击下载会报错。解决方法是:按住复位键不放,点击下载按钮并及时松开复位键。在低功耗情况下都需要以这种方式下载

        ·如果不小心禁用了调试端口,也可以按上边这个方法解决

修改主频

        ·修改主频不属于三种低功耗模式,但是是可以降低STM32的功耗的方法之一。

        ·这段代码第一行显示系统主频,第二行以1秒为周期闪烁running,由于正常系统主频是72MHz,但是降频为36MHz之后,运行时间变为原来的二倍

        ·修改主频在system_stm32f10x.c里边的文件里110行的位置配置时钟,将预留好的宏定义解除注释即可

接线图

 system_stm32f10x文件相关内容

        ·system_stm32f10x.c这两个文件提供了两个外部可调用的函数和一个外部可调用的变量,两个函数是SystemInit()和SystemCoreClockUpdate(),一个变量是SystemCoreClock

        SystemInit()用于配置时钟树,也是这个文件最主要的东西,这个函数使用HSE配置主频为72M。这个函数在复位之后执行main函数之前在启动文件里自动调用,所以main函数一进来就已经调用好了,无需操心。

        SystemCoreClock表示主频频率的值,如果想知道目前主频的值,直接显示这个变量即可

        SystemCoreClockUpdate()是用于更新SystemCoreClock这个变量的,因为这个变量只有最开始的一次赋值,后边如果更改了主频频率这个值是不会跟着自动变换的,所以需要调用这个函数,根据当前时钟树的配置更新

        ·如下图所示,如果使用的是VL超值系列,可选的主频只有两个,HSE的8M和24M,否则可以选择下边的8、24、36、48、56、72M,这里解除注释的是72M,所以主频默认的是72M

        ·简单的修改一个宏定义之后,是如何作用于电路的配置?首先找到SystemInit的函数,第一步是开启HSI,也就是默认使用内部的8M晶振,后边是各种disable和Reset,是为了恢复缺省配置,最后恢复完的时候调用SetSysClock()函数,

        ·进入SetSysClock()函数之后就可以看见宏定义可以修改主频的原理,这个函数实际上是一个分配函数,根据定义的不同宏定义,选择执行不同的配置函数,比如前边默认是解除了72M的注释,那就执行设置时钟72M的函数,

         ·进入SetSysClockTo72()函数才是配置时钟正式开始的部分,SetSysClockTo56和其他频率的时钟的配置内容完全一样,唯一的区别在于后边的锁相环的倍频不同(HSE * 倍频 = 输出频率)

                配置第一步是使能HSE外部高速时钟,

                第二步是循环等待HSERDY,或超时退出。

                接下来给HSEState置1或0,如果=1证明晶振启动成功,进入if,配置第一步是设置Flash等待,之后配置HCLK(AHB的时钟)、PCLK2(APB的时钟)和PCLK1(APB的时钟)的分频器,这里的分频分别设置为1、1、2,对应到时钟树就是如下图所示,如果SYSCLK是72M的话,AHB和APB2就是72M,APB1是36M

 

         ·往下边看到 #ifdef STM32F10X_CL部分内容的时候,CL是互联型,我们的是MD中容量型,所以看#else里边的内容。

        可以看到这部分内容是锁相环,HSE是8M,锁相环选择的是9倍频,最终锁相环输出就是72M,之后是使能锁相环,等待锁相环准备就绪,并选择锁相环的输出作为系统时钟 ,最终等待锁相环的输出成为系统时钟

        对应到时钟树就是,选择外部的8M晶振作为锁相环输入,锁相环执行9倍频,输出的72M选择为sysclk,这个是库函数默认配置,由systemInit执行相关操作。

        最后由一个else,写的是如果HSE启动失败,应用程序会有错误的时钟,用户可以在else里边加一些代码解决错误。如果HSE没接或者损坏,那么前边的代码都不执行,程序会默认使用前边的HSI内部8M时钟作为系统主频。也就是说,如果发现系统主频变成了8M,可能是外部晶振出现了问题,可以在else里边加代码,如果代码执行到else里边,那么确实是HSE出现了问题,

 

代码部分 

        ·调用下列代码,在OLED显示屏上边显示的内容是字符串 SYSCLK: 和系统主频 72000000,第二行闪烁RUNNING,周期为1秒

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"


int main()
{
	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_stmf10x.c文件里边修改频率,将 #define SYSCLK_FREQ_36MHz  36000000 解除注释,将 #define SYSCLK_FREQ_72MHz  72000000进行注释,随后编译烧录,发现原本以1秒为周期的字符串闪烁,速度变慢了一倍,并且显示的主频也变为了36000000

        ·修改主频之后涉及计时的代码都需要重新修改匹配,比如delay函数默认的是72M主频,在delay微秒时默认的是72,在72M的主频下delay的时间是正确的,降低主频后delay的时间不能自适应变化,如果想在任何主频下delay的时间都是正确的,那么可以使用SystemCoreClock这个变量做自适应,将这个变量带入计算即可

睡眠模式+串口发送+接收

        ·当收到一个字节的时候,中断触发,置标志位。主循环查询到标志位的时候,读取数据并用串口发送出去。收到数据后自动退出睡眠模式,执行一遍任务之后继续睡眠,空闲时芯片持续处于睡眠状态,降低系统功耗

        ·连接好串口后发送数据,发送数据给stm32,stm32成功接受数据并回传,现象和没使用睡眠模式的时候是一样的,区别的细节在于只有发送数据的时候,OLED才会显示一次running,空闲时芯片都在睡眠。

接线图

        ·加入现在要使用STM32做一个下位机,下位机接收电脑串口发送过来的指令,然后执行相应的功能。为了能随时响应指令,STM32需要时刻准备着,在主循环中不断检查标志位,但是如果一直不发送指令,那么主循环中的操作没什么意义,还费电。如果将代码放在中断里边,主循环是空的CPU也在不断耗电。

        对于这种靠中断触发,没中断就没有什么事的代码可以加入低功耗模式,没事的时候进入低功耗,中断来了再干活即可。对于实现以上功能,选择睡眠模式是比较好的选择,

代码部分

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"

uint8_t RXData;

int main()
{
	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(100);
		OLED_ShowString(2,1,"       ");
		Delay_ms(100);
		
		__WFI();//正好可以在带有中断的程序中修改 转入定义发现是一个CPU的汇编指令
		
	}
}


        编译烧录这部分代码之后发现,在串口助手中发送一个数据给stm32,显示屏会闪烁显示running,然后回传数据给串口助手。在没显示running的时候stm32是出于睡眠状态,发送完成之后再次进入睡眠状态,节约用电

        程序执行到WFI的时候开始睡眠,接收到数据的时候唤醒,唤醒后在再次开始新的while之前会进入USART中断,读取数据,置RXFLAG,清除RXNE标志位。然后进入主循环到 if 处判定成立,执行数据回传和显示在屏幕上的功能,之后running闪烁一次,然后程序到达WFI,CPU再次进入睡眠

停止模式+对射式红外传感期计次

        ·每遮挡一次,执行一次计次,也显示一次running,没有外部中断信号时,stm32处于休眠模式省点,

接线图

相关函数

//恢复缺省配置
void PWR_DeInit(void);
//使能后备区域的访问
void PWR_BackupAccessCmd(FunctionalState NewState);
//使能PVD功能 如果要使用PVD功能的话,先指定阈值 然后使能即可
void PWR_PVDCmd(FunctionalState NewState);
//配置PVD的阈值电压
void PWR_PVDLevelConfig(uint32_t PWR_PVDLevel);
//使能位于PA0位置的WKUP引脚 配合待机模式使用 待机模式可用WKUP引脚的上升沿唤醒
void PWR_WakeUpPinCmd(FunctionalState NewState);
//进入停止模式
void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry);
//进入待机模式
void PWR_EnterSTANDBYMode(void);
//获取标志位
FlagStatus PWR_GetFlagStatus(uint32_t PWR_FLAG);
//清除标志位
void PWR_ClearFlag(uint32_t PWR_FLAG);

        对于PWR_EnterSTOPMode()这句函数内部的工作流程,如下图可见,这个函数配置了各种寄存器和调用指令,全部完成,只需在主函数中调用这一个函数即可

        第一步读取PWR_CR寄存器放在临时变量里,

        第二步清除PDDS和LPDS位,其中清除PDDS代表选择停止模式,也就是PDDS=0,进入停机模式

        第三步,根据选择的参数选择LPDS位,如果选择调压器开启,那么LPDS=0,如果选择调压器低功耗,LPDS=1,

        第四步,把临时变量写入PWR_CR寄存器

        最后设置内核里的SLEEPDEEP位,这里 |= SLEEPDEEP的掩码,就是把SLEPPDEEP置1,

        配置完如上之后就可以调用WFI或WFE指令了

         在程序下边可以看到 if 判断是执行WFI还是WFE,执行到这芯片就会进入停止模式,程序暂停运行

        else{}下边还有一句函数,在停止模式唤醒之后才会执行到,才退出停止模式之后帮我们将SLEEPDEEP位清零了

代码

        编译烧录后,显示屏将显示计数次数,每当有中断信号时将会闪烁一次running,

        值得注意的是,烧录后的第一次复位,running的闪烁速度非常快,之后产生中断闪烁running时将会变慢,这是因为退出停止模式时HSI被选为系统时钟,

        在首次复位的时候,system_init里面配置的是HSE * 9倍频的72MHz,所以复位后第一次闪烁很快,之后进入停止模式再退出时,默认时钟就变成HSI了,之后程序的运行会明显变慢,解决方法是,在PWR_EnterSTOPMode()函数的后边加上SystemInit()即可

        注意:函数中如果加了delay函数会卡死,请注意尽量不要加delay

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "countsensor.h"

int main()
{
	OLED_Init();
	CountSensor_Init();

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
	
	OLED_ShowString(1,1,"counter:");
	while(1)
	{

		OLED_ShowNum(1,7,CountSensor_Get(),5);
		
		OLED_ShowString(2,1,"running");
		Delay_ms(100);
		OLED_ShowString(2,1,"       ");
		Delay_ms(100);
		
		//第一个参数是指定电压调节器在停止模式里的状态 是开启还是低功耗
		//第二个参数是选择WFI还是WFE指令进入停止模式
		PWR_EnterSTOPMode(PWR_Regulator_ON,PWR_STOPEntry_WFI);
	}
}

待机模式+实时时钟

        ·LSE外部低速时钟,如果没有RTC晶振或RTC晶振不起振,LSI在待机模式下也可以继续工作

        ·在进入待机模式之前,关闭外部链接的各个模块,以最大化省电。每隔10s唤醒一次,唤醒后执行一次任务后继续待机,

接线图

PWR_EnterSTANDBYMode这个函数:

        第一步:清除WKUP标志位

        第二步:选择STANDBY模式,实际上就是将PDDS置1,表示进入待机模式

        第三布:SLEEPDEEP置1,进入深度睡眠

        最后一步调用WFI模式进入待机模式

代码

        将下列代码烧录编译后发现,RUNNING闪烁一次,进入待机,此时CNT不会刷新,过一会闹钟触发,待机模式唤醒(时间约为3秒,程序中可设定),CNT和闹钟值刷新,RUNNING闪烁一次

        每次唤醒之后闹钟值重新设定,通过这一现象可以确定,待机模式唤醒之后,程序是从头开始运行的,因为闹钟设定的代码在while循环之前,如果不是从头开始闹钟也不会更新

        在进入待机模式后高速闹钟都会关闭,退出待机模式时程序从头开始运行,程序刚开始的时候自动调用system_Init初始化时钟,待机模式无需像停止模式一样自己调用system_Init

        在执行完PWR_EnterSTANDBYMode();这个代码进入待机模式之后,后边的代码将不会执行。待机模式退出程序从头开始,执行至此继续待机。

        在进入待机模式前要尽可能把外部挂载的模块都关掉

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyRTC.h"

//主要任务是
//1.设置RTC闹钟
//2.进入待机模式
//3.使用闹钟信号唤醒待机模式


int main()
{
	OLED_Init();
	MyRTC_Init();
	
	RCC_APB2PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE );//进入待机模式需要开启PWR外设
	
	OLED_ShowString(1,1,"CNT");//秒计数器
	OLED_ShowString(2,1,"ALR");//闹钟值
	OLED_ShowString(3,1,"ALRF");//闹钟标志位
	
	//由于无法读取寄存器,所以写入之前先将其存下来
	uint32_t Alarm = RTC_GetCounter() + 3;
	RTC_SetAlarm(Alarm);//这个闹钟寄存器时只写的,无法读
	OLED_ShowNum(2,6,Alarm,10);
	while(1)
	{		
		OLED_ShowNum(1,6,RTC_GetCounter(),10);
		OLED_ShowNum(3,6,RTC_GetFlagStatus(RTC_FLAG_ALR),1);
		
		OLED_ShowString(4,1,"running");
		Delay_ms(100);
		OLED_ShowString(4,1,"       ");
		Delay_ms(100);
		
		PWR_EnterSTANDBYMode();
	}
}

        在main函数中的while前边加上函数PWR_WakeUpPinCmd(ENABLE);使能后WKUP引脚会被强制配置为输入下拉。这个时候PA0引脚如果有一个上升沿,将会直接唤醒STM32,屏幕显示,验证了WKUP引脚上升沿可以唤醒STM32,也可以别的传感器信号接入唤醒STM32,

  • 111
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值