良许Linux教程网 干货合集 STM32学习笔记 | RTC日历基础应用问题分析

STM32学习笔记 | RTC日历基础应用问题分析

RTC,即实时时钟(Real-Time Clock),在许多电子系统中都会使用实时时钟。

每个STM32芯片都内建有RTC模块,它是一个独立的计数器/定时器,具有计数、时钟和闹钟等功能。

STM32 RTC基础内容

STM32内部集成的RTC实际上类似于一个TIM计数器,但与TIM有一些差别,例如供电来自备份区域,可作为低功耗模式的自动唤醒单元等等。

在STM32芯片中,F1系列除外,通常具备日历功能的BCD寄存器。除了这一点,其他系列的RTC都类似,因此本文以F4系列RTC为例进行讲述。

  1. RTC时钟源

RTC本身不具备输出时钟信号的功能,类似于TIM,由内部或外部晶体振荡器提供时钟源。

通常情况下,低速外部晶体振荡器(LSE)的频率为32.768kHz,或低速内部晶体振荡器(LSI)提供时钟源。对于高精度需求,应选择外部晶体振荡器,因为内部晶体振荡器具有较大误差。

当然,也可以使用高速外部晶体振荡器(HSE)的分频信号作为时钟源,但该时钟源具有最高频率限制。

image-20231127223109893
image-20231127223109893

2. RTC日历

RTC的日历功能算是一个比较重要的功能,但是在早期的F1系列中不具备该功能,需要结合软件计算才能实现日期和时间的功能。

除F1系列的RTC自生具备日历功能,即具有日期、时间、亚秒等于日历相关的寄存器,只需要直接读取寄存器即可获取日历信息。

同时,系统可以自动将月份的天数补偿为 28、 29(闰年)、 30 和 31 天。并且还可以进行夏令时补偿。

3. RTC闹钟

RTC闹钟功能也是一个比较实用的功能,大部分RTC都具有两个可编程的闹钟:闹钟A和闹钟B。

RTC闹钟可产生中断信号,也可以产生闹钟输出信号。

4. RTC自动唤醒

有的产品需要周期性唤醒,比如间隔5秒唤醒一次休眠的芯片。

RTC自动唤醒由 16 位可编程自动重载递减计数器生成,通过 WUTE 位可扩展至17位。如果频率为1Hz,则自动唤醒时间可以 1s 到 36h 左右。

以上是重点知识点,更多细节请查阅芯片对应的参考手册。

STM32 RTC 参数配置

STM32 的RTC使用比较方便,不像TIM各种复杂的关系,可以通过STM32CubeMX很简单就能使用RTC的各项功能。

下面以F4、Cube配置日历为例。

**1. *配置*时钟源

image-20231127223126890
image-20231127223126890

2. 配置分频值

通过32.768kHz信号得到1Hz分辨率,可参考例程默认分频配置:

32768/128/256 = 1.

备注:从0开始分频,所以配置的分频值需要减一:127 = 128 – 1, 255 = 256 – 1.

3. 初始化时间和日期

通过Cube工具初始化时间、日期以及格式:

image-20231127223130687
image-20231127223130687

以上就是通过Cbue工具配置的参数,生成的代码:

static void MX_RTC_Init(void)
{
  /* USER CODE BEGIN RTC_Init 0 */
  /* USER CODE END RTC_Init 0 */

  RTC_TimeTypeDef sTime = {0};
  RTC_DateTypeDef sDate = {0};

  /* USER CODE BEGIN RTC_Init 1 */
  /* USER CODE END RTC_Init 1 */

  /** Initialize RTC Only 
  */
  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 */
  /* USER CODE END Check_RTC_BKUP */

  /** Initialize RTC and set the Time and Date 
  */
  sTime.Hours = 0x0;
  sTime.Minutes = 0x0;
  sTime.Seconds = 0x0;
  sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  sTime.StoreOperation = RTC_STOREOPERATION_RESET;
  if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
  {
    Error_Handler();
  }
  sDate.WeekDay = RTC_WEEKDAY_MONDAY;
  sDate.Month = RTC_MONTH_JANUARY;
  sDate.Date = 0x1;
  sDate.Year = 0x0;

  if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
  {
    Error_Handler();
  }
  /** Enable the WakeUp 
  */
  if (HAL_RTCEx_SetWakeUpTimer(&hrtc, 0, RTC_WAKEUPCLOCK_RTCCLK_DIV16) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN RTC_Init 2 */
  /* USER CODE END RTC_Init 2 */
}

RTC通过Cube工具配置比较省心,如果使用标准外设库进行配置,就需要注意很多细节,简单参考官方提供例程。

STM32 RTC 常见问题

STM32内部RTC模块应用场景相对简单,不像TIM有复杂的配置以及关联性。但使用RTC仍需要注意一些细节问题。

问题一:RTC时间不准

有不少工程师都遇到过RTC计数一天,相差几秒甚至几十秒的情况。导致时间不准最根本的原因是时钟源,还有时钟分频值。

低速内部晶振(LSI)的误差相对较大,特别是温差变化较大的环境。

还有关于时钟分频值,上面已经提到了分频128,实际配置参数应该为127.

解决办法:使用更高精度低速外部晶振、校正、软件配置正确分频值。

问题二:RTC时钟配置失败

RTC的供电来源备份区域电源,操作RTC之前,需要使能后备区域操作。如果没有这一步操作,你会发现操作低速时钟、RTC可能会失败。

当然,出现这种情况,一般是使用标准外设库配置导致的失败。

解决办法:使用Cube工具,或参考官方例程初始化代码。

问题三:RTC日历不更新的问题

在我们的RTC应用中,经常有人反映在做日历数据读取操作时发现日历不更新的情形。其实,STM32 RTC的日历寄存器由两个组成,为了保证读取时间点的一致性,先读时分秒然后读日期做为一个完整的日历读取操作。在读取TIME【时分秒】后,硬件会将当前日历数据锁住,直到DATE【年月日】寄存器被读取后释放。否则会遇到读取日历时发生数据不更新的情况。

解决办法:对于RTC日历的读取要注意读取动作的完整性,读了TIME还要读取DATE才算一个完整操作,以保持读取时间的一致性。

以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !

137e00002230ad9f26e78-265x300
本文由 良许Linux教程网 发布,可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。
良许

作者: 良许

良许,世界500强企业Linux开发工程师,公众号【良许Linux】的作者,全网拥有超30W粉丝。个人标签:创业者,CSDN学院讲师,副业达人,流量玩家,摄影爱好者。
上一篇
下一篇

发表评论

联系我们

联系我们

公众号:良许Linux

在线咨询: QQ交谈

邮箱: yychuyu@163.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部