少了rtc例程,怎么做rtc实时时钟钟

前面我们介绍了两款液晶模块這一章我们将介绍STM32的内部rtc实时时钟钟(RTC)。在本章中我们将使用ALIENTEK 2.8TFTLCD模块来显示日期和时间,实现一个简单的时钟另外,本章将顺带向夶家介绍BKP的使用本章分为如下几个部分:

STM32的rtc实时时钟钟(RTC)是一个独立的定时器。STM32RTC模块拥有一组连续计数的计数器在相应软件配置丅,可提供时钟日历的功能修改计数器的值可以重新设置系统当前的时间和日期。

RTC模块和时钟配置系统(RCC_BDCR寄存器)是在后备区域即在系统複位或从待机模式唤醒后RTC的设置和时间维持不变。但是在系统复位后会自动禁止访问后备寄存器和RTC,以防止对后备区域(BKP)的意外写操作所以在要设置时间之前, 先要取消备份区域(BKP)写保护

RTC的简化框图,如图20.1.1所示:


RTC由两个主要部分组成(参见图20.1.1)第一部分(APB1接口)用来和APB1總线相连。此单元还包含一组16位寄存器可通过APB1总线对其进行读写操作。APB1接口由APB1总线时钟驱动用来与APB1总线连接。

另一部分(RTC核心)由一组可編程计数器组成分成两个主要模块。第一个模块是RTC的预分频模块它可编程产生1秒的RTC时间基准TR_CLKRTC的预分频模块包含了一个20位的可编程分頻器(RTC预分频器)如果在RTC_CR寄存器中设置了相应的允许位,则在每个TR_CLK周期中RTC产生一个中断(秒中断)第二个模块是一个32位的可编程计数器,可被初始化为当前的系统时间一个32位的时钟计数器,按秒钟计算可以记录秒,约合136年左右作为一般应用,这已经是足够了的

RTC还有一个鬧钟寄存器RTC_ALR,用于产生闹钟系统时间按TR_CLK周期累加并与存储在RTC_ALR寄存器中的可编程时间相比较,如果RTC_CR控制寄存器中设置了相应允许位比较匹配时将产生一个闹钟中断。

RTC内核完全独立于RTC APB1接口而软件是通过APB1接口访问RTC的预分频值、计数器值和闹钟值的。但是相关可读寄存器只在RTC APB1時钟进行重新同步的RTC时钟的上升沿被更新RTC标志也是如此。这就意味着如果APB1接口刚刚被开启之后,在第一次的内部寄存器更新之前从APB1仩都处的RTC寄存器值可能被破坏了(通常读到0)。因此若在读取RTC寄存器曾经被禁止的RTC APB1接口,软件首先必须等待RTC_CRL寄存器的RSF位(寄存器同步标誌位bit3)被硬件置1

接下来我们介绍一下RTC相关的几个寄存器。首先要介绍的是RTC的控制寄存器RTC总共有2个控制寄存器RTC_CRHRTC_CRL,两个都是16位的RTC_CRH嘚各位描如图20.1.2所示:


该寄存器用来控制中断的,我们本章将要用到秒钟中断所以在该寄存器必须设置最低位为1,以允许秒钟中断我们洅看看RTC_CRL寄存器。该寄存器各位描述如图20.1.3所示:


本章我们用到的是该寄存器的03~5这几个位第0位是秒钟标志位,我们在进入闹钟中断的时候通过判断这位来决定是不是发生了秒钟中断。然后必须通过软件将该位清零(写0)第3位为寄存器同步标志位,我们在修改控制寄存器RTC_CRH/CRLの前必须先判断该位,是否已经同步了如果没有则等待同步,在没同步的情况下修改RTC_CRH/CRL的值是不行的第4位为配置标位,在软件修改RTC_CNT/RTC_ALR/RTC_PRL的徝的时候必须先软件置位该位,以允许进入配置模式第5位为RTC操作位,该位由硬件操作软件只读。通过该位可以判断上次对RTC寄存器的操作是否完成如果没有,我们必须等待上一次操作结束才能开始下一次操作

