首页 - 通讯 - STM32实时时钟(RTC)基础教程

STM32实时时钟(RTC)基础教程

2023-10-01 11:05

目录

前言

RTC 框图

STM32实时时钟电路

功能需要

STM32CubeMx配置RTC

配置 RCC

配置RTC

配置时间、闹钟、唤醒

启用中断

设置中断优先级

功能代码实现

STM32Cude生成RTC初始化

自定义触发警报的次数

重写周期性唤醒回调函数

重写闹钟中断功能


前言

在做51单片机项目时,如果需要记录年月日时分秒,就会在51单片机上附加一个DS1302时钟芯片,加上时间芯片的外围电路。但在STM32F407中,就不再需要这样做了,因为STM32内部已经集成了年月日时分秒的时钟电路——即实时时钟(RTC)

RTC 框图

下图是RTC的框图。箭头部分是实时时钟的基本部分,包括时钟源、预分频器、影子寄存器、引脚复用输出。此外,还有两个闹钟、定期唤醒、入侵检测和时间戳。

STM32实时时钟电路

开发板上有低速外部时钟源 - 32.768Khz。

功能需要

1) 配置当前时间

时间可以采用 24 小时格式或 12 小时格式。默认为 24​​ 小时格式。配置时间时,也会设置日期格式,是BCD还是二进制。建议使用二进制,直接填写时间值即可。

2)配置闹钟(每10秒触发一次闹钟中断)

3)设置周期唤醒(唤醒时间1s),可输出低电平。

STM32CubeMx配置RTC

配置 RCC

由于RTC使用外部时钟源,因此在时钟配置中需要使用低速外部时钟源。

配置RTC

配置时间、闹钟、唤醒

配置24小时格式、二进制格式的时间(2022年5月2日12:19:50);设置闹钟(由于闹钟每10s触发一次中断,因此小时和分钟被阻塞,但秒不被阻塞);设置Periodic时钟,周期为1Hz,不需要计数,即每1秒触发一次;如果计数值为1,则每2秒触发一次中断。

6 {IMG_6: Ahr0CHM6LY9PMY53CC5JB20VAW1NLWJSB2CUY3NKBMLTZY5JBI8WZJU2MTQ5MZDG0MZJJODRHYZU4MJEGQ0ZI5WBMC =/}

启用中断

设置中断优先级

功能代码实现

STM32Cude生成RTC初始化

void MX_RTC_Init(void)
{

  /* 用户代码开始 RTC_Init 0 */

  /* 用户代码结束 RTC_Init 0 */

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

  /* 用户代码开始 RTC_Init 1 */

  /* 用户代码结束 RTC_Init 1 */

  /** 仅初始化 RTC
  */
  hrtc.Instance = RTC;
  hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
  hrtc.Init.AsynchPrediv = 127;
  hrtc.Init.SynchPrediv = 255;
  hrtc.Init.OutPut = RTC_OUTPUT_WAKEUP;
  hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
  hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
  if (HAL_RTC_Init(&hrtc) != HAL_OK)
  {
    Error_Handler();
  }/* 用户代码开始 Check_RTC_BKUP */

  /* 用户代码结束 Check_RTC_BKUP */

  /** 初始化RTC并设置时间和日期
  */
  sTime.Hours = 12;
  sTime.分钟 = 19;
  sTime.Seconds = 50;
  sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  sTime.StoreOperation = RTC_STOREOPERATION_RESET;
  if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
  {
    Error_Handler();
  }
  sDate.WeekDay = RTC_WEEKDAY_MONDAY;
  sDate.Month = RTC_MONTH_MAY;
  sDate.日期 = 2;
  sDate.Year = 22;

  if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
  {
    Error_Handler();
  }

  /** 启用警报A
  */
  sAlarm.AlarmTime.Hours = 0;
  sAlarm.AlarmTime.分钟 = 0;
  sAlarm.AlarmTime.Seconds = 10;
  sAlarm.AlarmTime.SubSeconds = 0;
  sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
  sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS|RTC_ALARMMASK_MINUTES;
  sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
  sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
  sAlarm.AlarmDateWeekDay = 1;
  sAlarm.Alarm = RTC_ALARM_A;
  if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK)
  {
    Error_Handler();
  }

  /** 启用唤醒
  */
  if (HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 0, RTC_WAKEUPCLOCK_CK_SPRE_16BITS) != HAL_OK)
  {
    Error_Handler();
  }
  /* 用户代码开始 RTC_Init 2 */

  /* 用户代码结束 RTC_Init 2 */

}

自定义触发警报的次数

重写周期性唤醒回调函数

注:

1)一定要先读时间,再读日期,否则会出错;

2) 即使不需要日期数据,也必须读取日期,否则会发生错误。

void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{
   RTC_TimeTypeDef sTime ={0};
   RTC_DateTypeDef sDate={0};字符str[40] = {0};
    
    
    //1)一定要先读取Time,再读取Date,否则会出错;即使不需要日期数据,也必须读取日期,否则会发生错误。
    if((HAL_RTC_GetTime(hrtc,&sTime,RTC_FORMAT_BIN)!=HAL_OK)|| (HAL_RTC_GetDate(hrtc,&sDate,RTC_FORMAT_BIN)!=HAL_OK))
    {
           返回;
    }
   
    sprintf(str,"RTC 时间 = %4d 年%2d 月%2d 日 \r\n",2000+sDate.Year,sDate.Month,www.gsm-guard.net);
    HAL_UART_Transmit(&huart1,(const uint8_t *)str,strlen(str),100);
    
    sprintf(str,"RTC 时间 = %2d 小时 %2d 分钟 %2d 秒 \r\n",sTime.Hours,sTime.Minutes,sTime.Seconds);
    HAL_UART_Transmit(&huart1,(const uint8_t *)str,strlen(str),100);
  
    
    
}

重写报警中断功能

void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
    字符str[40] = {0};
    sprintf(str,"报警触发次数: %d \r\n",++alarmTrigger);
    HAL_UART_Transmit(&huart1,(const uint8_t *)str,strlen((const char *)str),100);


}