文章目录
1.认识RTC
1.1什么是RTC
●RTC (Real Time Clock):实时时钟
●RTC是个独立的定时器,RTC模块拥有一个连续计数的计数器,在相应的软件配置下,可以提供时钟日历的功能。修改计数器的值可以重新设置当前时间和日期,RTC还包含用于管理低功耗模式的自动唤醒单元,在断电情况下 RTC仍可以独立运行 只要芯片的备用电源一直供电,RTC上的时间会一直走。
●RTC实质是一个掉电后还继续运行的定时器,从定时器的角度来看,相对于通用定时器TIM外设,它的功能十分简单,只有计时功能(也可以触发中断)。但其高级指出也就在于掉电之后还可以正常运行。
●两个 32 位寄存器包含二进码十进数格式 (BCD) 的秒、分钟、小时( 12 或 24 小时制)、星期几、日期、月份和年份。此外,还可提供二进制格式的亚秒值。系统可以自动将月份的天数补偿为 28、29(闰年)、30 和 31 天。
●上电复位后,所有RTC寄存器都会受到保护,以防止可能的非正常写访问。
●无论器件状态如何(运行模式、低功耗模式或处于复位状态),只要电源电压保持在工作范围内,RTC使不会停止工作。
1.2RCT特征
● 可编程的预分频系数:分频系数高为220。
● 32位的可编程计数器,可用于较长时间段的测量。
● 2个分离的时钟:用于APB1接口的PCLK1和RTC时钟(RTC时钟的频率必须小于PCLK1时钟 频率的四分之一以上)。
● 可以选择以下三种RTC的时钟源:
● HSE时钟除以128;
● LSE振荡器时钟;
● LSI振荡器时钟
● 2个独立的复位类型:
● APB1接口由系统复位;
● RTC核心(预分频器、闹钟、计数器和分频器)只能由后备域复位
● 3个专门的可屏蔽中断:
● 闹钟中断,用来产生一个软件可编程的闹钟中断。
● 秒中断,用来产生一个可编程的周期性中断信号(长可达1秒)。
● 溢出中断,指示内部可编程计数器溢出并回转为0的状态。
1.3RTC时钟源
● 三种不同的时钟源可被用来驱动系统时钟(SYSCLK):
● HSI振荡器时钟
● HSE振荡器时钟
● PLL时钟
● 这些设备有以下2种二级时钟源:
● 40kHz低速内部RC,可以用于驱动独立看门狗和通过程序选择驱动RTC。 RTC用于从停机/待机模式下自动唤醒系统。
● 32.768kHz低速外部晶体也可用来通过程序选择驱动RTC(RTCCLK)。
1.4RTC原理框图
RTC时钟的框图可以分成 两个部分
:
第一个部分
:
●APB1 接口:用来和 APB1 总线相连。 此单元还包含一组 16 位寄存器,可通过 APB1 总线对其进行读写操作。APB1 接口由 APB1 总 线时钟驱动,用来与 APB1 总线连接。
●通过APB1接口可以访问RTC的相关寄存器(预分频值,计数器值,闹钟值)。
第二个部分
:
RTC 核心接口:由一组可编程计数器组成,又可以分成 两个主要模块
第一个模块是 RTC 的 预分频模块,它可编程产生 1 秒的 RTC 时间基准 TR_CLK。RTC 的预分频模块包含了一个 20 位的可编程分频器(RTC 预分频器)。如果在 RTC_CR 寄存器中设置了相应的允许位,则在每个 TR_CLK 周期中 RTC 产生一个中断(秒中断)。
第二个模块是一个 32 位的可编程计数器 (RTC_CNT),可被初始化为当前的系统时间,一个 32 位的时钟计数器,按秒钟计算,可以记 录 4294967296 秒,约合 136 年左右,作为一般应用,这已经是足够了的。
1.5RTC具体流程
● 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.6RTC时钟选择
● 使用HSE分频时钟或者LSI的时候,在主电源VDD掉电的情况下,这两个时钟来源都会受到影响,因此没法保证RTC正常工作.所以RTC一般都时钟低速外部时钟LSE,频率为实时时钟模块中常用的32.768KHz,因为32768 = 2^15,分频容易实现,所以被广泛应用到RTC模块.(在主电源VDD有效的情况下(待机),RTC还可以配置闹钟事件使STM32退出待机模式).
1.7RTC复位过程
● 除了RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器外,所有的系统寄存器都由系统复位或电源复位进行异步复位。
RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器仅能通过备份域复位信号复位。
● 系统复位后,禁止访问后备寄存器和RCT,防止对后卫区域(BKP)的意外写操作
1.8RTC中断
● 秒中断:
这里时钟自带一个秒中断,每当计数加一的时候就会触发一次秒中断,。注意,这里所说的秒中断并非一定是一秒的时间,它是由RTC时钟源和分频值决定的“秒”的时间,当然也是可以做到1秒钟中断一次。我们通过往秒中断里写更新时间的函数来达到时间同步的效果
● 闹钟中断:
闹钟中断就是设置一个预设定的值,计数每自加多少次触发一次闹钟中断
2.STM32CUBEMX实现RTC时钟
2.1配置RCC
●设置高速外部时钟HSE 选择外部时钟源
●使能外部晶振LSE
●RTC设备因为其独特的运行方式(即掉电依旧运行)使用HSE分频时钟或者LSI的时候,在主电源VDD掉电的情况下,这两个时钟来源都会受到影响,资源消耗太大,小小的纽扣电池根本吃不消。没法保证RTC正常工作.所以RTC一般都时钟低速外部时钟LSE
2.2配置RTC
●Activate Clock Source 激活时钟源 (使能时钟源)
●Activate calendar激活日历 (使能RTC日历)
●RTC_OUT: Not RTC_OUT (使能tamper(PC13)引脚作为时钟脉冲输出)
●Tamper: × ( 使能tamper(PC13)引脚作为入侵检测功能)
RTC校验功能,使能侵入检测功能。RTC时钟经64分频输出到侵入检测引脚TAMPER上当 TAMPER引脚上的信号从 0变成1或者从 1变成 0(取决于备份控制寄存器BKP_CR的 TPAL位),会产生一个侵入检测 事件。侵入检测事件将所有数据备份寄存器内容清除。
●两个RTC的中断:
RTC全局中断RTC_IRQHandler()
闹钟中断函数RTCAlarm_IRQHandler()
此处设置时间为2022/10/31 22:18:00
2.3配置串口
2.4配置时钟
原理参考:《【STM32】系统时钟RCC详解(超详细,超全面)》
2.5文件保存,创建工程
2.6修改工程代码
2.6.1代码编写前分析
勾选下图选项,则可以展开头文件,便于查看
打开stm32f1xx_hal_rtc.h文件可以看到以下函数
我们可以看到前面的四个函数,分别是:
- 设置系统时间:HAL_RTC_SetTime();
- 读取系统时间: HAL_RTC_GetTime();
- 设置系统日期: HAL_RTC_SetDate();
- 读取系统日期: HAL_RTC_GetDate();
两个读取函数是我们待会儿编写输出日历代码所需要的
继续查看此文件,可以看到如下图两个结构体:
两个结构体中的属性就是待会儿要输出的日历里所包含的数据
2.6.2具体的代码编写·
在main.c中重写fputc函数,使得能够使用printf函数
#include "stdio.h"//添加到头部
int fputc(int ch,FILE *f){
uint8_t temp[1]={ch};
HAL_UART_Transmit(&huart1,temp,1,2);
return ch;
}
定义两个结构体来获取日期和时间:
RTC_DateTypeDef GetData; //获取日期结构体
RTC_TimeTypeDef GetTime; //获取时间结构体
在while循环中添加:
/* Get the RTC current Time */
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 time Format : hh:mm:ss */
printf("%02d:%02d:%02d\r\n",GetTime.Hours, GetTime.Minutes, GetTime.Seconds);
printf("\r\n");
HAL_Delay(1000);
程序中使用HAL_RTC_GetTime(),HAL_RTC_GetDate()读取时间和日期,并保存到结构体变量中,然后通过串口输出读取的时间和日期。
想要输出星期几则继续写入如下代码:
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");
}
2.7编译,烧录,测试
效果展示1:
效果展示2:
3.总结
掌握了RTC定时器的基本原理,以及如何使用RTC定时器设置一个日历,并且输出,但是在配置时钟放面有所欠缺,还需要努力掌握
4.参考
https://blog.csdn.net/as480133937/article/details/105741893