STM32 RTC实时时钟(一)

stm32处理器内部集成了实时时钟控制器(rtc),因此在实现实时时钟功能时,无须外扩时钟芯片即可构建实时时钟系统。
实时时钟 (rtc) 是一个独立的 bcd 定时器/计数器。rtc 提供一个日历时钟、两个可编程闹钟中断,以及一个具有中断功能的周期性可编程唤醒标志。rtc 还包含用于管理低功耗模式的自动唤醒单元。
两个 32 位寄存器包含二进码十进数格式 (bcd) 的秒、分钟、小时(12 或 24 小时制)、星期几、日期、月份和年份。此外,还可提供二进制格式的亚秒值。系统可以自动将月份的天数补偿为 28、29(闰年)、30 和 31天。并且还可以进行夏令时补偿。其它 32 位寄存器还包含可编程的闹钟亚秒、秒、分钟、小时、星期几和日期。
此外,还可以使用数字校准功能对晶振精度的偏差进行补偿。
上电复位后,所有 rtc 寄存器都会受到保护,以防止可能的非正常写访问。无论器件状态如何(运行模式、低功耗模式或处于复位状态),只要电源电压保持在工作范围内,rtc 便不会停止工作。
stm32f4xx的rtc模块和时钟配置可设置在备份区域,这样系统复位或者从待机模式唤醒后rtc的设置和时间依然维持不变,只要备份域供电正常,rtc模块就能持续地走时。为防止备份域被意外写操作,备份区域也是被写保护的。
备份区域包含20个备份寄存器,共80个字节。可利用备份寄存器模拟eeprom,实现非易失功能,但是必须保证备份区域供电正常。通常,为保证系统掉电后rtc能够正常走时且备份寄存器非易失,都会为rtc模块配备一枚纽扣电池。
rtc框图
时钟和预分频器
rtc 时钟源 (rtcclk) 通过时钟控制器从 lse 时钟、lsi 振荡器时钟以及 hse 时钟三者中选择。
可编程的预分频器阶段可生成 1 hz 的时钟,用于更新日历。为最大程度地降低功耗,预分频器分为 2 个可编程的预分频器:
● 一个通过 rtc_prer 寄存器的 prediv_a 位配置的 7 位异步预分频器。
● 一个通过 rtc_prer 寄存器的 prediv_s 位配置的 15 位同步预分频器。
实时时钟和日历
rtc 日历时间和日期寄存器可通过与 pclk1(apb1 时钟)同步的影子寄存器来访问。这些时间和日期寄存器也可以直接访问,这样可避免等待同步的持续时间。
● rtc_ssr 对应于亚秒
● rtc_tr 对应于时间
● rtc_dr 对应于日期
每隔两个 rtcclk 周期,便将当前日历值复制到影子寄存器,并将 rtc_isr 寄存器的 rsf位置 1。在停机和待机模式下不会执行复制操作。退出这两种模式时,影子寄存器会在最长 2 个 rtcclk 周期后进行更新。
当应用读取日历寄存器时,它会访问影子寄存器的内容。也可以通过将 rtc_cr 寄存器的
bypshad 控制位置 1 来直接访问日历寄存器。默认情况下,该位被清零,用户访问影子寄存器。
在 bypshad=0 模式下读取 rtc_ssr、rtc_tr 或 rtc_dr 寄存器时,apb 时钟频率(f apb ) 必须至少为 rtc 时钟频率 (f rtcclk ) 的 7 倍。
影子寄存器通过系统复位来复位。
rtc 寄存器写保护
系统复位后,可通过 pwr 电源控制寄存器 (pwr_cr) 的 dbp 位保护 rtc 寄存器以防止非正常的写访问。必须将 dbp 位置 1 才能使能 rtc 寄存器的写访问。
上电复位后,所有 rtc 寄存器均受到写保护。通过向写保护寄存器 (rtc_wpr) 写入一个密钥来使能对 rtc 寄存器的写操作。
要解锁所有 rtc 寄存器(rtc_isr[13:8]、rtc_tafcr 和 rtc_bkpxr 除外)的写保护,需要执行以下步骤:
将“0xca”写入 rtc_wpr 寄存器。将“0x53”写入 rtc_wpr 寄存器。写入一个错误的关键字会再次激活写保护。保护机制不受系统复位影响。
日历初始化和配置
要编程包括时间格式和预分频器配置在内的初始时间和日期日历值,需按照以下顺序操作:
将 rtc_isr 寄存器中的 init 位置 1 以进入初始化模式。在此模式下,日历计数器将停止工作并且其值可更新。轮询 rtc_isr 寄存器中的 initf 位。当 initf 置 1 时进入初始化阶段模式。大约需要2 个 rtcclk 时钟周期(由于时钟同步)。要为日历计数器生成 1 hz 时钟,应首先编程 rtc_prer 寄存器中的同步预分频系数,然后编程异步预分频系数。即使只需要更改这两个字段中之一,也必须对 rtc_prer寄存器执行两次单独的写访问。在影子寄存器(rtc_tr 和 rtc_dr)中加载初始时间和日期值,然后通过 rtc_cr寄存器中的 fmt 位配置时间格式(12 或 24 小时制)。通过清零 init 位退出初始化模式。随后,自动加载实际日历计数器值,在 4 个 rtcclk时钟周期后重新开始计数。当初始化序列完成之后,日历开始计数。
注意:系统复位后,应用可读取 rtc_isr 寄存器中的 inits 标志,以检查日历是否已初始化。如果该标志为 0 ,表明日历尚未初始化,因为年份字段设置为其上电复位时的默认值 (0x00) 。
要在初始化之后读取日历,必须首先用软件检查 rtc_isr 寄存器的 rsf 标志是否置 1 。
接着查看寄存器描述:
rtc 时间寄存器 (rtc_tr)
rtc_tr 是日历时间影子寄存器。只能在初始化模式下对该寄存器执行写操作。
位 22 pm:am/pm 符号 (am/pm notation)
0:am 或 24 小时制
1:pm
位 21:20 ht[1:0]: 小时的十位(bcd 格式)(hour tens in bcd format)
位 16:16 hu[3:0]: 小时的个位(bcd 格式)(hour units in bcd format)
位 14:12 mnt[2:0]: 分钟的十位(bcd 格式)(minute tens in bcd format)
位 11:8 mnu[3:0]: 分钟的个位(bcd 格式)(minute units in bcd format)
位 6:4 st[2:0]: 秒的十位(bcd 格式)(second tens in bcd format)
位 3:0 su[3:0]: 秒的个位(bcd 格式)(second units in bcd format)
rtc 日期寄存器 (rtc_dr)
rtc_dr 是日历日期影子寄存器。只能在初始化模式下对该寄存器执行写操作。
位 23:20 yt[3:0]: 年份的十位(bcd 格式)(year tens in bcd format)
位 19:16 yu[3:0]: 年份的个位(bcd 格式)(year units in bcd format)
位 15:13 wdu[2:0]: 星期几的个位 (week day units)
000:禁止
001:星期一
...
111:星期日
位 12 mt: 月份的十位(bcd 格式)(month tens in bcd format)
位 11:8 mu: 月份的个位(bcd 格式)(month units in bcd format)
位 5:4 dt[1:0]: 日期的十位(bcd 格式)(date tens in bcd format)
位 3:0 du[3:0]: 日期的个位(bcd 格式)(date units in bcd format)
rtc 控制寄存器 (rtc_cr)
位 23 coe:校准输出使能 (calibration output enable)
该位使能 rtc_calib 输出
0:禁止校准输出
1:使能校准输出
位 22:21 osel[1:0]:输出选择 (output selection)
这些位用于选择要连接到 rtc_alarm 输出的标志
00:禁止输出
01:使能闹钟 a 输出
10:使能闹钟 b 输出
11:使能唤醒输出
位 20 pol:输出极性 (output polarity)
该位用于配置 rtc_alarm 输出的极性
0:当 alraf/alrbf/wutf 置 1 时(取决于 osel[1:0]),该引脚为高电平
1:当 alraf/alrbf/wutf 置 1 时(取决于 osel[1:0]),该引脚为低电平
位 19 cosel:校准输出选择 (calibration output selection)
当 coe=1 时,该位可选择 rtc_calib 上输出的信号。
0:校准输出为 512 hz
1:校准输出为 1 hz
在 rtcclk 为 32.768 khz 且预分频器为其默认值(prediv_a=127 且 prediv_s=255)的条件下,这些频率有效。
位 18 bkp:备份 (backup)
用户可对此位执行写操作以记录是否已对夏令时进行更改。
位 17 sub1h:减少 1 小时(冬季时间更改)(subtract 1 hour (winter time change))
当该位在初始化模式以外的模式下置 1 时,如果当前小时不是 0,则日历时间将减少 1 小时。此位始终读为 0。当前小时为 0 时,将此位置 1 没有任何作用。
0:无作用。
1:将当前时间减少 1 小时。这可用于冬季时间更改。
位 16 add1h:增加 1 小时(夏季时间更改)(add 1 hour (summer time change))
当该位在初始化模式以外的模式下置 1 时,日历时间将增加 1 小时。此位始终读为 0。
0:无作用。
1:将当前时间增加 1 小时。这可用于夏季时间更改
位 15 tsie:时间戳中断使能 (timestamp interrupt enable)
0:禁止时间戳中断
1:使能时间戳中断
位 14 wutie:使能唤醒定时器使能 (wakeup timer interrupt enable)
0:禁止唤醒定时器中断
1:使能唤醒定时器中断
位 13 alrbie: ** 闹钟 b 中断使能 (alarm b interrupt enable)**
0:闹钟 b 中断禁止
1:闹钟 b 中断使能
位 12 alraie:闹钟 a 中断使能 (alarm a interrupt enable)
0:禁止闹钟 a 中断
1:使能闹钟 a 中断
位 11 tse:时间戳使能 (time stamp enable)
0:禁止时间戳
1:使能时间戳
位 10 wute:唤醒定时器使能 (wakeup timer enable)
0:禁止唤醒定时器
1:使能唤醒定时器
位 9 alrbe: ** 闹钟 b 使能 (alarm b enable)**
0:禁止闹钟 b
1:使能闹钟 b
位 8 alrae :闹钟 a 使能 (alarm a enable)
0:禁止闹钟 a
1:使能闹钟 a
位 7 dce :粗略数字校准使能 (coarse digital calibration enable)
0:禁止数字校准
1:使能数字校准
prediv_a 必须大于或等于 6
位 6 fmt:小时格式 (hour format)
0:24 小时/天格式
1:am/pm 小时格式
位 5 bypshad:旁路影子寄存器 (bypass the shadow registers)
0:日历值(从 rtc_ssr、rtc_tr 和 rtc_dr 读取时)取自影子寄存器,该影子寄存器每两个 rtcclk 周期更新一次。
1:日历值(从 rtc_ssr、rtc_tr 和 rtc_dr 读取时)直接取自日历计数器。
注意:如果 apb1 时钟的频率低于 7 倍的 rtcclk 频率,则必须将 bypshad 置“ 1 ”。
位 4 refckon: **参考时钟检测使能(50 hz 或 60 hz)(reference clock detection enable (50 or **60 hz))
0:禁止参考时钟检测
1:使能参考时钟检测
注意:prediv_s 必须为 0x00ff 。
位 3 tsedge:时间戳事件有效边沿 (timestamp event active edge)
0:timestamp 上升沿生成时间戳事件
1:timestamp 下降沿生成时间戳事件
tsedge 发生更改时,必须复位 tse 以避免将 tsf 意外置 1
位 2:0 wucksel[2:0]:唤醒时钟选择 (wakeup clock selection)
000:选择 rtc/16 时钟
001:选择 rtc/8 时钟
010:选择 rtc/4 时钟
011:选择 rtc/2 时钟
10x:选择 ck_spre 时钟(通常为 1 hz)
11x:选择 ck_spre 时钟(通常为 1 hz)并将 wut 计数器值增加 216
rtc 初始化和状态寄存器 (rtc_isr)
位 16 recalpf:重新校准挂起标志 (recalibration pending flag)
当软件对 rtc_calr 寄存器执行写操作时,recalpf 状态标志将自动置“1”,指示rtc_calr 寄存器已屏蔽。当采用新的校准设置时,该位恢复为“0”。
位 14 tamp2f:tamper2 检测标志 (tamper2 detection flag)
在入侵输入 2 上检测到入侵检测事件时,由硬件将此标志置 1。
该标志由软件写零清除。
位 13 tamp1f:入侵检测标志 (tamper detection flag)
当检测到入侵检测事件时,由硬件将此标志置 1。
该标志由软件写零清除。
位 12 tsovf:时间戳溢出标志 (timestamp overflow flag)
当在 tsf 已置 1 的情况下发生时间戳事件时,由硬件将此标志置 1。
该标志由软件写零清除。建议仅在 tsf 位清零之后再检查并清tsovf 位。否则,如果时间戳事件恰好在清零 tsf 位之前刚刚发生,则溢出事件可能会被漏掉。
位 11 tsf:时间戳标志 (timestamp flag)
发生时间戳事件时,由硬件将此标志置 1。
该标志由软件写零清除。
位 10 wutf:唤醒定时器标志 (wakeup timer flag)
当唤醒自动重载计数器计数到 0 时,由硬件将此标志置 1。
该标志由软件写零清除。
软件必须在 wutf 再次置 1 的 1.5 个 rtcclk 周期之前将该标志清零。
位 9 alrbf:闹钟 b 标志 (alarm b flag)
当时间/日期寄存器(rtc_tr 和 rtc_dr)与闹钟 b 寄存器 (rtc_alrmbr) 匹配时,由硬件将该标志置 1。该标志由软件写零清除。
位 8 alraf:闹钟 a 标志 (alarm a flag)
当时间/日期寄存器(rtc_tr 和 rtc_dr)与闹钟 a 寄存器 (rtc_alrmar) 匹配时,由
硬件将该标志置 1。
该标志由软件写零清除。
位 7 init:初始化模式 (initialization mode)
0:自由运行模式。
1:初始化模式,用于编程时间和日期寄存器(rtc_tr 和 rtc_dr)以及预分频器寄存器(rtc_prer)。计数器停止计数,当 init 被复位后,计数器从新值开始计数。
位 6 initf:初始化标志 (initialization flag)
当此位置 1 时,rtc 处于初始化状态,此时可更新事件、日期和预分频器寄存器。
0:不允许更新日历寄存器。
1:允许更新日历寄存器。
位 5 rsf:寄存器同步标志 (registers synchronization flag)
每次将日历寄存器的值复制到影子寄存器(rtc_ssrx、rtc_trx 和 rtc_drx)时,都会由硬件将此位置 1。在初始化模式下、平移操作挂起时 (shpf=1) 或在旁路影子寄存器模式 (bypshad=1) 下,该位由硬件清零。该位还可由软件清零。
0:日历影子寄存器尚未同步
1:日历影子寄存器已同步
位 4 inits:初始化状态标志 (initialization status flag)
当日历年份字段不为 0 时(上电复位状态),由硬件将该位置 1。
0:日历尚未初始化
1:日历已经初始化
位 3 shpf:平移操作挂起 (shift operation pending)
0:没有平移操作挂起
1:某个平移操作挂起
只要通过对 rtc_shiftr 寄存器执行写操作来启动平移操作,此标志便由硬件置 1。执行完相应的平移操作后,此标志由硬件清零。对 shpf 执行写入操作不起作用。
位 2 wutwf:唤醒定时器写标志 (wakeup timer write flag)
在 rtc_cr 寄存器中的 wute 位置 0 后,当唤醒定时器值可更改时,由硬件将该位置 1。
0:不允许更新唤醒定时器配置
1:允许更新唤醒定时器配置
位 1 alrbwf:闹钟 b 写标志 (alarm b write flag)
在 rtc_cr 寄存器中的 alrbie 位置 0 之后,当闹钟 b 的值可更改时,由硬件将该位置 1。该位在初始化模式下由硬件清零。
0:不允许更新闹钟 b
1:允许更新闹钟 b
位 0 alrawf:闹钟 a 写标志 (alarm a write flag)
在 rtc_cr 寄存器中的 alrae 位置 0 后,当闹钟 a 的值可更改时,由硬件将该位置 1。
该位在初始化模式下由硬件清零。
0:不允许更新闹钟 a
1:允许更新闹钟 a
rtc 预分频器寄存器 (rtc_prer)
预分频器寄存器复位值刚好使时钟频率为1hz,满足rtc的需求,所以这里不对其进行配置。
rtc初始化程序如下:
#include rtc.h#include stm32f4xx.hvoid rtc_init(u8 hour,u8 fen,u8 miao,u8 nian,u8 yue,u8 ri,u8 xingqi){ u32 temp = 0; rcc- >apb1enr |= 1< cr |= 1< bdcr &=~ (1< bdcr |= 1< bdcr & 1< bdcr &=~ (0x3< bdcr |= 1< bdcr |= 1< wpr = 0xca; //解除写保护 rtc- >wpr = 0x53; //解除写保护 rtc- >isr |= 1< isr & (1< <6))==0); //等待进入初始化模式 temp |= (hour/10)< <20 | (hour%10)< <16 | (fen/10)< <12 | (fen%10)< <8 | (miao/10)< tr = temp; temp = 0; temp |= (nian/10)< <20 | (nian%10)< <16 | (xingqi)< <13 | (yue/10)< <12 | (yue%10)< <8 | (ri/10)< dr = temp; rtc- >cr = 0; rtc- >isr &=~(1< wpr = 0; //写任意值,再次保护}编写主函数测试:
#include stm32f4xx.h#include usart.h#include delay.h#include stdio.h#include rtc.htypedef struct{ u8 shi; u8 fen; u8 miao; u8 nian; u8 yue; u8 ri; u8 xingqi;}time_typedef;time_typedef time = {1};int main(){ usart1_init(115200); rtc_init(23,59,50,19,7,9,2); while(1) { time.shi = ((rtc- >tr & 0x300000) >>20)*10 + ((rtc- >tr & 0xf0000) >>16); time.fen = ((rtc- >tr & 0x7000) >>12)*10 + ((rtc- >tr & 0xf00) >>8); time.miao = ((rtc- >tr & 0x70) >>4)*10 + (rtc- >tr & 0xf); printf(%d:%d:%drn,time.shi,time.fen,time.miao); delay_ms(1000); }}运行后可以看到串口输出了设置的时分秒计数,时间不会出错,rtc实时时钟测试成功。
但是在系统复位后,发现又重新从刚开始设的时间计时,这显然不是我们想要的,所以在这里再添加备份域的读写函数。
rtc 备份寄存器 (rtc_bkpxr)
rtc的备份域是在rtc基地址上偏移了0x50开始到偏移0x9c的范围。
//备份域//注意:备份域寄存器也受dbp位保护,在未初始化rtc模块的条件下,如果要使用备份域,//需单独开启dbp位//num:0~19void rtc_writebkpxr(u8 num,u32 dat){ u32 add = 0; num %= 20; add = rtc_base + 0x50 + 4*num; *((volatile u32 *)add) = dat;}u32 rtc_readbkpxr(u8 num){ u32 add = 0; num %= 20; add = rtc_base + 0x50 + 4*num; add = *((volatile u32 *)add); return add;}然后再在初始化函数中调用读取备份域函数,判断是否已经设置过时间,如果第一次设时间就写备份域的标记,再设置时间;不是第一次就直接开启计时。初始化函数更改如下:
void rtc_init(u8 hour,u8 fen,u8 miao,u8 nian,u8 yue,u8 ri,u8 xingqi){ u32 temp = 0; rcc- >apb1enr |= 1< cr |= 1< bdcr &=~ (1< bdcr |= 1< bdcr & 1< bdcr &=~ (0x3< bdcr |= 1< bdcr |= 1< wpr = 0xca; //解除写保护 rtc- >wpr = 0x53; //解除写保护 rtc- >isr |= 1< isr & (1< <6))==0); //等待进入初始化模式 temp = rtc_readbkpxr(0); if(temp != 0xaa) { rtc_writebkpxr(0,0xaa); temp = 0; temp |= (hour/10)< <20 | (hour%10)< <16 | (fen/10)< <12 | (fen%10)< <8 | (miao/10)< tr = temp; temp = 0; temp |= (nian/10)< <20 | (nian%10)< <16 | (xingqi)< <13 | (yue/10)< <12 | (yue%10)< <8 | (ri/10)< dr = temp; } rtc- >cr = 0; rtc- >isr &=~(1< wpr = 0; //写任意值,再次保护}主函数依旧不变,运行程序发现系统复位后,时间是继续复位之前的计时,不会再被重新设置,所以在用rtc时加上备份域就可以防止系统复位造成计时不理想。

美国在全球3D打印市场中持续靠前
PCB设计方法与技巧,PCB Design Methods and Techniques
网易游戏与华为达成鸿蒙合作
特斯拉纯电动皮卡车2020年投产 续航里程尚不清楚
极致轻薄!歌尔光学发布新一代小型化高性能AR显示模组
STM32 RTC实时时钟(一)
深亚微米 BiCMOS[B] 芯片与制程剖面结构
跟随德索工厂的步伐认识Fakra连接器发展历程
三星手机中国市场份额不足1%,转型迫在眉睫
Pickering Interfaces最近扩展了他们的PXI故障注入开关产品系列
水库浮标叶AD绿素你该如何检测?
上海泰格聚合物技术有限公司选购我司HS-TGA-101热重分析仪
光谱共焦位移传感器破解玻璃检测难题,为高精度玻璃测量舔砖加瓦
AI大模型的研发层出不穷,未来的算力缺口将更加惊人
三相交流伺服电机的应用及故障原因
聊一聊关于光纤适配器二三事
行业 | 赛灵思携手三星完成全球首例 5G 新无线电商用部署
新型纳米银线材料技术让触控具有无限发展空间
车市的下一个风口会是车联网吗
物联网十大技术趋势,如何把握?