STM32 RTC实时时钟,上电对时并在串口打印

一、RTC原理简介

      RTC (Real Time Clock):实时时钟。STM32F4 的 RTC,是一个独立的 BCD 定时器/计数器。 STM32F4 的 RTC 提供一个日历时钟(包含年月日时分秒信息)、两个可编程闹钟(ALARM A 和 ALARM B)中断,以及一个具有中断功能的周期性可编程唤醒标志。 RTC 还包含用于管理低功耗模式的自动唤醒单元。两个 32 位寄存器(TR 和 DR) 包含二进码十进数格式(BCD) 的秒、 分钟、小时(12 或 24 小时制) 、星期、日期、月份和年份。此外, 还可提供二进制格式的亚秒值。STM32F4 的实时时钟(RTC)相对于 STM32F1 来说,改进了不少,自带了日历功能,让软件编程更加简单。

      RTC 模块和时钟配置是在后备区域,无论器件状态如何(运行模式、低功耗模式或处于复位状态) ,只要保证后备区域供电正常,RTC 便不会停止工作,所以通常会在后备区域供电端加一个纽扣电池,即使主电源停止供电,后备电源也会启动供电,从而保证 RTC 时钟不停的运行,只有当主电源和后备纽扣电池都没有电的时,RTC 才停止工作。RTC结构框图如图所示:

       可把 RTC 结构框图分成 以下5 个子模块:

    (1) 标号 1: 时钟源

       RTC 时钟源(RTCCLK)可通过时钟控制器从 LSE 时钟、LSI 振荡器时钟以及HSE 时钟三者中选择。其中使用最多的是 LSE,即外部低速时钟, 通常选择一个大小为 32.768KHZ 的晶振提供(配合 2 个谐振电容)。LSI 是芯片内部的 30KHZ晶体,精度比较低,对于时钟精度要求高的场合不建议使用。HSE_RTC 由 HSE 分频得到,最高是 4M。

     (2) 标号 2: 预分频器

       预分频器 PRER 由 7 位的异步预分频器 APRE 和 15 位的同步预分频器 SPRE组成。为最大程度地降低功耗,预分频器分为 2 个可编程的预分频器。一个通过RTC_PRER寄存器的 PREDIV_A 位配置的 7 位异步预分频器,另一个通过RTC_PRER 寄存器的 PREDIV_S 位配置的 15 位同步预分频器。异步预分频器时钟计算公式为:

fCK_APRE=fRTC_CLK/(PREDIV_A+1)

      ck_apre 时钟用于为RTC亚秒递减计数器(RTC_SSR)提供时钟。当该计数器计数到 0 时, 会使用 PREDIV_S 的内容重载 RTC_SSR 。而 PREDIV_S 一般为255,这样,我们得到亚秒时间的精度是:1/256 秒,即 3.9ms 左右,有了这个亚秒寄存器 RTC_SSR,就可以得到更加精确的时间数据。同步预分频器时钟计算公式为:

