目录
实验平台
硬件:银杏科技GT7000双核心开发板-ARM-STM32H743XIH6,银杏科技iToolXE仿真器
软件:最新版本STM32CubeH7固件库,STM32CubeMX v6.10.0,开发板环境MDK v5.35,串口工具putty
RTC
RTC介绍
RTC(Real-Time Clock)是电子设备中的独立计时模块,功能类似于电子手表,用于管理所有低功耗模式的自动唤醒单元。实时时钟 (RTC) 是一个独立的 BCD 定时器/计数器。RTC 提供具有可编程闹钟中断功能的日历时钟/日历。RTC拥有独立电源域:通过VBAT引脚连接备份电池(典型3V CR2032),主电源关闭时保持计时。
主要特性如下:
- 包含亚秒、秒、分钟、小时(12/24 小时制)、星期几、日期、月份和年份的日历。
- 软件可编程的夏令时补偿,自动将月份的天数补偿为 28、29(闰年)、30 和 31 天。
- 具有中断功能的可编程闹钟。可通过任意日历字段的组合触发闹钟。
- 自动唤醒单元,可周期性地生成标志以触发自动唤醒中断。
- 参考时钟检测:可使用更加精确的第二时钟源(50Hz 或 60Hz)来提高日历的精确度。
- 利用亚秒级移位特性与外部时钟实现精确同步。
- 数字校准电路(周期性计数器调整):精度为 0.95ppm,在数秒钟的校准窗口中获得。
- 用于事件保存的时间戳功能。
- 带可配置过滤器和内部上拉的入侵检测事件。
- 可屏蔽中断/事件:
- --闹钟 A
- --闹钟 B
- --唤醒中断
- --时间戳
- --入侵检测
- 32 备份寄存器。
RTC框图

