STM32 RTC时钟读取时间

文章目录

  • 一、RTC简介
    • 1.1 RTC
    • 1.2 RTC特征
    • 1.3 RTC原理框图
    • 1.4 RTC工作流程
    • 1.5 RTC时钟选择
    • 1.6 RTC复位过程
    • 1.7 RTC中断
  • 二、CubeMX配置
    • 2.1 RCC配置
    • 2.2 SYS配置
    • 2.3 RTC配置
    • 2.4 串口配置
    • 2.5 时钟配置
    • 2.6 生成项目代码
  • 三、代码编写
    • 3.1 重写printf
    • 3.2 RTC_HAL库函数/*设置系统时间*/
    • 3.3 定义两个结构体来获取日期和时间
    • 3.3 在while循环中添加如下代码
  • 四、编译运行烧录
  • 五、参考资料

一、RTC简介

1.1 RTC

RTC是个独立的定时器。

RTC模块拥有一个连续计数的计数器,在相应的软件配置下,可以提供时钟日历的功能。修改计数器的值可以重新设置当前时间和日期 RTC还包含用于管理低功耗模式的自动唤醒单元。

在断电情况下 RTC仍可以独立运行 只要芯片的备用电源一直供电,RTC上的时间会一直走。

RTC实质是一个掉电后还继续运行的定时器,从定时器的角度来看,相对于通用定时器TIM外设,它的功能十分简单,只有计时功能(也可以触发中断)。但其高级之处也就在于掉电之后还可以正常运行。

两个 32 位寄存器包含二进码十进数格式 (BCD) 的秒、分钟、小时( 12 或 24 小时制)、星期几、日期、月份和年份。此外,还可提供二进制格式的亚秒值。系统可以自动将月份的天数补偿为 28、29(闰年)、30 和 31 天。

上电复位后,所有RTC寄存器都会受到保护,以防止可能的非正常写访问。

无论器件状态如何(运行模式、低功耗模式或处于复位状态),只要电源电压保持在工作范围内,RTC使不会停止工作。

1.2 RTC特征

  • 可编程的预分频系数:分频系数高为220。

  • 32位的可编程计数器,可用于较长时间段的测量。

  • 2个分离的时钟:用于APB1接口的PCLK1和RTC时钟(RTC时钟的频率必须小于PCLK1时钟 频率的四分之一以上)。

  • 可以选择以下三种RTC的时钟源:

    • HSE时钟除以128;
    • LSE振荡器时钟;
    • LSI振荡器时钟
  • 2个独立的复位类型:

    APB1接口由系统复位;
    RTC核心(预分频器、闹钟、计数器和分频器)只能由后备域复位

  • 3个专门的可屏蔽中断:

    • 闹钟中断,用来产生一个软件可编程的闹钟中断。
    • 秒中断,用来产生一个可编程的周期性中断信号(长可达1秒)。
    • 溢出中断,指示内部可编程计数器溢出并回转为0的状态.

    RTC时钟源:
    三种不同的时钟源可被用来驱动系统时钟(SYSCLK):

    ● HSI振荡器时钟
    ● HSE振荡器时钟
    ● PLL时钟

    这些设备有以下2种二级时钟源:

    ● 40kHz低速内部RC,可以用于驱动独立看门狗和通过程序选择驱动RTC。 RTC用于从停机/待机模式下自动唤醒系统。
    ● 32.768kHz低速外部晶体也可用来通过程序选择驱动RTC(RTCCLK)。

1.3 RTC原理框图

STM32 RTC时钟读取时间_第1张图片
RTC时钟的框图还是比较简单的,这里我们把他分成两个部分:

APB1 接口:用来和 APB1 总线相连。此单元还包含一组16位寄存器,可通过APB1 总线对其进行读写操作。APB1接口由 APB1 总 线时钟驱动,用来与 APB1 总线连接。
通过APB1接口可以访问RTC的相关寄存器(预分频值,计数器值,闹钟值)。
RTC 核心接口:由一组可编程计数器组成,分成 两个主要模块 。

STM32 RTC时钟读取时间_第2张图片

  • 第一个模块是RTC的预分频模块,它可编程产生 1 秒的RTC时间基准 TR_CLK
    RTC的预分频模块包含了一个 20 位的可编程分频器(RTC 预分频器)。如果在 RTC_CR 寄存器中设置了相应的允许位,则在每个 TR_CLK 周期中 RTC 产生一个中断(秒中断)。
    STM32 RTC时钟读取时间_第3张图片
  • 第二个模块是一个 32 位的可编程计数器 (RTC_CNT),可被初始化为当前的系统时间,一个 32 位的时钟计数器,按秒钟计算,可以记 录 4294967296 秒,约合 136 年左右,作为一般应用,这已经是足够了的。

1.4 RTC工作流程