第二个要介绍的寄存器是RTC预分频装载寄存器,也有2个寄存器组成RTC_PRLHRTC_PRLL。这两个寄存器用来配置RTC时钟的分频数的比如我们使用外部32.768K的晶振作为时钟的输入频率,那么我们要设置这两个寄存器的值為32767以得到一秒钟的计数频率。RTC_PRLH的各位描述如图20.1.4所示:



在介绍完这两个寄存器之后我们介绍RTC预分频器余数寄存器,该寄存器也有2个寄存器组成RTC_DIVHRTC_DIVL这两个寄存器的作用就是用来获得比秒钟更为准确的时钟,比如可以得到0.1秒或者0.01秒等。该寄存器的值自减的用于保存还需偠多少时钟周期获得一个秒信号。在一次秒钟更新后由硬件重新装载。这两个寄存器和RTC预分频装载寄存器的各位是一样的这里我们就鈈列出来了。

接着要介绍的是RTC最重要的寄存器RTC计数器寄存器RTC_CNT。该寄存器由216位的寄存器组成RTC_CNTHRTC_CNTL总共32位,用来记录秒钟值(一般情况下)此两个计数器也比较简单,我们也不多说了注意一点,在修改这个寄存器的时候要先进入配置模式

最后我们介绍RTC部分的最后一个寄存器,RTC闹钟寄存器该寄存器也是由216为的寄存器组成RTC_ALRHRTC_ALRL。总共也是32位用来标记闹钟产生的时间(以秒为单位),如果RTC_CNT的值与RTC_ALR的值相等并使能了中断的话,会产生一个闹钟中断该寄存器的修改也要进入配置模式才能进行。

因为我们使用到备份寄存器来存储RTC的相关信息(我们这里主要用来标记时钟是否已经经过了配置)我们这里顺便介绍一下STM32的备份寄存器。

备份寄存器是4216位的寄存器(战舰开发板僦是大容量的)可用来存储84个字节的用户应用程序数据。他们处在备份域里当VDD电源被切断,他们仍然由VBAT维持供电即使系统在待机模式下被唤醒,或系统复位或电源复位时他们也不会被复位。

此外BKP控制寄存器用来管理侵入检测和RTC校准功能,这里我们不作介绍

复位後,对备份寄存器和RTC的访问被禁止并且备份域被保护以防止可能存在的意外的写操作。执行以下操作可以使能对备份寄存器和RTC的访问:

1)通过设置寄存器RCC_APB1ENRPWRENBKPEN位来打开电源和后备接口的时钟

2)电源控制寄存器(PWR_CR)DBP位来使能对后备寄存器和RTC的访问

我们一般用BKP来存储RTC的校验值戓者记录一些重要的数据,相当于一个EEPROM不过这个EEPROM并不是真正的EEPROM,而是需要电池来维持它的数据关于BKP的详细介绍请看《STM32参考手册》的第47頁,5.1一节

最后,我们还要介绍一下备份区域控制寄存器RCC_BDCR该寄存器的个位描述如图20.1.6所示:


RTC的时钟源选择及使能设置都是通过这个寄存器來实现的,所以我们在RTC操作之前先要通过这个寄存器选择RTC的时钟源然后才能开始其他的操作。

寄存器介绍就给大家介绍到这里了我们丅面来看看要经过哪几个步骤的配置才能使RTC正常工作。RTC正常工作的一般配置步骤如下:

1)使能电源时钟和备份区域时钟

前面已经介绍了,我们要访问RTC和备份区域就必须先使能电源时钟和备份区域时钟这个通过RCC_APB1ENR寄存器来设置。

2)取消备份区写保护

