摘要
实时时钟是一个独立的定时器。RTC模块拥有一组连续计数的计数器,在相应软件配置下,可 提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。 RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒 后,RTC的设置和时间维持不变。
电路设计
以上是规格书对单片机RTC时钟的介绍。提供时钟、日历的功能;并且可以使用外部电池供电,使得断电、复位的情况下还能够继续计算时间。而且在VDD-VBAT>0.6V的情况下,内部二极管导通,可由VDD直接供电。
如果需要实现电池和VDD交叉供电,单片机供电2~3.6V。考虑冗余,VDD不能直接3.6V供电,VDD3.3V的话,VBAT<2.7V,考虑到电源波动,VBAT还得再小点,控制在2.5V。
如下图所示,用一个二极管降压,兼防止由VDD供电时,防倒流。
有些会在单片机的VDD供电口前也加一个二极管防倒流,个人的建议是,大可不必,见上方规格书警告第二点,单片机内部自带有二极管,没有在在外面加二极管的必要,再加上STM32的供电口有很多个,根本不知道哪个给VBAT供电还是都会参与VBAT的供电,每一个都加上太伤成本。
还有一种比较推荐的方式如下图,用一个NMOS,当3.3V端带点时,截至,3.3V掉电时导通。直接解决一切问题,价格也相差不大(注:mos的Vgs<3V)。
工程配置
配置外部低速晶振
System Core -> RCC -> LowSpeed Clock(LSE) -> Crystal/Ceramic Resonator
配置RTC
Timers -> RTC ->
Activate Clock Source 开启时钟源
Activate Calendar 开启日历
RTC OUT RTC输出
Data Format 输出数据形式
Binary data format 二进制
BCD data format BCD形式
二进制因该都了解,介绍一下什么是BCD,全称(Binary Coded Decimal),二进制形式的十进制码,举个例子就明白了:
BCD | 单片机识别 | 换算HEX | 换算DEC |
09 | 0x09 | 0x09 | 9 |
10 | 0x10 | 0x10 | 10 |
16 | 0x16 | 0x10 | 16 |
21 | 0x21 | 0x15 | 21 |
如果还不明白,那就带着下面的理解再去看一遍上面的表格:
BCD码每4位表示十进制一个位,BCD只能表示0~1001,十个数;也是一种10进制,只是用2进制的每4位表示10进制的一位,但是进位还是按照10进制,到9进1,只不过时进的高四位的1。如果实在理解不了,那就都用二进制吧。(如果日后有想使用RTC芯片开发的,有必要掌握BCD码)
Output 输出的三种方式(警报):
Alarm pulse signal on the TAMPER pin 自定义报警脉冲
RTC clock with a frequency divided by 64 on the TAMPER pin 以RTC时钟64分频为报警脉冲
Second pulse signal on the TAMPER pin 秒脉冲信号
时间设置,这里设置的时间是初始时间,配置意义不大,一般都需要重新调整,
随便设置个最开心的时间吧,周五的下午5点59分59秒。
此处报警脉冲有问题,如下:先看第一张秒脉冲信号,好像没什么不对;但是换成64分频的时候,报警信号初的一看,好像也没啥不对,但是看到仿真,70s了,时钟才过5s,约14倍。然后1000ms/64=15.6ms,报警信号每30s响一次正常,但是时钟也分频了,显然是有问题的。因该是HAL库的一个bug。
配置时钟树
由时钟树可知,RTC时钟是由单片机内部低速晶振或者外部低速晶振再或者外部高速晶振128分频直接提供时基。
注意:RTC必须使用外部晶振,单片机内部低速晶振VDD断电之后将不工作。
最后,导出工程。
程序
按照之前介绍过的方式,Keil左边工具栏下方
Functions -> ...rtc.c -> HAL_RTC_GetData/HAL_RTC_GetTime
HAL_RTC_GetData 获取日期
HAL_RTC_GetTime 获取时间
先不急着下一步,看到这两个函数的形参,以时间为例(日期也是一样的),
*hrtc 时间句柄结构体,RTC的句柄就是hrtc;
*sTime 时间结构体
Format 获取的格式二进制或者BCD
先看时间结构体,右键跟踪RTC_TimeTypeDef,结构体中包含三个元素,时分秒。然后结构体是无名结构体,HAL库中的结构体都是无名结构体,在使用无名结构体的时候,我们需要先给结构体命名,然后再使用。
无名结构体命名:结构体类型 结构体名称;例:
RTC_TimeTypeDef Get_Time;
RTC_DataTypeDef Get_Data;
这样我们就命名好了时间和日期两个结构体,
转到main.c文件中,在用户定义区域,定义RTC_TimeTypeDef类型的结构体Get_Time和RTC_DataTypeDef类型的结构体Get_Data;
然后把刚才两个获取时间和日期的函数复制添加到.c文件的while循环中,并用串口打印出来。(串口打印下节讲)。
✳注意
如果选用的选用的格式是BCD码,串口打印出来的时间是不正确的,计算机不能识别BCD码,就如初始化,打印出来的是
2023/9/22 星期5
17:59:59
如果选用的是BCD形式,系统会默认为二进制数,打印出来的是:
2035/9/34 星期5
23:89:89
附:
BCD形式转换的代码在HAL库里有,以时间为例:
找到时间获取函数:HAL_RTC_GetTime();翻到函数最下方,因为只有两种形式,二进制和BCD,函数如果不是二进制码,对应的就是BCD码了,跟踪RTC_ByteToBcd2()过去:
以下就是HAL自带的BCD码转BIN码的代码了: