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中斷,那麼這時候需要進行數據備份處理或者進行低電量提醒。

如果直接切斷電源,進入中斷只能維持很短很短的時間,連一句打印信息也無法完整輸出。解決這個問題,需要在電源輸入點加大電容,當掉電的時候由電容提供電源維持芯片運行一段時候,以做緊急數據保存。所選用電容的參數影響掉電後芯片維持運行的時間,根據掉電中斷處理所需的時間長短來選用電容。

 

 

 

<< 騏驥一躍,不能十步;駑馬十駕,功在不捨。———荀子 >>

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