STM32 RTC实时时钟

我用的是STM32库函数:两个知识点:
      一、RTC时钟框图分析(重要)
      二、时间是怎样显示出来的(简析)

一、RTC时钟框图分析(重要)
先熟悉一下几个知识点:
      1、STM32的实时时钟(RTC)是一个独立的定时器!
      2、RTC模块和时钟配置系统(RCC_BDCR寄存器)是在后备区域,即在系统复位火从待机模式唤醒后RTC的设置和时间维持不变。

RTC这章中,对RTC相关的寄存器的操作特别重要,我在这里不解释了,请查阅手册。。

先上图!

RTC时钟框图

RTC时钟框图分为完全独立的两个部分:1、APB1接口部分(用来RTC相关的寄存器);2、RTC核心;
      第一部分:
APB1接口。注意:这里涉及到寄存器RTC_CRL中的RSF位,这位是寄存器的同步标志,具体内容去看STM32参考手册RTC这一章。
      第二部分:
RTC核心。这里分为两个模块:1、RTC预分频器模块;2、一个32位的可编程计数器;
      下面开始分析第二部分:
       先给大家介绍下后备区域的几个特别重要的寄存器:
       1、RTC_DIV(重要):RTC预分频器余数寄存器。这个寄存器的作用是来获得比秒钟更加准确的时钟(0.1s,0.01s),该寄存器是自减的,用来保存还需要多少个时钟周期获得一个秒信号。这里加上一个公式(STM32参考手册里有):fTR_CLK=fRTCCLK/(PRL[19:0]+1)    到这里是书上的原话~!
       解释一下,
RTC_DIV寄存器的值是由RTC_PRL(RTC预分频器装载寄存器)提供的,而RTC_DIV寄存器的时钟频率是由RTCCLK提供的(看图)。比如我们把RTC_PRL值设为32767,则RTC_DIV寄存器的值也为32767,他和RTCCLK的时钟频率是一样的(这里根据上面的公式,RTC_PRL加1,则RTC_DIV也加1)。RTCCLK的时钟周期是1/32768(s),也就是每一个RTCCLK的时钟周期,RTC_DIV自减1,直至到1s钟后,被硬件重新装载,也就是1s钟减32768次。那他到底是怎么提供0.1s,甚至是0.01s的呢?
       举个例子就明白了。比如我想要得到1.12秒的这个时间,就要求RTC_DIV自减0.12/(1/32768)次。RTC_DIV只得到0.12s的时间,还有1s时间从哪儿来?他是TR_CLK提供的。这个问题会在下文讲解。。
→_→
       2、RTC_PRL:RTC预分频装载寄存器。这个寄存器有两个作用:1、提供给RTC_DIV的重新装载值;2、设置时钟分频系数。
       第一个作用不讲了。第二个作用:
设置时钟分频系数。比如我们使用32.768KHz的晶振作为时钟输入,那么我们配置这个寄存器值位32767,就可以得到1s钟的计数频率(32768/(32767+1),单位(HZ))。
       3、RTC_CNT(重要):RTC计数器寄存器。这个寄存器较简单,用来记录秒钟值。如果之前对RTC_CR(控制寄存器),的相关中断允许位配置的话,RTC_CNT寄存器可以产生一个溢出中断
       4、RTC_ALR:RTC闹钟寄存器。从图中就可以看出来,很简单。用来标记闹钟产生时间,如果RTC_CNT的值和RTC_ALR的值相等的话,并使能中断的话(
在RTC_CR(控制寄存器)中配置),会产生一个闹钟中断
       后备区域的寄存器就给大家介绍到这儿。相比大家通过上面的介绍结合框图,头脑里面应该有个大致流程了吧。没有~!?卧槽~那就给大家理一遍思路
→_→
       首先外部加进来一个时钟信号RTCCLK(32.768K),然后设置RTC_PRL的分频系数为32767,得到一个秒时钟信号TR_CLK(1HZ)。当TR_CLK每过一个时钟周期,产生一个RTC_Second(秒钟中断),同时RTC_CNT计数器(记录秒值)加1。如果要求更精准的时间,还可以在RTC_CR寄存器的RSF位被置1时去读RTC_DIV的值。


二、时间是怎样显示出来的(简析)
      主函数中有这么两条语句:
      LCD_ShowString(60,130,200,16,16,"    -  -  ");       ①
      LCD_ShowString(60,162,200,16,16,"  :  :  ");          ②
      在看这三条语句(这里统称”中间三条语句“):
      LCD_ShowNum(60,130,calendar.w_year,4,16);                                     
      LCD_ShowNum(100,130,calendar.w_month,2,16);                                     
      LCD_ShowNum(124,130,calendar.w_date,2,16);
      和这三条语句(
这里统称”最后三条语句“):
      LCD_ShowNum(60,162,calendar.hour,2,16);                                     
      LCD_ShowNum(84,162,calendar.min,2,16);                                     
      LCD_ShowNum(108,162,calendar.sec,2,16);
      很显然,中间三条语句是显示年月日的对应①,最后三条语句是显示时分秒的对应②。这些结构体成员都在初始化函数(RTC_Init();)中被赋值了,怎么赋值的,大家自己去研究吧。。。然后在硬件中,TR_CLK的每个时钟周期都会触发秒中断,在秒中断服务函数中又对时间进行了更新。
       想显示时间,是不是先得设置一个基础时间,然后让系统在基础时间上,进行自加。
       
第一步:设置一个基础时间。在对时钟进行配置时(在初始化函数(RTC_Init();中配置),里面有个RTC_Set();函数,此函数会你设置的年月日时分秒进行计算,算出从1970年到你设置那个时刻总共是多少秒(这博主也不知道为什么是1970年),然后把算出来的这个秒值赋给RTC_CNT计数器作为初值。
       第二步:系统自己更新时间(自加)。时间是怎么更新的,这里给大家简单提一下。。在更新函数(RTC_Get();)中,首先会读取RTC_CNT计数器中的值,然后经过一番倒计算,计算出年月日时分秒和星期,分别赋值给那些时间的结构体变量。于是在主函数的while(1)中,会不断的被秒中断刷新时间,并显示在LCD上。
       这样,一个完整的时钟就显示在LCD屏幕上了。大功告成!
       
博主不才,大牛不喜勿喷哦~

猜你喜欢

转载自blog.csdn.net/qinrenzhi/article/details/82558352