fCK_SPRE=fRTC_CLK/[(PREDIV_S+1)*(PREDIV_A+1)]

        ck_spre 时钟既可以用于更新日历,也可以用作 16 位唤醒自动重载定时器的时基 。通 常 的 情 况 下,我 们 会 选 择 LSE 作 为 RTC 的 时 钟 源,即fRTC_CLK==32.768KHZ。然后经过预分频器 PRER 分频生成 1HZ 的时钟用于更新日历。使用两个预分频器分频的时候,为了最大程度的降低功耗,我们一般把异步预分频器(PREDIV_A)设置成较大的值,为了生成 1HZ 的同步预分频器时钟CK_SPRE,通常我们设置:PREDIV_A=0X7F,即 128 分频;PREDIV_S=0XFF,即 256分频,代入上述同步预分频器时钟计算公式即可得到 fCK_SPRE=1Hz。RTC_CLK 经过预分频器后,有一个 512HZ 的 CK_APRE 和 1 个 1HZ 的CK_SPRE,这两个时钟可以成为校准的时钟输出 RTC_CALIB,RTC_CALIB 最终要输出则需映射到 RTC_AF1 引脚,即 PC13 输出,用来对外部提供时钟。

    (3) 标号 3: 实时时钟和日历

       STM32F4 的 RTC 时间信息是存放在日历时间( RTC_TR)和日期( RTC_DR)寄存器中, 可以读取也可以写入。亚秒值存放在 RTC 亚秒寄存器(RTC_SSR)中,只能读取不能写入。这些寄存器都具有写保护,所以需要使能后备寄存器访问功能才能读取或写入时间。RTC_TR 时间寄存器存放的是时分秒,寄存器说明如下:

         RTC_DR 日期寄存器存放的是年月日星期,寄存器说明如下:

       RTC_SSR 亚秒寄存器存放的是 RTC 亚秒值, 寄存器说明如下:

       STM32F4 的 RTC 日历时间(RTC_TR)和日期(RTC_DR)寄存器可通过与PCLK1( APB1 时钟)同步的影子寄存器来访问,这些时间和日期寄存器也可以直接访问,这样可避免等待同步的持续时间。每隔两个 RTC_CLK 周期,当前日历值便会复制到影子寄存器,并将 RTC_ISR寄存器的 RSF 位置 1。在停机和待机模式下不会执行复制操作。退出这两种模式时,影子寄存器会在最长 2 个 RTCCLK 周期后进行更新。

       当应用读取日历寄存器时,它会访问影子寄存器的内容。也可以通过将RTC_CR 寄存器的 BYPSHAD 控制位置 1 来直接访问日历寄存器。默认情况下,该位被清零,用户访问影子寄存器。读取 RTC_TR 和 RTC_DR 来得到当前时间和日期信息,不过需要注意的是:时间和日期都是以 BCD 码的格式存储的,读出来要转换一下,才可以得到十进制的数据。

      (4) 标号 4: 可编程闹钟

       RTC 单元提供两个可编程闹钟,即闹钟 A 和闹钟 B。可通过将 RTC_CR 寄存器中的 ALRAE 和 ALRBE 位置 1 来使能可编程闹钟功能。如果日历亚秒、秒、分钟、小时、日期或日分别与闹钟寄存器 RTC_ALRMASSR/RTC_ALRMAR 和RTC_ALRMBSSR/RTC_ALRMBR 中编程的值相匹配,则 ALRAF 和 ALRBF 标志会被置为 1。可 通 过 RTC_ALRMAR 和 RTC_ALRMBR 寄 存 器 的 MSKx 位 以 及RTC_ALRMASSR 和 RTC_ALRMBSSR 寄存器的 MASKSSx 位单独选择各日历字段。可通过 RTC_CR 寄存器中的 ALRAIE 和 ALRBIE 位使能闹钟中断。闹钟 A 和闹钟B(如果已通过 RTC_CR 寄存器中的位 OSEL[0:1] 使能)可连接到 RTC_ALARM输出,RTC_ALARM 最终连接到 RTC 的外部引脚RTC_AF1。可通过RTC_CR 寄存器的 POL 位配置 RTC_ALARM 极性, 可以为输出高电平或低电平。

      (5) 标号 5: 周期性自动唤醒

        STM32F4 的 RTC 不带秒钟中断了,但是多了一个周期性自动唤醒功能。周期性唤醒功能由 16 位可编程自动重载递减计数器生成,唤醒定时器范围可扩展至 17 位,可用于周期性中断/唤醒。可通过 RTC_CR 寄存器中的 WUTE 位来使能此唤醒功能。唤醒定时器的时钟输入可以是:

        唤醒定时器的时钟输入可以是:2、4、8 或 16 分频的 RTC 时钟 (RTCCLK)。

        当 RTCCLK 为 LSE (32.768 kHz) 时,可配置的唤醒中断周期介于 122 μ s和 32 s 之间,且分辨率低至 61 μ s。

        ck_spre(通常为1Hz内部时钟) 当 ck_spre 频率为1Hz 时,可得到的唤醒时间为 1s 到 36h 左右,分辨率为 1 秒。这一较大的可编程时间范围分为两部分:

        — WUCKSEL [2:1] = 10时为1s到18h。

        — WUCKSEL [2:1] = 11时约为18h到36h。

       在后一种情况下,会将 2^16 添加到 16 位计数器当前值(即扩展到17 位,相当于最高位用 WUCKSEL [1]代替)。

        完成初始化序列后, 定时器开始递减计数。在低功耗模式下使能唤醒功能时,递减计数保持有效。此外,当计数器计数到 0 时,RTC_ISR 寄存器的 WUTF 标志会置 1,并且唤醒寄存器会使用其重载值(RTC_WUTR 寄存器值)自动重载。之后必须用软件清零 WUTF 标志。通过将 RTC_CR2 寄存器中的 WUTIE 位置 1来使能周期性唤醒中断时,它会使器件退出低功耗模式。如果已通过 RTC_CR 寄存器中的位 OSEL[0:1] 使能周期性唤醒标志,则该标志可连接到 RTC_ALARM 输出。可通过 RTC_CR 寄存器的 POL 位配置 RTC_ALARM 极性。系统复位以及低功耗模式(睡眠、停机和待机)对唤醒定时器没有任何影响,所以唤醒定时器,可以用于周期性唤醒 STM32F4。

       (7) 标号 7: 入侵检测

       STM32F4 的 RTC 有两个入侵检测输入引脚可用,分别是 RTC_AF1( PC13)和RTC_AF2( PI8)。这两个输入既可配置为边沿检测,也可配置为带过滤的电平检测。备份寄存器(RTC_BKPxR) 包括 20 个 32 位寄存器,用于存储 80 字节的用户应用数据。这些寄存器在备份域中实现,可在 VDD 电源关闭时通过 VBAT 保持上电状态。备份寄存器不会在系统复位或电源复位时复位,也不会在器件从待机模式唤醒时复位。只有当发生入侵检测事件时,备份寄存器将复位。通过将RTC_TAFCR 寄存器中的 TAMPIE 位置 1,可在发生入侵检测事件时生成中断。

