前言: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中斷,那麼這時候需要進行數據備份處理或者進行低電量提醒。
如果直接切斷電源,進入中斷只能維持很短很短的時間,連一句打印信息也無法完整輸出。解決這個問題,需要在電源輸入點加大電容,當掉電的時候由電容提供電源維持芯片運行一段時候,以做緊急數據保存。所選用電容的參數影響掉電後芯片維持運行的時間,根據掉電中斷處理所需的時間長短來選用電容。
<< 騏驥一躍,不能十步;駑馬十駕,功在不捨。———荀子 >>