RTCCLK经过RTC_DIV预分频,RTC_PRL设置预分频系数,然后得到TR_CLK时钟信号,我们一般设置其周期为1s,RTC_CNT计数器计数,假如1970设置为时间起点为0s,通过当前时间的秒数计算得到当前的时间。RTC_ALR是设置闹钟时间,RTC_CNT计数到RTC_ALR就会产生计数中断,

  • RTC_Second为秒中断,用于刷新时间,
  • RTC_Overflow是溢出中断。
  • RTC Alarm 控制开关机

1.5 RTC时钟选择

使用HSE分频时钟或者LSI的时候,在主电源VDD掉电的情况下,这两个时钟来源都会受到影响,因此没法保证RTC正常工作.所以RTC一般都时钟低速外部时钟LSE,频率为实时时钟模块中常用的32.768KHz,因为32768 = 2^15,分频容易实现,所以被广泛应用到RTC模块.(在主电源VDD有效的情况下(待机),RTC还可以配置闹钟事件使STM32退出待机模式).

1.6 RTC复位过程

除了RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器外,所有的系统寄存器都由系统复位或电源复位进行异步复位。
RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器仅能通过备份域复位信号复位。

系统复位后,禁止访问后备寄存器和RCT,防止对后卫区域(BKP)的意外写操作

1.7 RTC中断

秒中断:
这里时钟自带一个秒中断,每当计数加一的时候就会触发一次秒中断。注意,这里所说的秒中断并非一定是一秒的时间,它是由RTC时钟源和分频值决定的“秒”的时间,当然也是可以做到1秒钟中断一次。我们通过往秒中断里写更新时间的函数来达到时间同步的效果

闹钟中断:
闹钟中断就是设置一个预设定的值,计数每自加多少次触发一次闹钟中断

二、CubeMX配置

2.1 RCC配置

STM32 RTC时钟读取时间_第4张图片
RTC设备因为其独特的运行方式(即掉电依旧运行)使用HSE分频时钟或者LSI的时候,在主电源VDD掉电的情况下,这两个时钟来源都会受到影响,资源消耗太大,小小的纽扣电池根本吃不消。没法保证RTC正常工作.所以RTC一般都时钟低速外部时钟LSE

2.2 SYS配置

STM32 RTC时钟读取时间_第5张图片

2.3 RTC配置

STM32 RTC时钟读取时间_第6张图片

  • Activate Clock Source 激活时钟源
  • Activate calendar激活日历
  • 这两个都要点,作用也很明显,先是使能时钟源,再使能RTC日历

RTC_OUT: Not RTC_OUT
Tamper: ×
第一个是是否使能 tamper(PC13)引脚上输出校正的秒脉冲时钟,

第二个: RTC入侵检测校验功能

RTC校验功能,使能侵入检测功能。RTC时钟经64分频输出到侵入检测引脚TAMPER上
当 TAMPER引脚上的信号从 0变成1或者从 1变成 0(取决于备份控制寄存器BKP_CR的 TPAL位),会产生一个侵入检测事件。侵入检测事件将所有数据备份寄存器内容清除。

第一个是使能tamper(PC13)引脚作为时钟脉冲输出
第二个是使能tamper(PC13)引脚作为入侵检测功能

下面是RTC的中断:
RTC全局中断RTC_IRQHandler()
STM32 RTC时钟读取时间_第7张图片
此处设置时间为2022/10/29 12:56:00

Data Format: 日期格式
Binary data format 十六进制
BCD data format BCD码进制

使用自动配置,初始化时间必须使用BCD data format,原因是库函数存在bug,如果使用Binary data format,月份配置会出错,比如说11月,配置时会赋值为RTC_MONTH_NOVEMBER,而此宏定义值为0x11,也就是说其十进制值为17

Hours: 小时

Minutes: 分钟

Seconds: 秒

Week Day: 星期

Month 月份

Date: 日期

Year: 年份

2.4 串口配置

STM32 RTC时钟读取时间_第8张图片

2.5 时钟配置

STM32 RTC时钟读取时间_第9张图片

2.6 生成项目代码

STM32 RTC时钟读取时间_第10张图片
STM32 RTC时钟读取时间_第11张图片

三、代码编写

3.1 重写printf

在main.c和usart.c中添加头文件#include "stdio.h"之后,勾选Target中的use MicroLIB,在mian.c文件中,添加如下代码,进行重定义
STM32 RTC时钟读取时间_第12张图片

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

STM32 RTC时钟读取时间_第13张图片

STM32 RTC时钟读取时间_第14张图片