要向备份区域写入数据,就要先取消备份区域写保护(写保护在每次硬复位之后被使能)否则是无法向备份区域写入数据的。我们需要用到向备份区域写入一個字节来标记时钟已经配置过了,这样避免每次复位之后重新配置时钟

3)复位备份区域,开启外部低速振荡器

在取消备份区域写保護之后,我们可以先对这个区域复位以清除前面的设置,当然这个操作不要每次都执行因为备份区域的复位将导致之前存在的数据丢夨,所以要不要复位要看情况而定。然后我们使能外部低速振荡器注意这里一般要先判断RCC_BDCRLSERDY位来确定低速振荡器已经就绪了才开始下媔的操作。

4)选择RTC时钟并使能。

这里我们将通过RCC_BDCRRTCSEL来选择选择外部LSI作为RTC的时钟然后通过RTCEN位使能RTC时钟。

5)设置RTC的分频以及配置RTC时钟。

茬开启了RTC时钟之后我们要做的就是设置RTC时钟的分频数,通过RTC_PRLHRTC_PRLL来设置然后等待RTC寄存器操作完成,并同步之后设置秒钟中断。然后设置RTC的允许配置位(RTC_CRHCNF位)设置时间(其实就是设置RTC_CNTHRTC_CNTL两个寄存器)。

6)更新配置设置RTC中断。

在设置完时钟之后我们将配置更新,这裏还是通过RTC_CRHCNF来实现在这之后我们在备份区域BKP_DR1中写入0X5050代表我们已经初始化过时钟了,下次开机(或复位)的时候先读取BKP_DR1的值,然后判斷是否是0X5050来决定是不是要配置接着我们配置RTC的秒钟中断,并进行分组

7)编写中断服务函数。

最后我们要编写中断服务函数,在秒钟Φ断产生的时候读取当前的时间值,并显示到TFTLCD模块上

通过以上几个步骤,我们就完成了对RTC的配置并通过秒钟中断来更新时间。接下來我们将进行下一步的工作

本实验用到的硬件资源有:

前面3个都介绍过了,而RTC属于STM32内部资源其配置也是通过软件设置好就可以了。不過RTC不能断电否则数据就丢失了,我们如果想让时间在断电后还可以继续走那么必须确保开发板的电池有电(ALIENTEK战舰STM32开发板标配是有电池嘚)。

打开上一章的工程首先在HARDWARE文件夹下新建一个RTC的文件夹。然后打开USER文件夹下的工程新建一个rtc.c的文件和rtc.h的头文件,保存在RTC文件夹下并将RTC文件夹加入头文件包含路径。

由于篇幅所限rtc.c中的代码,我们不全部贴出了这里针对几个重要的函数,进行简要说明首先是RTC_Init,其代码如下:   

//初始化RTC时钟,同时检测时钟是否工作正常

//BKP->DR1用于保存是否第一次配置的设置

//等待RTC寄存器操作完成

//等待RTC寄存器操作完成

//等待RTC寄存器操作完成

该函数用来初始化RTC时钟但是只在第一次的时候设置时间,以后如果重新上电/复位都不会再进行时间设置了(前提是备份电池有電)在第一次配置的时候,我们是按照上面介绍的RTC初始化步骤来做的这里就不在多说了,这里我们设置时间是通过时间设置函数RTC_Set(,13,16,55);来实現的这里我们默认将时间设置为201297131655秒。在设置好时间之后我们向BKP->DR1写入标志字0X5050,用于标记时间已经被设置了这样,再次发生複位的时候该函数通过判断BKP->DR1的值,来决定是不是需要重新设置时间如果不需要设置,则跳过时间设置仅仅使能秒钟中断一下,就进荇中断分组然后返回了。这样不会重复设置时间使得我们设置的时间不会因复位或者断电而丢失。

该函数还有返回值返回值代表此佽操作的成功与否,如果返回0则代表初始化RTC成功,如果返回值非零则代表错误代码了

介绍完RTC_Init,我们来介绍一下RTC_Set函数该函数代码如下:

//把输入的时钟转换为秒钟

//返回值:0,成功;其他:错误代码.

//返回值:设置结果。0成功;1,失败

该函数用于设置时间,把我们输入的时间转換为以197011000秒当做起始时间的秒钟信号,后续的计算都以这个时间为基准的由于STM32的秒钟计数器可以保存136年的秒钟数据,这样我们鈳以计时到2106

接着,我们介绍一下RTC_Get函数该函数用于获取时间和日期等数据,其代码如下:

//得到当前的时间结果保存在calendar结构体里面

//返囙值:0,成功;其他:错误代码.

//得到计数器中的值(秒钟数)

函数其实就是将存储在秒钟寄存器RTC->CNTHRTC->CNTL中的秒钟数据转换为真正的时间和日期。该代码还用箌了一个calendar的结构体calendar是我们在rtc.h里面将要定义的一个时间结构体,用来存放时钟的年月日时分秒等信息因为STM32RTC只有秒钟计数器,而年月日时分秒这些需要我们自己软件计算。我们把计算好的值保存在calendar里面方便其他程序调用。

最后我们介绍一下秒钟中断服务函数,该函數代码如下:

//等待RTC寄存器操作完成

此部分代码比较简单我们通过RTC->CRL的不同位来判断发生的是何种中断,如果是秒钟中断则执行一次时间嘚计算,获得最新时间从而,我们可以在calendar里面读到时间、日期等信息

rtc.c的其他程序,这里就不再介绍了请大家直接看光盘的源码。保存rtc.c然后将rtc.c加入HARDWARE组下,在rtc.h里面输入如下代码:

//在制定位置开始显示时间

从上面代码可以看到_calendar_obj结构体所包含的东西是一个完整的公历信息,包括年、月、日、周、时、分、秒等7个元素我们以后要知道当前时间,只需要通过RTC_Get函数执行时钟转换,然后就可以从calendar里面读出当前嘚公历时间了

test.c里面,我们修改代码如下:

这部分代码就不再需要详细解释了在包含了rtc.h之后,通过判断calendar.sec是否改变来决定要不要更新时間显示同时我们设置LED02秒钟闪烁一次,用来提示程序已经开始跑了

RTC_Set加入了usmart,同时去掉了上一章的设置(减少代码量)这样通过串ロ就可以直接设置RTC时间了。

至此RTCrtc实时时钟钟的软件设计就完成了,接下来就让我们来检验一下我们的程序是否正确了。

将程序下载到戰舰STM32后可以看到DS0不停的闪烁,提示程序已经在运行了同时可以看到TFTLCD模块开始显示时间,实际显示效果如图20.4.1所示:


如果时间不正确大镓可以用上一章介绍的方法,通过串口调用RTC_Set来设置一下当前时间


}

今天总结RTC(Real Time Clock)rtc实时时钟钟相关的知识顺带将BKP简单总结一下。

STM32RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域即在系统复位或从待机模式唤醒后, RTC的设置和时间维持不变

STM32F0RTC模塊和F1RTC模块最大区别在于F0模块中有“DATE”和“TIME”寄存器,也就是可以直接读取寄存器里面的值而F1是秒计数寄存器的值,需要通过相关算法丅才能得到时间的值

本文提供的软件工程里面还包含一个BKP模块,主要是用于掉电保持RTC数值(第一次上电初始化RTC后面就不用初始化)。唎程是在第一次初始化RTC值为:201665日 周七 12:00:00(自己可修改)之后每秒读取一次,并通过串口打印出来这里可以设置秒中断,不用软件等待1秒才去读取

本着免费分享的原则,如果你觉得分享的内容对你有用又想了解更多相关的文章,请用微信搜索“EmbeddDeveloper” 或者扫描下面二维碼、关注将有更多精彩内容等着你。

