如前文所述,HAL库默认是不用RTC的计数器来保存日期的,而是保存到RTC句柄中的DateToUpdate结构体中。为了在系统复位后能够正确恢复日期,可以将日期保存到备份区的某个寄存器中,供复位后读取以恢复日期。在系统运行期间,RTC计数器是持续计时的,获取日期或时间时都会将超过24小时的部分这算为日期,自动更新DateToUpdate,同时从RTC计数器扣除相应的秒数。备份区中的日期无需频繁更新,一般在关机前更新一下即可。为了避免忘记手动更新,我们可以通过PVD的掉电保护功能来实现。原理很简单:关机时,电压下降,触发PVD掉电中断,在中断服务程序的回调函数中更新并保存日期到BKP寄存器即可。详述如下:

使能PVD中断

PVD属于PWR的组成部分。可能是由于PWR比较简单,STM32CubeIDE中没有将之作为独立外设。只在NVIC中提供了一个中断设置选项。配置也很简单,如下图所示,点击NVIC,勾选PVD interrupt through EXTI Line 16,即可开启PVD中断。中断优先级默认即可。图形化界面能配置的参数就这些。其他参数配置,要到代码中实现。

供电线路电流速断保护实验数据(利用PVD中断实现掉电保护)(1)

图1. 开启PVD中断

配置PVD

PVD初始化配置函数如下。该函数可以放置于main.c中,在main()函数前声明一下,然后main()函数中调用一下即可。

void HQ_PWR_Init(void) { PWR_PVDTypeDef hpvd; hpvd.PVDLevel = PWR_PVDLEVEL_7; //2.(n 2)V max2.9 hpvd.Mode = PWR_PVD_MODE_ITFALLING; //Powr down reset HAL_PWR_ConfigPVD(&hpvd); /* Enable the PVD Output */ HAL_PWR_EnablePVD(); }

配置方法很简单,只需指定PVD电压和触发方式。由于是掉电保护,所以这里选择的是FALLING。PVDLevel越高,掉电后备份数据的时间越充裕,但若电压不稳也有可能导致误触发。根据供电情况,尽量往高处设,最高2.9V。

编写中断回调函数

关机时电压下降,电平穿越PVDLevel时触发PVD中断,依次调用PVD_IRQHandler、HAL_PWR_PVD_IRQHandler和HAL_PWR_PVDCallback()。前两个函数STM32CubeIDE为我们自动生成好了。只需实现最有一个回调函数即可。代码如下:

void HAL_PWR_PVDCallback(void) { if ((hpvd.Mode&0x00000002U) == 0x00000002U) { HQ_RTC_BKUPDate(&hrtc); LEDG=LON; //For test only, comment out after successful debugging } }

函数很简单,if语句检测一下是不是掉电。库函数中定义了一个PVD_FALLING_EDGE,其值为0x00000002U。如果是掉电,则调用前文所述的HQ_RTC_BKUPDate函数更新备份区中的日期。在rtc.c或main.c中调用一下前文所述的HQ_RTC_RestoreDate即可恢复日期。

由于断电保护是个瞬间事件,板子掉电后也无法通过仿真器观察中断执行情况。回调函数中设置了一个点亮绿色LED的指令,用来判断保护代码是否被执行。

功能测试

驱动程序写入板子以后,只留一个便于开关的电源供电。按电源开关关闭电源,观察绿色LED是否闪一下。如果观察到现象,说明保护代码被成功执行。回到代码,注释掉点亮LED的代码。掉电后是靠电容供电的,电量十分珍贵,要尽一切可能避免浪费。

点灯测试可以作为PVD调试手段,比如追踪保护代码执行情况。

总结

PVD中断主要用来在意外断电时执行一些挽救操作,比如备份数据、启用备用方案等。这个例子虽然简单,但包括了配置和测试的主要步骤。其他功能可以按需添加。

断电后完全是靠电容供电,所以应该尽量减少不必要的操作,提高保护代码的执行效率。如果电量实在不够,可以考虑外接一个合适的电容来适当延长断电后的“抢救”时间。

,