STM32 可编程电压监测器(PVD)

1)PVD = Programmable Votage Detector 可编程电压监测器   它的作用是监视供电电压,在供电电压下降到给定的阀值以下时,产生一个中断,通知软件做紧急处理。在给出表格的上半部分就是可编程的监视阀值数据。当供电电压又恢复到给定的阀值以上时,也会产生一个中断,通知软件供电恢复。供电下降的阀值与供电上升的PVD阀值有一个固定的差值,这就是表中的VPVDhyst(PVD迟滞)这个参数,通过列出的PVD阀值数据可以看到这个差别。引入这个差值的目的是为了防止电压在阀值上下小幅抖动,而频繁地产生中断。   
    2)POR = Power On Reset 上电复位;PDR = Power Down Reset 掉电复位。  POR的功能是在VDD电压由低向高上升越过规定的阀值之前,保持芯片复位,当越过这个阀值后的一小段时间后(图中的"滞后时间"或表中的"复位迟滞"),结束复位并取复位向量,开始执行指令。这个阀值就是表中倒数第4行(min=1.8,typ=1.88,max=1.96)。  POR的功能是在VDD电压由高向低下降越过规定的阀值后,将在芯片内部产生复位,这个阀值就是表中倒数第3行(min=1.84,typ=1.92,max=2.0)。     3)可以看到POR比PDR大了0.04V,这就是表中倒数第2行,VPDRhyst(PDR迟滞)=40mV。   
    4)从上面的第2张图可以看到,当VDD上升越过POR阀值时,内部并不马上结束复位,而是等待一小段时间(Reset temporization),这就是表中的最后一行TRSTTEMPO,它的典型数值是2.5ms。  这个滞后时间是为了等待供电电压能够升高到最低可靠工作电压以上,我们看到POR阀值最小只有1.8V,最大也只有1.96V,都低于数据手册中给出的最低可靠工作电压2.0V,所以这个滞后时间是十分必要的,如果供电电压上升缓慢,尤其是从1.8V升到2.0V以上超过1~2.5ms,则很可能造成上电复位后MCU不能正常工作的情况。   
    STM32内部自带PVD功能,用于对MCU供电电压VDD进行监控。通过电源控制寄存器中的PLS[2:0]位可以用来设定监控电压的阀值,通过对外部 电压进行比较来监控电源。当条件触发,需要系统进入特别保护状态,执行紧急关闭任务:对系统的一些数据保存起来,同时对外设进行相应的保护操作。  操作流程:   
    1)、系统启动后启动PVD,并开启相应的中断。  
    PWR_PVDLevelConfig(PWR_PVDLevel_2V8); // 设定监控阀值  
    PWR_PVDCmd(ENABLE); // 使能PVD  
    EXTI_StructInit(&EXTI_InitStructure);   
    EXTI_InitStructure.EXTI_Line = EXTI_Line16; // PVD连接到中断线16上  
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //使用中断模式   
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Raising;//电压低于阀值时产生中断  
    EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 使能中断线  
    EXTI_Init(&EXTI_InitStructure); // 初始   
    EXTI_InitStructure.EXTI_Trigger的赋值可选项:  
    EXTI_Trigger_Rising---表示电压从高下降到低于设定阀值时产生中断;  
    EXTI_Trigger_Falling---表示电压从低上升到高于设定阀值时产生中断;   
    EXTI_Trigger_Rising_Falling---表示电压上升或下降越过设定阀值时都产生中断。   