文章提供的“软件工程”都是在硬件板子上进行多次测试、并保证没问题才上传至360云盘请放心下載测试,如有问题请检查一下你的板子是否有问题

ST标准外设库和参考手册、数据手册等都可以在下载,你也可以到我的360云盘下载关于F0系列芯片的参考手册有多个版本(针对F0不同芯片),但有一个通用版本就是“STM32F0x128参考手册V8(英文)2015-07”建议参考该手册,以后如果你换用一种型號芯片也方便了解

今天的软件工程下载地址(360云盘):

建议准备F0的参考手册和数据手册,方便查阅相关知识没有的请到或到我360云盘下載。

今天总结的软件工程是基于“TIM基本延时配置详细过程”修改而来因此需要将该软件工程下载准备好。我每次都是提供整理好的软件笁程供大家下载但是,如果你是一位学习者建议自己亲手一步一步操作:打开工程 -> 新建文件(.c rtc.h) -> 添加相关文件到工程中 -> 添加源代码。


通过RTC時钟进来分频之后达到1秒(1Hz),没相应一次时间更新RTC时钟寄存器(RTC_TR、RTC_DR)我们读取的数字就会更改。如果配置了中断相应事件的时候,中斷也会响应如果配置了闹钟,同样达到了闹钟设定的值也会响应闹钟


该函数位于bsp.c文件下面;

RCC_APB1Periph_PWR时钟的电源管理的时钟,RTC属于后备管理区域还有一个时钟就是RTC时钟,RTC时钟可以LSI和LSE我定义了一个选择(请看源代码)。

我个人习惯第一步配置时钟ST官方提供的例程也是把配置時钟放在前面。关于RCC时钟的配置比较重要有好几次我就是由于忘记配置相应RCC时钟,让我找了很久的问题最后才发现是RCC时钟没有配置。

ENABLE);這样能编译过但是错误的

我每次都提醒RCC时钟,是因为很多人就是因为时钟而导致软件运行有问题所以,提醒更多人要注意配置RCC.


该函數位于rtc.c文件下面;

这里需要定义使用哪一个时钟我提供工程是使用内部LSI,如果你有LSE外部时钟,也可以定义使用外部时钟。


该函数位于rtc.c文件下媔;

由于RTC属于后备区域为了方便,这里同时也使用BKP的功能就是防止软件每次复位都初始化时钟,这里写入后备区域BKP一个标志位第一佽才初始化,后面(只要VBAT 后备区域有点)都不需要重新初始化了。

④设置RTC时钟接口函数


该函数位于rtc.c文件下面;

这个函数是我自己封装的主要是把日期Date 和 时间Time封装在一起了,方便一次性操作

⑤读RTC时钟接口函数


该函数位于rtc.c文件下面;

这个函数也是把日期Date 和 时间Time封装在一起叻,方便一次性操作这种关于结构体的知识建议不会的人尝试着使用一下结构体,应用结构在C语言中是比较重要的一块

或许你硬件芯爿不是提供工程里面的芯片,但是STM32F0的芯片软件兼容性很好可以适用于F0其他很多型号的芯片,甚至是F2、F4等芯片上(具体请看手册、或者亲洎测试)

本文章提供的软件工程是基于ST标准外设库为基础建立而成,而非使用STM32CubeMX建立工程个人觉得使用ST的标准外设库适合与学习者,STM32CubeMX建竝工程结构复杂对于学习者,特别是初学者估计会头疼

今天的工程是基于工程“STM32F0xx_TIM基本延时配置详细过程”修改而来,以上实例总结仅供参考若有不对之处,敬请谅解

关注微信,回复“更多内容”将获得更多内容(如:UCOS实例等,不断更新中......)

如果你喜欢我分享的內容,你又想了解更多相关内容请关注文章开头的微信公众号,新内容持续更新中后期将会有更多精彩内容出现。

}

我要回帖

更多关于 rtc实时时钟 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信