凡亿专栏 | 【STM32 cubemx】0009 HAL库开发:RTC实时时钟的使用、掉电时间保持
【STM32 cubemx】0009 HAL库开发:RTC实时时钟的使用、掉电时间保持

RTC (Real Time Clock)即实时时钟。它可以提供时钟、日历的功能;并且可以使用外部电池供电,在极低的功耗下保持计数,使得断电之后还能够计算时间,所以名为实时时钟。

STM32f103的RTC,本质上是一个32位的计数器,在断电后,由电池供电还能保持计数;要使用时间时,需要将计数器的值换算成日期和时间。

此外,stm32的RTC还具备后备存储区,可以利用电池供电,保存10个16bit的数据。


1)cubemx中配置RTC

我们在之前的串口中断工程上修改,以便于打印数值查看。

使用cubemx打开串口中断的工程,然后另存为RTC工程,增加如下设置,启用RTC,勾选时钟源、日历、以及RTC OUT:

(注意这里选择RTC OUT输出时,固定是PC13引脚,如果我们之前的工程中设置了PC13引脚,要先设为reset模式,再选RTC OUT)

66fa7e6a9c3d69728b29b60452345c.jpg


设置RTC的初始时间:

1a9929e0665ada4ba0109ee105166e.jpg


接着,设置RTC的时钟,切换到clock configuration 选项卡,如下设置,选择外部的低速时钟:

6791f9111ea0a9b095fe75a32ab9a7.jpg

这里选择外部时钟是因为,内部的RC振荡器精度较低,计时不准确;而如果使用主时钟(高速时钟)分频后作为时钟源功耗较大;一般RTC要求掉电还能运行,需要低功耗。

设置完成后,就可以生成工程代码了。


2)keil中的程序编写

Keil中打开工程,在rtc.c文件中,我们可以看到RTC的初始时间是通过如下方式设置的,

有需要的时候,我们可以仿照这部分代码重新设置时间:

4f8f6dc9f53b7c4b6ec46aee1109f5.jpg


在main.c中添加如下代码,然后编译、下载,运行结果可见右下角的串口打印信息:

0509c9c5bfb923e0666d5d3adcc48f.jpg

8eeb8a0161f2f7562ee6b6ce92315a.jpg

这个程序先定义了两个结构体,用来作为保存日期和时间的临时变量;然后通过重定向后的串口打印输出。每秒钟打印一次,可以看到输出时间和日期能自动进位、更新。


3)RTC时间的掉电保持

通过上面的配置,我们已经可以设置RTC开始运行,但是,这个程序还很不实用;每次掉电、上电重启都会重新设置为初始时间;这完全不能发挥RTC的特点。

要想RTC在掉电后仍能继续计时、再次上电后还能保持准确的时间,需要软硬件两方面的支持。

首先,硬件上,VBAT引脚上必须连接电池,一般我们使用3V的纽扣电池,以使得断电后电池能为RTC供电,继续计时。

其次,软件上,需要修改HAL库代码,这里详细说说软件改写这一步。

Cubemx(5.10)生成的RTC HAL库代码,有个明显的缺陷,主要体现在日期的存储和时间的存储是分开的;日期的存储是在一个普通的RAM变量(就是HAL库中DateToUpdate这个全局变量)中,它每次在累计到满一天时,就会将日期存储(DateToUpdate)变量加1,然后将rtc的计数器清0;这样使用在不掉电时是没有什么问题的,但是一旦掉电,存储日期的变量(DateToUpdate)不能保持,会被置为初始值,而时间每次都是从rtc计数器中读取,这就导致掉电重启后,日期变成了2000/01/01,而时间还在正常继续累加。

正因为这个每次日期进位的清rtc计数器操作,使得原本连续的rtc计数变得不连续,因而仅仅从rtc计数器中无法恢复时间。

有些网友的办法是,将日期值存在后备存储器中,这样掉电后再读取时可以恢复,但是如果掉电时间超过了一天,读回的日期会是前一天存储的,也不能保证完全正确。

比较彻底的解决办法是不用HAL库的时间设置和时间获取函数,把这套函数完全重写。主要的两个函数如下,就是设置时间和获取时间的函数,把日期和时间看作一个整体。


设置时间时,由日期和时间换算成秒,再写入rtc计数器:

cd251abf320b3436be60d896b1d491.jpg


获取时间时,读取rtc计数器,再由秒数换算成年月日时分秒:

cd9cc7bbf1cf3514f07ffdb1fde14c.jpg

实际上,rtc计数器有32位,每秒增1的话可以计时130多年不溢出,足够一般的使用了。


另外,还需要在MX_RTC_Init()函数中添加代码,如下:

92c9b1659ebcf7d73f2b4cb276806b.jpg

06c08a0089afb16455db749ccf9b5e.jpg

这一段是读取后备存储区中的内容,然后对比是否与特定的RTC_unique_ID一致,如果不一致,则设置一个当前的时间初值,并将RTC_unique_ID写入后备存储区;如果一致,则说明初值已经被设置过,直接返回,不再执行HAL库函数中设置RTC时间的操作。


这样就设置完了,之后可以调用获取时间的函数了:

689371ed66f1c1b369892a4e608f16.jpg


运行结果如下,可以看到中间断电了26分钟,有电池为VBAT供电,再次给系统加电时,时间和日期都能正确获取。

9b3239cc142ee86edb219afb97f305.jpg


好了,这一节的内容基本讲完了,主要讲了RTC相关的知识,要想掉电后还能正确恢复时间,HAL库函数有缺陷,需要大改;此外,RTC的后备存储器,可以利用电池供电存储一些掉电需要保存的数据。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表凡亿课堂立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。
相关阅读
进入分区查看更多精彩内容>
精彩评论

暂无评论