2)、当工作电压低于设定阀值时,将产生PVD中断,在中断程序中进行相应的处理:  
void PVD_IRQHandler(void) 
{   
    EXTI_ClearITPendingBit(EXTI_Line16);  
    …… // 用户添加紧急处理代码处  
}
-----------------------------------------------------------------------------------搬运-------------------------------------------------------------------------------------------
亲测:
01 u32 num = 0;
02  
03 void PWR_PVD_Init(void)
04 {  
05     NVIC_InitTypeDef NVIC_InitStructure;
06     EXTI_InitTypeDef EXTI_InitStructure;
07      
08     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//使能PWR时钟
09  
10     NVIC_InitStructure.NVIC_IRQChannel = PVD_IRQn;           //使能PVD所在的外部中断通道
11     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级1
12     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;       //子优先级0
13     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;          //使能外部中断通道
14     NVIC_Init(&NVIC_InitStructure);
15      
16     EXTI_StructInit(&EXTI_InitStructure);
17     EXTI_InitStructure.EXTI_Line = EXTI_Line16;             //PVD连接到中断线16上
18     EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;     //使用中断模式
19     EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;  //电压低于阀值时产生中断
20     EXTI_InitStructure.EXTI_LineCmd = ENABLE;               //使能中断线
21     EXTI_Init(&EXTI_InitStructure);                         //初始
22      
23     PWR_PVDLevelConfig(PWR_PVDLevel_2V8);//设定监控阀值
24     PWR_PVDCmd(ENABLE);//使能PVD    
25 }
26  
27 void PVD_IRQHandler(void)
28 {
29     EXTI_ClearITPendingBit(EXTI_Line16);//清中断
30      
31     num = BKP_ReadBackupRegister(BKP_DR10);
32     num++;
33      
34     //用户添加紧急处理代码处
35     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);//使能PWR和BKP外设时钟
36     PWR_BackupAccessCmd(ENABLE);//使能后备寄存器访问
37  
38     BKP_WriteBackupRegister(BKP_DR10, (u8)num);//启动界面

39 }




再补点东西:
掉电中断里能存多少数据,能成多长时间一直是我比较关心的问题,在这里我测试了一下,也提供了一个简单的测试方法,可以粗略的获知。

1、测试RTC后备存储器存数据的速度

01 void PVD_IRQHandler(void)
02 {   
03     EXTI_ClearITPendingBit(EXTI_Line16);//清中断
04      
05     vTaskEndScheduler();//关闭调度器
06      
07     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR , ENABLE);//使能PWR和BKP外设时钟
08     PWR_BackupAccessCmd(ENABLE);//使能后备寄存器访问
09  
10     while(1)
11     {
12         power_time++;
13         RTC_WriteBackupRegister(RTC_BKP_DR14, power_time);
14     }
15 }

重上电之后, power_time = 171534,也就是说在2.8V掉到2V的时间内能读写171534次那么多,当然这个跟你设计的电路有绝对的关系,这个就根据具体自己的情况去测试吧。(事实证明RTC后备存储器的读写速度是很快的)

2、测试掉电的时间
01 void PVD_IRQHandler(void)
02 {   
03     EXTI_ClearITPendingBit(EXTI_Line16);//清中断
04      
05     vTaskEndScheduler();//关闭调度器
06      
07      
08     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR , ENABLE);//使能PWR和BKP外设时钟
09     PWR_BackupAccessCmd(ENABLE);//使能后备寄存器访问
10      
11  
12     while(1)
13     {
14         power_time++;
15         RTC_WriteBackupRegister(RTC_BKP_DR14, power_time);
16         Dellayus(2);//1.2us
17     }
18 }
重上电之后,power_time = 40496,也就是说在2.8V掉到2V的需要大约33~40ms左右(当然这是我的电路的掉电时间),这个需要具体自行测试。

注意:这里测试的是STM32F207的RTC,用这个存储一些应急数据还是足够的,不建议用FLASH存数据,因为FLASH读写操作需要高压,不确定2~2.8V操作是否稳定,但是STM32手册上说单片机的工作电压到2V还是可以工作的。

01 /*******************************************************************************
02 * 函数名   : Dellayu
03 * 描述    : 延时函数(局部使用),调用一次延时的时间:
04 *             72M下是1us,120M下是0.6us
05 * 参数    : usec
06 * 返回值   : 无
07 *******************************************************************************/
08 __asm int Dellayu(u32 usec)
09 {
10     ALIGN
11     PUSH.W {r1} //2时钟周期
12     MOV r1,#18  //1时钟周期
13     MUL r0,r1   //1时钟周期
14     SUB r0,#3   //1时钟周期
15 loop
16     SUBS r0,#1  //1时钟周期
17     BNE loop    //如果跳转则为3个周期,不跳则只有1个周期
18     POP {r1}    //2时钟周期
19     BX lr       //3个时钟周期
20     //总共所用周期为(usec*4)-4,此处减4主要用于抵消调用此函数的消耗时钟周期(传参1时钟,BLX跳转3时钟)
21 }

http://www.openedv.com/posts/list/39501.htm




你可能感兴趣的:(STM32 可编程电压监测器(PVD))