二、CubeMx工程创建

 功能要求:STM32 RTC对时,串口打印当前时间。

1. 芯片选型(本文选用STM32F407IGT6)

2. SYS配置(启用SW下载接口)

3. RCC配置(开启外部低速时钟和高速时钟)

4. 串口配置(UART4,波特率115200,8bits) 

开启串口中断。

5. RTC时钟配置

6. GPIO配置(用于验证系统运行状态) 

 三、关键代码实现

//rtc.c
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 */
  // 2024/1/17 add 
  //检查后备寄存器
  uint32_t iSetFlag = 0x5053;// 这个0x5053值自己随意
  if(iSetFlag != HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR0))
  {
     /* USER CODE END Check_RTC_BKUP */

     /** Initialize RTC and set the Time and Date
     */
    sTime.Hours = 0x0e;
    sTime.Minutes = 0x0b;
    sTime.Seconds = 00;
    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_THURSDAY;
    sDate.Month = RTC_MONTH_JANUARY;
    sDate.Date = 18;
    sDate.Year = 54;

    if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
    {
      Error_Handler();
    }
  /* USER CODE BEGIN RTC_Init 2 */
    // 设置完时钟,设置标志
     HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR0, iSetFlag);
  /* USER CODE END RTC_Init 2 */

   }
   else
   {    //设置完时钟,设置标志
        RTC_TimeTypeDef sTime;  //获取一次时间显示
        HAL_StatusTypeDef status = HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
 
        RTC_DateTypeDef sDate;
        status = HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
   }
  
}

//主函数
#include "main.h"
#include "rtc.h"
#include "usart.h"
#include "gpio.h"
#include "stdio.h"

/* Private define ------------------------------------------------------------*/
#define LENGTH 3

RTC_DateTypeDef GetData;  //获取日期结构体
 
RTC_TimeTypeDef GetTime;   //获取时间结构体


void SystemClock_Config(void);

int main(void)
{
  
  uint8_t RxBuf[LENGTH];

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

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


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

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_RTC_Init();
  MX_UART4_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */
  LED_BLUE_ON;
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    /* Get the RTC current Time */
	/*************2024/1/18 add*******************/
	  HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);
      /* Get the RTC current Date */
      HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN);
	  
	if(HAL_UART_Receive(&huart4,RxBuf,sizeof(RxBuf),500) == HAL_OK)
	//if(HAL_UART_Receive(&huart4,RxBuf,sizeof(RxBuf),300) == HAL_OK)
	{
	 LED_BLUE_OFF;
	 LED_GREEN_ON;
	 printf("系统当前时间为:\r\n");
      /* Display date Format : yy/mm/dd */
     printf("%02d-%02d-%02d %02d:%02d:%02d\r\n",1970 + GetData.Year, GetData.Month, GetData.Date,GetTime.Hours, GetTime.Minutes, GetTime.Seconds);
      /* Display time Format : hh:mm:ss */
     // printf("%02d:%02d:%02d\r\n",GetTime.Hours, GetTime.Minutes, GetTime.Seconds);
     printf("\r\n");
	}   
     HAL_Delay(400);
	 LED_GREEN_OFF;
	 LED_BLUE_ON;
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

四、上板验证 

 1. 程序烧录。

2. 串口功能验证。 

四、完整源代码链接 

https://download.csdn.net/download/hyp12347/88760634

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值