1.时钟源
STM32H743 的 RTC 时钟(RTCCLK)通过时钟控制器,可以从 LSE 时钟、LSI 时钟以及HSE 时钟三者中选择(通过 RCC_BDCR寄存器选择)。一般我们选择 LSE,即外部 32.768Khz 晶振作为时钟源(RTCCLK),而 RTC时钟核心,要求提供 1Hz 的时钟,所以,我们要设置 RTC 的可编程预分配器。
2.预分频器
STM32H743的可编程预分配器(RTC_PRER)分为 2 个部分:
(1) 一个通过 RTC_PRER 寄存器的 PREDIV_A 位配置的 7 位异步预分频器。
(2) 一个通过 RTC_PRER 寄存器的 PREDIV_S 位配置的 15 位同步预分频器。
RTC 框图中,ck_spre 的时钟可由如下计算公式计算:
Fck_spre=Frtcclk/[(PREDIV_S+1)*(PREDIV_A+1)]
其中,Fck_spre 即可用于更新日历时间等信息。PREDIV_A 和 PREDIV_S 为 RTC 的异步和同步分频器。且推荐设置 7 位异步预分频器(PREDIV_A)的值较大,以最大程度降低功耗。
3.日历时间(RTC_TR)和日期(RTC_DR)寄存器
STM32H743 的 RTC 日历时间(RTC_TR)和日期(RTC_DR)寄存器,用于存储时间和日期(也可以用于设置时间和日期),可以通过与 PCLK1(APB1 时钟)同步的影子寄存器来访问,这些时间和日期寄存器也可以直接访问,这样可避免等待同步的持续时间。
每隔 2 个 RTCCLK 周期,当前日历值便会复制到影子寄存器,并置位 RTC_ISR 寄存器的 RSF 位。我们可以读取RTC_TR 和 RTC_DR 来得到当前时间和日期信息,不过需要注意的是:时间和日期都是以BCD 码的格式存储的,读出来要转换一下,才可以得到十进制的数据。
4.可编程闹钟
STM32H743 提供两个可编程闹钟:闹钟 A(ALARM_A)和闹钟 B(ALARM_B)。通过 RTC_CR 寄存器的 ALRAE 和 ALRBE 位置 1 来使能闹钟。当日历的亚秒、秒、分、小时、日期分别与闹钟寄存器RTC_ALRMASSR/RTC_ALRMAR和RTC_ALRMBSSR/RTC_ALRMBR 中的值匹配时,则可以产生闹钟(需要适当配置)。本章我们将利用闹钟A 产生闹铃,即设置RTC_ALRMASSR 和 RTC_ALRMAR 即可。
5.周期性自动唤醒
STM32H743 的 RTC 不带秒钟中断,但是多了一个周期性自动唤醒功能。周期性唤醒功能,由一个 16 位可编程自动重载递减计数器(RTC_WUTR)生成,可用于周期性中断/唤醒。
我们可以通过 RTC_CR 寄存器中的WUTE 位设置使能此唤醒功能。唤醒定时器的时钟输入可以是:2、4、8 或 16 分频的 RTC 时钟(RTCCLK),也可以是 ck_spre 时钟(一般为1 HZ)。
本实验中,通过软件对 RTC 计数器进行相关的配置,可以提供时钟功能,通过修改计时器的值可以调整时钟。最终通过串口在终端显示时间。
STM32CubeMX生成工程
我们参考前面章节STM32H743-结合CubeMX新建HAL库MDK工程,打开CubeMX软件,重复步骤不再展示,我们来看配置RTC部分如下图所示:
实验代码
1. 主函数
c
int main(void)
{
RTC_TimeTypeDef sTime;
//定义RTC_TimeTypeDef结构体类型下的结构体变量sTime(时间)
RTC_DateTypeDef sDate;//(日期)
int second_bak = 0;
MPU_Config();
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_RTC_Init();
MX_USART6_UART_Init();
uart6.initialize(115200);
//设置RTC日期和时间
my_rtc.set_date(25,3,11,2);
my_rtc.set_time(14,32,00);
while (1)
{
if(systick._500ms_flag == 1)
{
systick._500ms_flag = 0;
HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
//使用HAL库函数获取RTC的时间信息,将结果存储在sTime变量中
HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
//使用HAL库函数获取RTC的日期信息,将结果存储在sDate变量中
if(second_bak != sTime.Seconds)
//上一秒的秒数second_bak是否与当前秒数sTime.Seconds不相等,用于实现每秒钟输出一次RTC时间
{
uart6.printf("\x0c"); //用于清屏操作
uart6.printf("\033[1;32;40m"); //用于设置终端显示颜色
uart6.printf("Hello,I am GT7000!\r\nThis is RTC TIME interface!\r\n");
uart6.printf("RTC TIME:");
uart6.printf(" %02d:%02d:%02d",sTime.Hours,sTime.Minutes,sTime.Seconds); //将格式化后的时间信息发送到UART6,格式为"时:分:秒"
uart6.printf("20%02d-%02d-%02d星期期%01d\r\n\r\n",sDate.Year,sDate.Month,sDate.Date,sDate.WeekDay);
//将格式化后的日期信息发送到UART6,格式为"年-月-日 星期-"
second_bak = sTime.Seconds;
}
}
}
}
2. RTC初始化
c
void MX_RTC_Init(void)
{
RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef sDate = {0};
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;
hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
if (HAL_RTC_Init(&hrtc) != HAL_OK)
{
Error_Handler();
}
sTime.Hours = 0x11;
sTime.Minutes = 0x40;
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_TUESDAY;
sDate.Month = RTC_MONTH_MARCH;
sDate.Date = 0x11;
sDate.Year = 0x0;
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
{
Error_Handler();
}
if (HAL_RTCEx_SetWakeUpTimer(&hrtc, 0, RTC_WAKEUPCLOCK_RTCCLK_DIV16) != HAL_OK)
{
Error_Handler();
}
}
该函数用来初始化 RTC 配置以及日期和时钟,这里设置时间和日期,分别是通过
HAL_RTC_SetTime 函数和 HAL_RTC_SetDate 函数来实现。
3、设置时间和日期
主函数中调用设置时间和日期的自定义函数rtc_set_time 和rtc_set_date 来设置初始时间日期,这两个函数实际就是调用库函数里面的 HAL_RTC_SetTime 函数和HAL_RTC_SetDate函数来实现的,它们的定义如下:
c
static int rtc_set_time(unsigned char hour,unsigned char min,unsigned char sec)
{
RTC_TimeTypeDef sTime;
sTime.Hours = hour;
sTime.Minutes = min;
sTime.Seconds = sec;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
{
while(1);
}
return 0;
}
static int rtc_set_date(unsigned char year,unsigned char month,unsigned char date,unsigned char week)
{
RTC_DateTypeDef sDate;
sDate.WeekDay = week;
sDate.Month = month;
sDate.Date = date;
sDate.Year = year;
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
{
while(1);
}
return 0;
}
实验现象
在终端屏幕上可以看到显示的时间和日期。如图所示。