STM32 HAL库 RTC实时时钟打印时间日期 掉电不清零 CubeMX

CubeMX配置

启用HSE和HSI

在这里插入图片描述

启用RTC和Calendar功能,选择内部唤醒

在这里插入图片描述

设置参数

在这里插入图片描述

  • Hour Format:小时格式(12小时或24小时制)
  • Asynchronous Predivider value:异步分频系数
  • Synchronous Predivider value:同步分频系数
    异步分频系数和同步分频系数共同决定RTC的频率。当使用32.768KHz的LSE时,RTC分频后的时钟频率为 f = 32.768 K H z ( A P V + 1 ) ∗ ( S P V + 1 ) f = \frac{32.768KHz}{(APV+1)*(SPV+1)} f=(APV+1)(SPV+1)32.768KHz,当APV=127,SPV=255时, f = 1 H z f=1Hz f=1Hz,即RTC时钟周期为1秒。
  • Data Format:二进制或BCD码

剩下的就不讲了,很容易看懂

  • Wake Up Clock:定期唤醒时钟的频率
  • Wake Up Counter:定期唤醒的计数值。设置为0时,实际寄存器写入值为1,即每1秒钟触发一次唤醒中断

启用唤醒中断

在这里插入图片描述

时钟设置

在这里插入图片描述
注意想要RTC在掉电情况下继续计时的话建议启用LSE(外部低速时钟)。RTC时钟源一般可选LSE、LSI或HSE,但是LSI精度较低,且可能发生温漂。分频后的HSE可作没有LSE时的备选。

启用USART

在这里插入图片描述

MDK部分编写(打印时间日期至串口)

重定向printf至串口

#include <stdio.h>

int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}

While(1)

获取RTC日期和时间的这部分代码可以在唤醒中断里写(确保唤醒是一秒钟一次),也可以在While(1)里写。

  while (1)
  {
  RTC_TimeTypeDef gTime;
  RTC_DateTypeDef gDate;

  HAL_RTC_GetTime(&hrtc,&gTime,RTC_FORMAT_BIN);
  HAL_RTC_GetDate(&hrtc,&gDate,RTC_FORMAT_BIN);

  printf("%04d-%02d-%02d-%02d\r\n",2000 + gDate.Year,gDate.Month,gDate.Date,gDate.WeekDay);
  printf("%02d:%02d:%02d",gTime.Hours,gTime.Minutes,gTime.Seconds);
  printf("\r\n");
      
  HAL_Delay(1000);

  }

注意HAL_RTC_GetTime必须在HAL_RTC_GetDate前面,同理SetTime也必须在SetDate前面。HAL库官方已经在这四个函数的定义里写得很明白了(但是不少人似乎不知道):

“You must call HAL_RTC_GetDate() after HAL_RTC_GetTime() to unlock thevalues in the higher-order calendar shadow registers to ensure consistency between the time and date values. Reading RTC current time locks the values in calendar shadow registers until current date is read to ensure consistency between the time and date values.”
“必须在 HAL_RTC_GetTime() 之后调用 HAL_RTC_GetDate() 来解锁高阶日历影子寄存器中的值,以确保时间和日期值之间的一致性。读取 RTC 当前时间会锁定日历影子寄存器中的值,直到读取当前日期为止 确保时间和日期值之间的一致性。”

编译,下载
在这里插入图片描述

MDK部分编写(掉电后RTC不清零)

上面那种方法虽然能很简单的实现RTC输出时间和日期的功能,但是当RTC断电或者系统复位后,RTC会重新初始化,回到最开始的时间。要想RTC在掉电后仍能继续计时、再次上电后还能保持准确的时间,必须满足两个要求:

  • VBAT网络必须连接到可靠的电源(如纽扣电池)
  • 代码中RTC被正确初始化

为了方便,我们重写一遍HAL库里的SetTime和SetDate函数:


HAL_StatusTypeDef rtc_set_time(uint8_t hour, uint8_t min, uint8_t sec)
{
    RTC_TimeTypeDef rtc_time_handle;

    rtc_time_handle.Hours = hour;
    rtc_time_handle.Minutes = min;
    rtc_time_handle.Seconds = sec;
    rtc_time_handle.TimeFormat = 0;
    rtc_time_handle.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
    rtc_time_handle.StoreOperation = RTC_STOREOPERATION_RESET;

    return HAL_RTC_SetTime(&hrtc, &rtc_time_handle, RTC_FORMAT_BIN);
}


HAL_StatusTypeDef rtc_set_date(uint8_t year, uint8_t month, uint8_t date, uint8_t week)
{
    RTC_DateTypeDef rtc_date_handle;

    rtc_date_handle.Date = date;
    rtc_date_handle.Month = month;
    rtc_date_handle.WeekDay = week;
    rtc_date_handle.Year = year;

    return HAL_RTC_SetDate(&hrtc, &rtc_date_handle, RTC_FORMAT_BIN);
}

我们的思路是,通过备份寄存器BKUP_DRx的值来判断RTC是否是第一次被初始化。如果RTC是第一次被初始化,那么通过rtc_set_time和rtc_set_date向RTC写入初始值;如果RTC不是第一次初始化,那么在HAL_RTC_init()后直接退出MX_RTC_init(),让RTC继续工作。

重写后的函数:

void MX_RTC_Init(void)
{
  hrtc.Instance = RTC;
  hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
  hrtc.Init.AsynchPrediv = 127;
  hrtc.Init.SynchPrediv = 255;
  hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
  hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
  hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
  if (HAL_RTC_Init(&hrtc) != HAL_OK)
  {
    Error_Handler();
  }

  /* USER CODE BEGIN Check_RTC_BKUP */

  #define RTC_DEFINE_CODE (0x1818)		//定义后备寄存器状态值

  if (HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR0) != RTC_DEFINE_CODE)		//如果DR0读取值不为0x1818
  {
    HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR0,(uint16_t)RTC_DEFINE_CODE);	//向DR0写入0x1818,表明已被初始化
    rtc_set_time(15, 30, 0);	//设置初始时间
    rtc_set_date(24, 3, 25, 1);		//设置初始日期

    __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&hrtc, RTC_FLAG_WUTF);
  if (HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 0, RTC_WAKEUPCLOCK_CK_SPRE_16BITS) != HAL_OK)
  {
    Error_Handler();
  }
  }
  return;
}

注意,在调试程序前务必保证DR0是空值,可以先跑一个空白只有让DR0清零功能的的例程让DR0清零。不然可能会出bug。

CubeMX5.3版本前的固件包可能会碰到掉电一整天后日期计数不正确的情况,可以尝试更新一下固件包,或是参考这两篇文章:文章1 文章2

编译,下载
在这里插入图片描述
15:54:32时开发板断电,间隔十秒后再次上电,可以看到RTC计时正确。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值