用CUBEMX生成STM32F103xx RTC时钟例程,系统掉电后日期参数会重置,时间参数正常运行,前提是加了电池供电。
直接上解决方案。
大体思路就是在第一次配置日期时间的时候把日期值加入后备区域寄存器保存起来,我用的是103RBT6,所以后备区域寄存器只有 10个,这里要注意一下。断电或复位以后
if(HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR1)!= 0x5051)这条语句不成立,所以从else处执行,先把保存在后备区域寄存器的日期值 提取出来,再更新到设置日期这个函数里,此函数HAL_RTC_SetDate(),由于掉电或复位后,有电池在供电,所以实时时钟计数器是一直在更新的,HAL_RTC_SetDate()函数会根据计数器的值对日期做校准。开启了秒中断,所以在中断回调函数里再把日期值写入到后备寄存器中,实时 更新。
以下是修改后的CUBE生成的RTC初始化源码和中断回调函数。
定义的全局变量。
RTC_TimeTypeDef time; //时间结构体参数
RTC_DateTypeDef datebuff; //日期结构体参数
static void MX_RTC_Init(void)
{
/* USER CODE BEGIN RTC_Init 0 */
/* USER CODE END RTC_Init 0 */
RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef DateToUpdate = {0};
/* USER CODE BEGIN RTC_Init 1 */
__HAL_RCC_BKP_CLK_ENABLE(); //开启后备区域时钟
__HAL_RCC_PWR_CLK_ENABLE(); //开启电源时钟
/* USER CODE END RTC_Init 1 */
/**Initialize RTC Only
*/
hrtc.Instance = RTC;
hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
hrtc.Init.OutPut = RTC_OUTPUTSOURCE_NONE;
if (HAL_RTC_Init(&hrtc) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN Check_RTC_BKUP */
if(HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR1)!= 0x5051)
{
/* USER CODE END Check_RTC_BKUP */
/**Initialize RTC and set the Time and Date
*/
sTime.Hours = 0x23;
sTime.Minutes = 0x59;
sTime.Seconds = 0x50;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
{
Error_Handler();
}
DateToUpdate.WeekDay = RTC_WEEKDAY_MONDAY;
DateToUpdate.Month = RTC_MONTH_DECEMBER;
DateToUpdate.Date = 0x31;
DateToUpdate.Year = 0x18;
if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BCD) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN RTC_Init 2 */
printf("%d\r\n",DateToUpdate.Month);
__HAL_RTC_SECOND_ENABLE_IT(&hrtc,RTC_IT_SEC); //开启RTC时钟秒中断
datebuff = DateToUpdate; //把日期数据拷贝到自己定义的data中
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, 0x5051);//向指定的后备区域寄存器写入数据
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, (uint16_t)datebuff.Year);
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR3, (uint16_t)datebuff.Month);
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR4, (uint16_t)datebuff.Date);
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR5, (uint16_t)datebuff.WeekDay);
printf("%d %d %d %d \r\n",datebuff.Year,datebuff.Month,datebuff.Date,datebuff.WeekDay);
}
else
{
datebuff.Year = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR2);
datebuff.Month = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR3);
datebuff.Date = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR4);
datebuff.WeekDay = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR5);
DateToUpdate = datebuff;
if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK)
{
Error_Handler();
}
__HAL_RTC_SECOND_ENABLE_IT(&hrtc,RTC_IT_SEC); //开启RTC时钟秒中断
}
getRealTime();
/* USER CODE END RTC_Init 2 */
}
void getRealTime(void)
{
HAL_RTC_GetTime(&hrtc, &time, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &datebuff, RTC_FORMAT_BIN);
printf("中断%d %d %d %d \r\n",datebuff.Year,datebuff.Month,datebuff.Date,datebuff.WeekDay);
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, (uint16_t)datebuff.Year);
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR3, (uint16_t)datebuff.Month);
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR4, (uint16_t)datebuff.Date);
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR5, (uint16_t)datebuff.WeekDay);
printf("%d-%d-%d-%d-",datebuff.Year,datebuff.Month,datebuff.Date,datebuff.WeekDay);
printf("%d:%d:%d\r\n",time.Hours,time.Minutes,time.Seconds);
}
void HAL_RTCEx_RTCEventCallback(RTC_HandleTypeDef *hrtc)
{
if(hrtc->Instance == RTC)
{
getRealTime();
}
}
有问题或者测试有错误的朋友可以在评论区留言,一起讨论共同进步。
这是CUBE配置截图。
附件不会上传。