在实际工程运用中需要对突发情况作出及时的相应,通常都需要考虑当系统电压下降或断电时,需要对控制系统加以保护。这时候就需要在程序中加入系统电压监测(PVD)。供电电压降低到某一个电压值时,需要系统进入保护状态,执行紧急关闭任务(对系统数据进行保存,并对外设进行相应的保护操作)。传统单片机例如STC12C60S2,其自带A/D,可以利用A/D对工作电压进行检测,每隔一段时间进行比较,如果异常进入保护模式,进行相关的保护措施。但是这种方法不但会占用MCU处理时间,而且利用ADC也增加了系统的功耗。STM32就可以很完美的解决这一问题,其内部自带了一个可编程电压检测器(PVD),对VDD的电压进行监控可以通过电源控制寄存器PLS[ 2:0 ]位来设置监控电压的阀值,这样通过与VDD电压比较达到了监控电压的目的。电源控制状态寄存器(PWR_CSR)中的PVDO用来表明VDD是高于还是低于PVD的电压阀值。当VDD下降到PVD阀值以下或VDD上升到PVD阀值之上时,通过外部中断16线上升或下降边沿触发设置,产生PVD中断。在中断处理函数中做相应的保护措施。具体由以下两表所示。
表1 阀值与PVD输出关系
表2 具体寄存器参数
下面对上面2张图和表格中的数据做一个简要的解释:
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);
…… // 用户添加紧急处理代码处
}
(以上内容是摘自网上的,以下内容是开发后总结的,经过验证的)
/************************************************************************************************************************************************************/ 20111220
STM32中PVD的编程:开始时参照网上的资料和技术文档的内容,把基本的代码组织了,但是程序还是无法如意向的执行(无论是用查询方式、还是中断方式);网上很少有提到解决为什么不能执行的,没有更多的参考,于是只能慢慢调试;
调试:首先是看PVD监控的标志位能否置起来,用死循环一直检测;然后要是行的话,再去用中断的方式;
结果发现时标志位无法被置起来,后来再去网上查,对比自己的代码,发现,漏了一步没进行:就是PVD所对应的时钟没有使能;
加上去后,果然能置位了。
总结:细想,对于stm32的外设或者模块的操作(配置、使用),在前期的配置中,基本上都是需要使能相应的时钟,而这次也是因为这个原因而出错;所以下次的使用中需要注意这方面的问题。
PVD的具体的编程:
基本的初始化和配置:
/************************************************************************** /
//Function : void EXTI_Configuration(void)
//Description : configures;
//Input : none;
//Output : none
//created by : *************************************************************************/
void EXTI_Configuration(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_DeInit();
EXTI_StructInit(&EXTI_InitStructure);
EXTI_InitStructure.EXTI_Line = EXTI_Line16;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
/**************************************************************************
//Function : void PVD_NVIC_Configuration(void)
//Description :
//Input : none;
//Output : none
//created by
**************************************************************************/
void PVD_NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = PVD_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; :
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); //point it;cann't lose it;这个必须要加;
NVIC_Init(&NVIC_InitStructure);
}
//中断函数:
extern void dev_pvd_irq_handle(void);
void PVD_IRQHandler(void)
{
dev_pvd_irq_handle();
}
/**************************************************************************
//Function : void dev_pvd_irq_handle(void)
//Description : PVD handle function;
//Input : none;
//Output : none
//created by
**************************************************************************/
extern u8 is_power_on;
void dev_pvd_irq_handle(void)
{ :
EXTI_ClearITPendingBit(EXTI_Line16);//clear bit;
if(PWR_GetFlagStatus(PWR_FLAG_PVDO))
{
dev_misc_power_on(0);
}
}
//主函数中的操作:
Main()
{
… …
PVD_NVIC_Configuration();
EXTI_Configuration();
PWR_PVDLevelConfig(PWR_PVDLevel_2V9);//2.8V;added for PDV;//有范围的;
PWR_PVDCmd(ENABLE); //added for PDV;
… …
}
//(除了用中断的方式,也可以用查询的方式:)
if(PWR_GetFlagStatus(PWR_FLAG_PVDO))
{
… …
}