上节的代码运行后,如果中途有掉电,则再次打开串口后显示的时间会回到初始值,就像下图这样
针对这个问题我花了蛮多时间寻找原因,也有很多意见众说纷纭,最后还是回到正点原子,看到了问题所在HAL库设置了一个BKP寄存器保存标志,每次单片机启动时都读取这个寄存器并判断是不是预先设定的值。如果不是就初始化RTC并设置时间,再设置标志为预期值;如果是预期值就跳过初始化和时间设置,继续执行后面的程序。
解决办法就很简单了,就是在RTC的初始化函数MX_RTC_Init(void)
中改写代码,如果BKP寄存器的保存标志是预先设置的值,就跳过这一步,继续读取时间,应该可以解决时间回到初始值的问题。
void MX_RTC_Init(void)
{
/* USER CODE BEGIN RTC_Init 0 */
RTC_DateTypeDef datebuff; //定义一个datebuff的日期结构体
/* USER CODE END RTC_Init 0 */
...
...
/* USER CODE BEGIN RTC_Init 1 */
__HAL_RCC_BKP_CLK_ENABLE(); //开启后备区域时钟
__HAL_RCC_PWR_CLK_ENABLE(); //开启电源时钟
/* USER CODE END RTC_Init 1 */
...
...
/* USER CODE BEGIN Check_RTC_BKUP */
if(HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR1)!=0xA0A0) //这里就是在检查寄存器是不是预先设定的值,如果不是,就按照STM32CubeMX默认的设置往下走。这个值是任意定的
{
sTime.Hours = 0x19; //第一次设置时间
sTime.Minutes = 0x59;
sTime.Seconds = 0x30;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
{
Error_Handler();
}
DateToUpdate.WeekDay = RTC_WEEKDAY_SUNDAY; //第一次设置日期
DateToUpdate.Month = RTC_MONTH_JUNE;
DateToUpdate.Date = 0x12;
DateToUpdate.Year = 0x22;
if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BCD) != HAL_OK)
{
Error_Handler();
}
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, 0xA0A0); //这里就是将这个寄存器的标志设为刚才的那个值,下次掉电后就不会进入到这里来了
/* USER CODE END Check_RTC_BKUP */
else{
if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK)
{
Error_Handler();
}
__HAL_RTC_SECOND_ENABLE_IT(&hrtc,RTC_IT_SEC); //开启RTC时钟秒中断
}
main.c则不需要修改任何代码,再来编译看下效果
掉电后的时间没有回复到初始值,但是日期却变得很怪异了,变成了00年0月0日,即year
,month
,date
都清0了。所以时间问题解决了,但日期问题又跑出来了。
由于我的串口屏项目里是需要显示日期的,所以必须想办法把这个问题也解决了。查阅了大量资料后,定位问题在于HAL库没有把日期换算为计数器的值,掉电后就不会计数了。针对这个问题的解决,会在后续章节详述。
文章评论