STM32CubeMX之RTC电子钟

STM32CubeMX之RTC电子钟

1.简介

实时时钟是一个独立的定时器。 RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。

2.特性

● 可编程的预分频系数:分频系数最高为220。
● 32位的可编程计数器,可用于较长时间段的测量。
● 2个分离的时钟:用于APB1接口的PCLK1和RTC时钟(RTC时钟的频率必须小于PCLK1时钟频率的四分之一以上)。
● 可以选择以下三种RTC的时钟源:
─ HSE时钟除以128;
─ LSE振荡器时钟;
─ LSI振荡器时钟
● 3个专门的可屏蔽中断:
─ 闹钟中断,用来产生一个软件可编程的闹钟中断。
─ 秒中断,用来产生一个可编程的周期性中断信号(最长可达1秒)。
─ 溢出中断,指示内部可编程计数器溢出并回转为0的状态。

3.功能概述

RTC由两个主要部分组成(见下图)。第一部分(APB1 接口 )用来和APB1 总线相连。此单元还包含一组16位寄存器,可通过APB1 总线对其进行读写操作。 APB1 接口由APB1 总线时钟驱动,用来与APB1 总线接口。另一部分(RTC核心)由一组可编程计数器组成,分成两个主要模块。第一个模块是RTC的预分频模块,它可编程产生最长为1 秒的RTC时间基准TR_CLK。RTC的预分频模块包含了一个20位的可编程分频器(RTC 预分频器)。如果在 RTC_CR寄存器中设置了相应的允许位,则在每个TR_CLK周期中RTC产生一个中断(秒中断)。第二个模块是一个32位的可编程计数器,可被初始化为当前的系统时间。系统时间按TR_CLK周期累加并与存储在RTC_ALR寄存器中的可编程时间相比较,如果RTC_CR控制寄存器中设置了相应允许位,比较匹配时将产生一个闹钟中断。
在这里插入图片描述

4.RTC配置过程

必须设置RTC_CRL寄存器中的CNF位 ,使RTC进入配置模式后 ,才能写入RTC_PRL 、RTC_CNT、 RTC_ALR寄存器。另外,对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。仅当RTOFF状态位是’1’时,才可以写入RTC寄存器。

  • 配置过程:

1. 选择RTC时钟源
2. 查询RTOFF位,直到RTOFF的值变为’1’;
3.置CNF值为1 ,进入配置模式;
4.对一个或多个RTC寄存器进行写操作;
5.清除CNF标志位,退出配置模式;
6.查询RTOFF,直至RTOFF位变为’1’以确认写操作已经完成。仅当CNF标志位被清除时,写操作才能进行,这个过程至少需要3个RTCCLK周期;

5.软件设计

5.1 选择RTC时钟源

在这里插入图片描述

5.2 RTC配置

开启RTC功能,开启日历功能,设置时间和日期,设置预分频系数,产生秒中断。
在这里插入图片描述
在这里插入图片描述

5.3 配置RTC时钟源

  • RTC时钟产生可配置三种时钟源:
    外部高速时钟HSE(8MHZ)进行128分频(HSE/128);
    外部低速时钟LSE(32.768KHZ);
    内部低速时钟LSI(40KHZ);
    下面配置选择为外部低速时钟LSE,32.768KHZ作为RTC时钟源。
    在这里插入图片描述

6.生成代码

6.1 RTC初始化

由于RTC部分配置寄存器是处于后备区域,在有后备电池供电情况下,为了保证掉电后电子钟数据持续更新,我们需要开启后备驱动。

/* RTC init function */
void MX_RTC_Init(void)
{
  RTC_TimeTypeDef sTime = {0};
  RTC_DateTypeDef DateToUpdate = {0};

  /** Initialize RTC Only
  */
  hrtc.Instance = RTC;
  hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
  hrtc.Init.OutPut = RTC_OUTPUTSOURCE_ALARM;
  if (HAL_RTC_Init(&hrtc) != HAL_OK)
  {
    Error_Handler();
  }

  /* USER CODE BEGIN Check_RTC_BKUP */
  /*检查后备区域是否写入数据*/
  if(HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR1)==0x12)
  {
    return ;
  }
  else HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR1,0x12);//写入标志位,表示RTC时间配置好,防止重置时间
  /* USER CODE END Check_RTC_BKUP */

  /** Initialize RTC and set the Time and Date
  */
  sTime.Hours = 0;
  sTime.Minutes = 0;
  sTime.Seconds = 0;

  if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)//设置时间
  {
    Error_Handler();
  }
  DateToUpdate.WeekDay = RTC_WEEKDAY_MONDAY;
  DateToUpdate.Month = RTC_MONTH_JUNE;
  DateToUpdate.Date = 30;
  DateToUpdate.Year = 21;

  if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK)//设置日期
  {
    Error_Handler();
  }

}

