最近在做一个项目需要用到掉电检测,然后保存数据,发现stm自带有PVD功能,就拿来用一下做个记录吧。本文测试基于stm32f407板子。
一、PVD功能介绍
有时在一些应用中,我们需要检测系统是否掉电了,或者要在掉电的瞬间需要做一些处理。STM32就有这样的掉电检测机制——PVD(Programmable Voltage Detecter),即可编程电压检测器。通过PVD我们可以设定一个基准电压,当芯片的供电电压高于或低于该基准电压时便产生PVD中断,我们可以在PVD中断里做一些处理。
下面是PVD输出的时序图:
PVD这个功能使用的不多,官方也没有太多的解释,主要在使用的时候最好加上一个存储的电容,以便程序能执行完中断程序。
在M3与M4权威指南中找到了这个功能寄存器对应的检测电压:
二、代码验证
在HAL库里面是有PVD相关代码的,这里直接调用就行:
/* PVD可编程电源检测器初始化配置函数*/
void PVD_Config(void)
{
/* 配置PWR时钟 */
__HAL_RCC_PWR_CLK_ENABLE();
/* 配置中断优先级,使能PVD中断 */
HAL_NVIC_SetPriority(PVD_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(PVD_IRQn);
/* 设置PVD电平,设置中断类型:低于设置电平产生上升沿,高于设置电平产生下降沿 */
PWR_PVDTypeDef sConfigPVD;
sConfigPVD.PVDLevel = PWR_PVDLEVEL_7; // LEVEL_0 - 2.0V
sConfigPVD.Mode = PWR_PVD_MODE_IT_FALLING; //电源欠压产生中断
HAL_PWR_ConfigPVD(&sConfigPVD) ;
/* 使能PVD */
HAL_PWR_EnablePVD();
}
这里可以设置PVD是欠压还是恢复产生中断,也可以两个都设置,有以下模式:
/** @defgroup PWR_PVD_Mode PWR PVD Mode
* @{
*/
#define PWR_PVD_MODE_NORMAL 0x00000000U /*!< basic mode is used */
#define PWR_PVD_MODE_IT_RISING 0x00010001U /*!< External Interrupt Mode with Rising edge trigger detection */
#define PWR_PVD_MODE_IT_FALLING 0x00010002U /*!< External Interrupt Mode with Falling edge trigger detection */
#define PWR_PVD_MODE_IT_RISING_FALLING 0x00010003U /*!< External Interrupt Mode with Rising/Falling edge trigger detection */
#define PWR_PVD_MODE_EVENT_RISING 0x00020001U /*!< Event Mode with Rising edge trigger detection */
#define PWR_PVD_MODE_EVENT_FALLING 0x00020002U /*!< Event Mode with Falling edge trigger detection */
#define PWR_PVD_MODE_EVENT_RISING_FALLING 0x00020003U /*!< Event Mode with Rising/Falling edge trigger detection */
/**
* @}
*/
这里我只使用了欠压的中断回调函数,其他的也可以参考下面被注释掉的代码:
/* PVD可编程电源检测器中断回调函数*/
void HAL_PWR_PVDCallback(void)
{
uint8_t flash_buf[0x4]={0};
for(int i=0; i<4; i++)
{
flash_buf[i] = i+1;
// printf("flash_buf[%d]:%0.2X\r\n",i,flash_buf[i]);
}
fal_partition_erase(fal_partition_find("para"),0,4);
fal_partition_write(fal_partition_find("para"),0,flash_buf,4);
rt_kprintf("pvd power off\r\n");
// PWR_PVDTypeDef sConfigPVD;
// if(__HAL_PWR_GET_FLAG(PWR_FLAG_PVDO)) //判断是 欠压 OR 电压恢复
// {
// /* 配置判断 电源恢复的参考电平 */
// sConfigPVD.PVDLevel = PWR_PVDLEVEL_7; //LEVEL_6 - 2.9V
// sConfigPVD.Mode = PWR_PVD_MODE_IT_RISING_FALLING;
// HAL_PWR_ConfigPVD(&sConfigPVD);
//
// /* 当VDD低于设定阈值(欠压) 时执行的代码, */
//
// }
// else
// {
// /* 配置 判断电源欠压的参考电平 */
// sConfigPVD.PVDLevel = PWR_PVDLEVEL_0; //LEVEL_0 - 2.0V
// sConfigPVD.Mode = PWR_PVD_MODE_IT_RISING_FALLING;
// HAL_PWR_ConfigPVD(&sConfigPVD);
//
// /* 当VDD高于设定阈值(电源恢复)时执行的代码 */
// rt_kprintf("pvd power on\n");
//
// }
}
还有就是中断函数,库里面没有给出来,需要自己添加上:
void HAL_PWR_PVD_IRQHandler(void)
{
/* Check PWR Exti flag */
if(__HAL_PWR_PVD_EXTI_GET_FLAG() != RESET)
{
/* PWR PVD interrupt user callback */
HAL_PWR_PVDCallback();
/* Clear PWR Exti pending bit */
__HAL_PWR_PVD_EXTI_CLEAR_FLAG();
}
}
void PVD_IRQHandler(void)
{
HAL_PWR_PVD_IRQHandler();
}
验证结果:
验证我这个板子是可以在中断的时候将数据写入内存的。