stm32之PVD可编程电压监测器(掉电保存数据)

前言:stm32系列提供了可编程电压检测器PVD,它是实时检测VDD的电压,当检测到电压低于或者高于PVD设置的阈值时,会想内核产生一个PVD中断(EXTI线中断)以使内核在复位前进行紧急处理。该电压阈值可通过PWR_CSR设置。

PVD可配置8个等级:

代码设计:

#include "stm32f10x.h"
#include "stdio.h"

static void EXTI_Configuration(void);
static void PVD_NVIC_Configuration(void);
static void USART1_Config(void);
static void Delay(__IO u32 nCount);

int main(void)
{	
        USART1_Config();//使用串口1来打印调试信息
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); //使能PVD电压检测模块的时钟
	
	//通过执行下面两个中断配置函数后,当VDD电压高于或者低于阈值时,就会进入PVD_IRQHandler中断
	EXTI_Configuration();//配置EXTI_Line16外部中断
	PVD_NVIC_Configuration();//PVD中断优先级
	
	PWR_PVDLevelConfig(PWR_PVDLevel_2V9);//设置PVD阈值
	PWR_PVDCmd(ENABLE);//使能PVD电压检测
	
	while(1)
	{
		Delay(0xfffff);
		printf("STM32正常工作中...\r\n");
		
		//去掉上面两个中断配置函数,也可以在while循环里不断查询PWR状态来判断VDD电压是否高于或低于阈值,如下
		#if 0
		if(PWR_GetFlagStatus(PWR_FLAG_PVDO)){ 
			printf("电压低于阈值.\r\n");
		}else{
			printf("电压高于阈值.\r\n");
		}
		#endif
	}
}

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_Falling;//上升沿和下降沿都触发
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);
}

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;
		
	NVIC_Init(&NVIC_InitStructure);
}

void USART1_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	//配置串口1(USART1)时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
	
        //配置串口1(USART1 Tx (PA.09))
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
  
	//配置串口1 USART1 Rx (PA.10)
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//串口1模式(USART1 mode)配置 
	USART_InitStructure.USART_BaudRate = 9600;//一般设置为9600;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No ;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Tx;
	USART_Init(USART1, &USART_InitStructure);
	
	USART_Cmd(USART1, ENABLE); //使能串口 
}

int fputc(int ch, FILE *f)//重写标准库的fputc函数
{
	//将Printf内容发往串口
	USART_SendData(USART1, (unsigned char) ch);
	while( USART_GetFlagStatus(USART1,USART_FLAG_TC)!= SET);	
	return (ch);
}

void Delay(__IO u32 nCount)	 //简单的延时函数
{
	for(; nCount != 0; nCount--);
} 

在stm32f10x_it.c文件加入:

void PVD_IRQHandler(void)
{
    if (EXTI_GetITStatus(EXTI_Line16) != RESET)
    {
       if(PWR_GetFlagStatus(PWR_FLAG_PVDO)==0) //高于阈值
       {                                         
          printf("进入PVD中断,电压高于阈值\r\n");
       }
       else                                    //低于阈值
       {
          printf("进入PVD中断,电压低于阈值\r\n");
       }      
       EXTI_ClearITPendingBit(EXTI_Line16);
    }
}

代码附带了不少注释,相信不难理解。编译下载到板子后,还需要一个可调电源来改变芯片的供电电压,当电压低于或者高于阈值的时候,就会进入PVD_IRQHandler中断,在PC端串口上位机可接受到进入中断打印的信息。

只要电压超过2.0v芯片就能正常工作,不是低于阈值就不能工作。所以在实际运用中,如果是用电池给芯片供电,当电池电量不足时,电池的供电电压就会下降,下降到低于阈值时就会触发PVD中断,那么这时候需要进行数据备份处理或者进行低电量提醒。

如果直接切断电源,进入中断只能维持很短很短的时间,连一句打印信息也无法完整输出。解决这个问题,需要在电源输入点加大电容,当掉电的时候由电容提供电源维持芯片运行一段时候,以做紧急数据保存。所选用电容的参数影响掉电后芯片维持运行的时间,根据掉电中断处理所需的时间长短来选用电容。

 

 

 

<< 骐骥一跃,不能十步;驽马十驾,功在不舍。———荀子 >>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章