6.2 开时钟,开RTC中断

void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle)
{
  if(rtcHandle->Instance==RTC)
  {
  /* USER CODE BEGIN RTC_MspInit 0 */

  /* USER CODE END RTC_MspInit 0 */
    HAL_PWR_EnableBkUpAccess();//电源接口时钟
    /* Enable BKP CLK enable for backup registers */
    __HAL_RCC_BKP_CLK_ENABLE();//后备域时钟
    /* RTC clock enable */
    __HAL_RCC_RTC_ENABLE();//RTC时钟

    /* RTC interrupt Init */
    HAL_NVIC_SetPriority(RTC_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(RTC_IRQn);
  /* USER CODE BEGIN RTC_MspInit 1 */
  HAL_RTCEx_SetSecond_IT(rtcHandle);//开启RTC中断
  /* USER CODE END RTC_MspInit 1 */
  }
}

6.3 RTC中断

void RTC_IRQHandler(void)
{
  /* USER CODE BEGIN RTC_IRQn 0 */
  RTC_TimeTypeDef sTime = {0};
  RTC_DateTypeDef DateToUpdate = {0};
  /* USER CODE END RTC_IRQn 0 */
  HAL_RTCEx_RTCIRQHandler(&hrtc);
  /* USER CODE BEGIN RTC_IRQn 1 */
	if(HAL_RTC_GetTime(&hrtc,&sTime,RTC_FORMAT_BIN)==HAL_OK)
	{
		printf("%d:%d:%d  ",sTime.Hours,sTime.Minutes,sTime.Seconds);
	}
	if(HAL_RTC_GetDate(&hrtc,&DateToUpdate,RTC_FORMAT_BIN)==HAL_OK)
	{
		printf("%d/%d/%d  星期:%d\r\n",DateToUpdate.Year,DateToUpdate.Month,DateToUpdate.Date,DateToUpdate.WeekDay);
	}
  /* USER CODE END RTC_IRQn 1 */
}

4.4 主体功能
主函数中实现OLED屏幕初始化、RTC电子钟初始化等;实现实时时间显示,可通过串口进行时间校准。

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM4_Init();
  MX_USART1_UART_Init();
  MX_RTC_Init();
  /* USER CODE BEGIN 2 */
  OLED_Init();
  OLED_Displey_Imag(48,0,32,32,(u8 *)android);
  Delay_Ms(500);
  Delay_Ms(500);
  OLED_Clear();//清屏
  flag=1;
  /* USER CODE END 2 */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)//轮询
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    if(usart1_flag)
    {
      printf("%s\r\n",usart1_buff_rx);
      if(usart1_buff_rx[0]== '*')
      {
        DateToUpdate.Year=(usart1_buff_rx[3]-'0')*10+(usart1_buff_rx[4]-'0')*1;//年
        DateToUpdate.Month=(usart1_buff_rx[5]-'0')*10+(usart1_buff_rx[6]-'0')*1;//月
        DateToUpdate.Date=(usart1_buff_rx[7]-'0')*10+(usart1_buff_rx[8]-'0')*1;//日

        sTime.Hours=(usart1_buff_rx[9]-'0')*10+(usart1_buff_rx[10]-'0')*1;
        sTime.Minutes=(usart1_buff_rx[11]-'0')*10+(usart1_buff_rx[12]-'0')*1;
        sTime.Seconds=(usart1_buff_rx[13]-'0')*10+(usart1_buff_rx[14]-'0')*1;
        printf("%d/%d/%d -- %d:%d:%d\r\n",DateToUpdate.Year,DateToUpdate.Month,DateToUpdate.Date,sTime.Hours,sTime.Minutes,sTime.Seconds);
        HAL_RTC_SetDate(&hrtc, &DateToUpdate,RTC_FORMAT_BIN);
        HAL_RTC_SetTime(&hrtc,&sTime,RTC_FORMAT_BIN);       
      }
      usart1_flag=0;
      usart1_count=0;
    }
  }
  /* USER CODE END 3 */
} 

7.示例效果

在这里插入图片描述
在这里插入图片描述

8.相关接口函数

//读取和写入后备域数据
uint32_t HAL_RTCEx_BKUPRead(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister)
HAL_RTCEx_BKUPWrite(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister, uint32_t Data)

//设置和获获取时间
HAL_StatusTypeDef HAL_RTC_SetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format)
HAL_StatusTypeDef HAL_RTC_GetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format)

//设置和获取日期
HAL_StatusTypeDef HAL_RTC_SetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format)
HAL_StatusTypeDef HAL_RTC_GetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format)

//设置RTC秒中断
HAL_StatusTypeDef HAL_RTCEx_SetSecond_IT(RTC_HandleTypeDef *hrtc)

参考示例:https://download.csdn.net/download/weixin_44453694/19938692


版权声明:本文为weixin_44453694原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。