3.2 RTC_HAL库函数/设置系统时间/

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)
/*启动报警功能*/
HAL_StatusTypeDef HAL_RTC_SetAlarm(RTC_HandleTypeDef *hrtc, RTC_AlarmTypeDef *sAlarm, uint32_t Format)
/*设置报警中断*/
HAL_StatusTypeDef HAL_RTC_SetAlarm_IT(RTC_HandleTypeDef *hrtc, RTC_AlarmTypeDef *sAlarm, uint32_t Format)
/*报警时间回调函数*/
__weak void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
/*写入后备储存器*/
void HAL_RTCEx_BKUPWrite(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister, uint32_t Data)
/*读取后备储存器*/
uint32_t HAL_RTCEx_BKUPRead(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister  

前面四个函数分别是

设置系统时间:HAL_RTC_SetTime();
读取系统时间: HAL_RTC_GetTime();
设置系统日期: HAL_RTC_SetDate();
读取系统日期: HAL_RTC_GetDate();

因为系统的时间和日期开始的时候已经设置过了,所以我们这里只用两个读取函数

读取系统时间函数

/*读取系统时间*/
HAL_StatusTypeDef HAL_RTC_GetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format)

功能: 获取RTC时钟的时间

参数:

  • *hrtc RTC结构体参数 例:&hi2c2
  • RTC_TimeTypeDef *sTime: 获取RTC时间的结构体,
  • Format: 获取时间的格式

RTC_FORMAT_BIN 使用16进制
RTC_FORMAT_BCD 使用BCD进制

读取系统日期函数

/*读取系统日期*/
HAL_StatusTypeDef HAL_RTC_GetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format)

功能: 获取RTC时钟的日期

参数:

  • *hrtc RTC结构体参数 例:&hi2c2
  • RTC_DateTypeDef *sTime: 获取RTC日期的结构体,
  • Format: 获取日期的格式

RTC_FORMAT_BIN 使用16进制
RTC_FORMAT_BCD 使用BCD进制

在stm32f1xx_hal_rtc.h头文件中,可以找到RTC_TimeTypeDef,RTC_DateTypeDef这两个结构体的成员变量。

/**

  * @brief  RTC Time structure definition
    */
    typedef struct
    {
      uint8_t Hours;            /*!< Specifies the RTC Time Hour.
                               This parameter must be a number between Min_Data = 0 and Max_Data = 23 */

  uint8_t Minutes;          /*!< Specifies the RTC Time Minutes.
                                 This parameter must be a number between Min_Data = 0 and Max_Data = 59 */

  uint8_t Seconds;          /*!< Specifies the RTC Time Seconds.
                                 This parameter must be a number between Min_Data = 0 and Max_Data = 59 */

} RTC_TimeTypeDef;
/**

  * @brief  RTC Date structure definition
    */
    typedef struct
    {
      uint8_t WeekDay;  /*!< Specifies the RTC Date WeekDay (not necessary for HAL_RTC_SetDate).
                       This parameter can be a value of @ref RTC_WeekDay_Definitions */

  uint8_t Month;    /*!< Specifies the RTC Date Month (in BCD format).
                         This parameter can be a value of @ref RTC_Month_Date_Definitions */

  uint8_t Date;     /*!< Specifies the RTC Date.
                         This parameter must be a number between Min_Data = 1 and Max_Data = 31 */

  uint8_t Year;     /*!< Specifies the RTC Date Year.
                         This parameter must be a number between Min_Data = 0 and Max_Data = 99 */

} RTC_DateTypeDef;

3.3 定义两个结构体来获取日期和时间

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

3.3 在while循环中添加如下代码

 HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);//获取时间
      /* Get the RTC current Date */
      HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN);//获取日期

  /* Display date Format : yy/mm/dd */
  printf("%02d/%02d/%02d\r\n",2000 + GetData.Year, GetData.Month, GetData.Date);
  /* Display date Format : weekday */
	if(GetData.WeekDay==1){
		printf("星期一\r\n");
	}else if(GetData.WeekDay==2){
		printf("星期二\r\n");
	}else if(GetData.WeekDay==3){
		printf("星期三\r\n");
	}else if(GetData.WeekDay==4){
		printf("星期四\r\n");
	}else if(GetData.WeekDay==5){
		printf("星期五\r\n");
	}else if(GetData.WeekDay==6){
		printf("星期六\r\n");
	}else if(GetData.WeekDay==7){
		printf("星期日\r\n");
	}
	/* Display time Format : hh:mm:ss */
  printf("%02d:%02d:%02d\r\n",GetTime.Hours, GetTime.Minutes, GetTime.Seconds);

  printf("\r\n");

  HAL_Delay(1000);



STM32 RTC时钟读取时间_第15张图片

四、编译运行烧录

STM32 RTC时钟读取时间_第16张图片
STM32 RTC时钟读取时间_第17张图片
STM32 RTC时钟读取时间_第18张图片

五、参考资料

https://blog.csdn.net/as480133937/article/details/105741893

https://blog.csdn.net/jynyyhd/article/details/127589960

你可能感兴趣的:(stm32,单片机,实时音视频)