【GD32 MCU 入门教程】GD32 MCU 常见外设介绍(14)RTC 模块介绍

描述

GD32 MCU内部提供了一个RTC(实时时钟)模块,通过RTC可以实现日历时钟、闹钟等功能。RTC也可以用于深度睡眠或待机模式的低功耗唤醒。不同系列的GD32 MCU在RTC设计和功能上有所区别,总体可以分为三大系列:

(1)F10x、F30x、E10x系列RTC功能基本相同,后文简称0x系列。

(2)F1x0、F3x0、E23x系列RTC功能基本相同,后文简称x0系列。

(3)F405、F407、F450系列RTC功能基本相同,后文简称4xx系列。后文会对0x系列、x0系列、4xx系列的RTC模块分别进行介绍,简单介绍RTC的工作原理、配置使用方法。

14.1.GD32 RTC 外设简介

0x 系列 RTC

0x系列RTC整体架构相对精简,主要依靠32位累加计数器配置分频实现时钟计数。日历功能可通过软件计算并写入备份域中实现;同时具有闹钟功能可用于定时产生中断和唤醒唤醒事件;RTC的核心计数部分在备份域中,可在VDD断电时VBAT供电的情况保持RTC的计数,正常上电工作时通过APB总线接口可对RTC寄存器进行配置。

0x系列RTC主要特点:

◼ 32位可编程计数器,用于计数运行时间

– 可编程的预分频器: 分频系数最高可达220

◼ 独立时钟域:

– PCLK1时钟域

– RTC时钟域(该时钟必须比PCLK1时钟至少慢4倍)

◼ RTC时钟源:

– HXTAL时钟分频

– LXTAL振荡电路时钟

– IRC40K振荡电路时钟

◼ 可屏蔽的中断源:

– 闹钟中断

– 秒中断

– 溢出中断

0x系列RTC框图介绍:

RTC由两个主要部分组成,如下图0x系列RTC结构框图所示,位于PCLK1时钟域的APB接口和位于RTC时钟域的RTC内核。

单片机

第一部分APB接口用来和APB1总线相连。此单元还包含一组16位寄存器,可通过APB1总线对其进行读写操作。对RTC模块进行相关配置。

另一部分(RTC核心)由一组可编程计数器组成,分成两个主要模块。第一个模块是RTC的预分频模块,RTC时钟源输入后经过预分频模块,可编程产生RTC时间基准SC_CLK。RTC的预分频模块包含了一个20位的可编程分频器(RTC预分频器);如果在RTC_INTEN寄存器中设置了相应的允许位,则在每个SC_CLK周期中RTC产生一个中断(秒中断)。

第二个模块是一个32位的可编程计数器,可被初始化为当前的系统时间。系统时间按SC_CLK周期累加并与存储在RTC_ALRM寄存器中的可编程时间相比较,如果RTC_INTEN控制寄存器中设置了相应允许位,比较匹配时将产生一个闹钟中断。

x0 系列 RTC

0x系列RTC提供了一个包含日期(年/月/日)和时间(时/分/秒/亚秒)的日历功能。除亚秒用二进制码显示外,时间和日期都以BCD码的形式显示。RTC可以进行夏令时补偿。RTC可以工作在省电模式下,并通过软件配置来智能唤醒。RTC支持外接更高精度的低频时钟,用以达到更高的日历精度。

x0系列RTC主要特点:

◼ 通过软件设置来实现夏令时补偿。

◼ 参考时钟检测功能:通过外接更高精度的低频率时钟源(50Hz/60Hz)来提高日历精度。

◼ 数字校准功能:通过调整最小时间单位(最大可调精度0.95ppm)来进行日历校准。

◼ 通过移位功能进行亚秒级调整。

◼ 记录事件时间的时间戳功能。

◼ 两个模式可配置的独立的侵入检测。

◼ 可编程的日历和一个位域可屏蔽的闹钟。

◼ 5个32位(共20字节)通用备份寄存器,能够在省电模式下保存数据。当有外部事件侵入时,备份寄存器将会复位。

◼ 可屏蔽的中断源:

– 闹钟0;

– 时间戳检测;

– 侵入检测;

x0系列RTC框图介绍:

x0系列RTC工作在备份域,可在低功耗模式下保持工作,通过APB总线可对RTC寄存器进行读取和配置。如下图x0系列RTC结构框图所示,RTC时钟源可配置通过数字平滑校准或直接输入到7位异步预分频器输出ck_apre时钟用于RTC_SS亚秒寄存器自减计数,ck_apre时钟又经过15位同步预分频器后输出1HZ的ck_spre时钟提供日历寄存器使用;基于日历寄存器还实现了闹钟和时间戳功能;RTC还具有闹钟、时钟输出功能,对RTC_TS、RTC_TAMP0、RTC_TAMP1引脚的有效输入可触发时间戳和侵入事件并产生中断。侵入事件会将备份域复位。

单片机

◼ 闹钟

RTC闹钟功能被划分为多个位域并且每一个位域有一个该域的可屏蔽位。屏蔽某些位域后可固定周期产生闹钟事件。

◼ 侵入事件

RTC_TAMPx管脚可以作为侵入事件检测功能输入管脚,检测模式有两种可供用户选择:边沿检测模式或者是带可配置滤波功能的电平检测模式。侵入事件会将备份域复位,可产生一个中断。

◼ 可选的RTC输出功能:

512Hz( 默认预分频值): RTC_OUT;

1Hz( 默认预分频值): RTC_ OUT;

闹钟事件( 极性可配置): RTC_ OUT。

◼ 可选的RTC输入功能:

时间戳事件检测( RTC_TS);

侵入事件检测 0( RTC_TAMP0);

侵入事件检测 1( RTC_TAMP1);

参考时钟输入 RTC_REFIN( 50 或 60Hz)。

◼ RTC中断

所有的RTC中断(闹钟、时间戳、侵入事件)都被连接到EXTI控制器。

4xx 系列 RTC 4xx系列RTC在x0系列RTC的基础上做了部分功能的升级。提供了一个包含日期(年/月/日)和时间(时/分/秒/亚秒)的日历功能。除亚秒用二进制码显示外,时间和日期都以BCD码的形式显示。

RTC可以进行夏令时补偿。RTC可以工作在省电模式下,并通过软件配置来智能唤醒。RTC支持外接更高精度的低频时钟,用以达到更高的日历精度。

  1. 4xx系列RTC主要特点:

◼ 通过软件设置来实现夏令时补偿。

◼ 参考时钟检测功能:通过外接更高精度的低频率时钟源(50Hz或60Hz)来提高日历精度。

◼ 数字校准功能:通过调整最小时间单位(最大可调精度0.95ppm)来进行日历校准。

◼ 通过移位功能进行亚秒级调整。

◼ 记录事件时间的时间戳功能。

◼ 两个模式可配置的独立的侵入检测。

◼ 可编程的日历和一个位域可屏蔽的闹钟。

◼ 20个32位(共80字节)通用备份寄存器,能够在省电模式下保存数据。当有外部事件侵入时,备份寄存器将会复位。

◼ 可屏蔽的中断源:

– 闹钟0和闹钟1;

– 时间戳检测;

– 自动唤醒事件;

– 侵入检测;

◼ 可配置周期的自动唤醒定时器

4xx系列RTC框图介绍:

4xx系列RTC工作在备份域,可在低功耗模式下保持工作,通过APB总线可对RTC寄存器进行读取和配置。如下图4xx系列RTC结构框图所示,RTC时钟源可配置通过数字平滑校准或直接输入到7位异步预分频器输出ck_apre时钟用于RTC_SS亚秒寄存器自减计数,ck_apre时钟又可通过数字粗平滑校准或直接输入15位同步预分频器后输出1HZ的ck_spre时钟提供日历寄存器使用;基于日历寄存器还实现了闹钟和时间戳功能;RTC还具有闹钟、时钟输出功能,对RTC_TS、RTC_TAMP0、RTC_TAMP1引脚的有效输入可触发时间戳和侵入事件并产生中断。侵入事件会将备份域复位。4xx系列RTC有一个独立的自动重加载唤醒定时器可用于产生唤醒事件和中断。

单片机

◼ 闹钟

RTC闹钟功能被划分为多个位域并且每一个位域有一个该域的可屏蔽位。屏蔽某些位域后可固定周期产生闹钟事件。

◼ 侵入事件

RTC_TAMPx管脚可以作为侵入事件检测功能输入管脚,检测模式有两种可供用户选择:边沿检测模式或者是带可配置滤波功能的电平检测模式。侵入事件会将备份域复位,可产生一个中断。

◼ 可选的RTC输出功能:

512Hz(默认预分频值):(RTC_OUT)PC13

1Hz(默认预分频值):(RTC_OUT)PC13

闹钟事件(极性可配置):(RTC_OUT)PC13

自动唤醒事件(极性可配置):(RTC_OUT)PC13

◼ 可选的RTC输入功能:

时间戳事件检测(RTC_TS):RTC_AF0、RTC_AF1;

侵入事件检测 0(RTC_TAMP0):RTC_AF0、RTC_AF1;

侵入事件检测 1(RTC_TAMP1):RTC_AF1;

参考时钟输入 RTC_REFIN(50或60Hz)。

◼ RTC中断

所有的RTC中断(闹钟0、闹钟1、唤醒、时间戳、侵入0、侵入1)都被连接到EXTI控制器。

各系列 RTC 模块功能对比

x0系列中的E23x系列均没有VBAT引脚,不支持VDD掉电保持RTC工作。

0x系列备份域不同于x0、4xx系列,为单独的一个外设模块,所以使用RTC时,0x系列相比x0系列和4xx系列还需使能BKP的时钟。

各系列 RTC 模块功能对比

单片机

14.2.GD32 RTC 硬件设计

◼ Vbat电源设计

Vbat可以连接至外部电池,在Vdd掉电时可以保证备份域不掉电、RTC继续运行。VBAT引脚需要对GND连接0.1uF电容,如果没有外部电池需要将VBAT和一个0.1uF电容连接至Vdd电源上。

单片机

◼ RTC_TAMPx引脚

入侵事件会导致备份域复位,如使用该功能需注意检测引脚的滤波,可在RTC_TAMPx引脚上并联0.1uf电容。

14.3.GD32 RTC 软件配置

GD32MCU_Example下的RTC_Example例程配置了日历和闹钟功能,并开启了闹钟中断。本小节讲解RTC_Example例程中RTC模块的配置说明,主要包括时钟及分频配置、日历配置、闹钟配置、主函数说明。本例程主要介绍GD32 MCU各系列RTC模块的时间、闹钟配置,有关RTC其他功能例程可参考各系列固件库例程。

时钟及分频配置

◼ 由于RTC工作在备份域,所以使用RTC时需要使能备份域写功能,而控制备份域写功能的寄存器位于PMU中,所以操作RTC还需要将PMU_CTL寄存中的BKPWEN置位,从而还需使能PMU的时钟。而对于0x系列备份域为单独的外设,还需额外使能BKP备份域时钟。

◼ 为了实现准确的日历功能,配置RTC前需要准备好需要的时钟源,在选择合适的时钟源后RTC还需要进行预分频的配置。

0x系列时钟及分频配置如代码清单 RTC 0x系列时钟及分频配置所示,RTC使能后需要等待RTC寄存器和APB1时钟同步,执行rtc_register_sync_wait()函数;此外0x系列RTC在RTC寄存器配 置时需要等待上一次配置结束才能继续新的配置,所以在每个寄存器配置前需要执行rtc_lwoff_wait()函数,等待LWOFF置位。

代码清单 RTC 0x 系列时钟及分频配置

void rtc_config(void) { uint32_t prescaler=0; /* enable PMU and BKPI clocks */ rcu_periph_clock_enable(RCU_BKPI); rcu_periph_clock_enable(RCU_PMU); /* allow access to BKP domain */ pmu_backup_write_enable(); #if RTC_CLOCK_SOURCE_IRC40K prescaler=40000; /* enable LXTAL */ rcu_osci_on(RCU_IRC40K); /* wait till LXTAL is ready */ rcu_osci_stab_wait(RCU_IRC40K); /* select RCU_LXTAL as RTC clock source */ rcu_rtc_clock_config(RCU_RTCSRC_IRC40K); #elif RTC_CLOCK_SOURCE_LXTAL prescaler=32767; /* enable LXTAL */ rcu_osci_on(RCU_LXTAL); /* wait till LXTAL is ready */ rcu_osci_stab_wait(RCU_LXTAL); /* select RCU_LXTAL as RTC clock source */ rcu_rtc_clock_config(RCU_RTCSRC_LXTAL); #else #error RTC clock source should be defined. #endif /* RTC_CLOCK_SOURCE_IRC40K */ /* enable RTC Clock */ rcu_periph_clock_enable(RCU_RTC); /* wait for RTC registers synchronization */ rtc_register_sync_wait(); /* wait until last write operation on RTC registers has finished */ rtc_lwoff_wait(); /* set RTC prescaler: set RTC period to 1s */ rtc_prescaler_set(prescaler); rtc_lwoff_wait(); rtc_interrupt_enable(RTC_INT_ALARM); rtc_lwoff_wait(); }

x0系列时钟及分频配置如代码清单 RTC x0系列时钟及分频配置所示,RTC使能后需要等待RTC寄存器和APB1时钟同步,执行rtc_register_sync_wait()函数;和0x系列不同,后续配置过程x0和4xx系列均不需要执行rtc_lwoff_wait()函数。

代码清单 RTC x0 系列时钟及分频配置

void rtc_config(void) { /* enable PMU clock */ rcu_periph_clock_enable(RCU_PMU); /* enable the access of the RTC registers */ pmu_backup_write_enable(); #if (RTC_CLOCK_SOURCE_IRC40K) rcu_osci_on(RCU_IRC40K); rcu_osci_stab_wait(RCU_IRC40K); rcu_rtc_clock_config(RCU_RTCSRC_IRC40K); prescaler_s = 0x18F; prescaler_a = 0x63; #elif (RTC_CLOCK_SOURCE_LXTAL) rcu_osci_on(RCU_LXTAL); rcu_osci_stab_wait(RCU_LXTAL); rcu_rtc_clock_config(RCU_RTCSRC_LXTAL); prescaler_s = 0xFF; prescaler_a = 0x7F; #else #error RTC clock source should be defined. #endif /* RTC_CLOCK_SOURCE_IRC40K */ rcu_periph_clock_enable(RCU_RTC); rtc_register_sync_wait(); rtc_interrupt_enable(RTC_INT_ALARM); }

4xx系列时钟及分频配置如代码清单 RTC 4xx系列时钟及分频配置所示,和x0系列基本相同,但由于4xx系列内部低速时钟为32K,所以分频系数和x0系列有所不同。

代码清单 RTC 4xx 系列时钟及分频配置

void rtc_config(void) { /* enable PMU clock */ rcu_periph_clock_enable(RCU_PMU); /* enable the access of the RTC registers */ pmu_backup_write_enable(); #if (RTC_CLOCK_SOURCE_IRC32K) rcu_osci_on(RCU_IRC32K); rcu_osci_stab_wait(RCU_IRC32K); rcu_rtc_clock_config(RCU_RTCSRC_IRC32K); prescaler_s = 0x13F; prescaler_a = 0x63; #elif (RTC_CLOCK_SOURCE_LXTAL) rcu_osci_on(RCU_LXTAL); rcu_osci_stab_wait(RCU_LXTAL); rcu_rtc_clock_config(RCU_RTCSRC_LXTAL); prescaler_s = 0xFF; prescaler_a = 0x7F; #else #error RTC clock source should be defined. #endif /* RTC_CLOCK_SOURCE_IRC32K */ rcu_periph_clock_enable(RCU_RTC); rtc_register_sync_wait(); rtc_interrupt_enable(RTC_INT_ALARM0); }

日历配置

0x系列由于没有硬件日历功能,所以需要读取计数器通过软件计算出日历;而x0系列和4xx系列具有硬件日历功能,日期信息均是BCD码,所以在日历配置的格式和方式均有差别。

0x系列RTC的日历配置如代码清单 RTC 0x系列日历配置所示,该函数提供了日历配置的入口参数,先将需要配置的日历信息转换成秒单位,再写入RTC计数器即可。入口参数使用十进制写入。

代码清单 RTC 0x 系列日历配置

uint32_t rtc_time_set(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { uint16_t t; uint32_t seccount = 0; if(year < 1970 || year > 2099) return ERROR; for(t = 1970; t < year; t++){ if(is_leap_year(t)){ seccount += 31622400; }else{ seccount += 31536000; } } month -= 1; for(t=0; t < month; t++){ seccount += (uint32_t)month_table[t] * 86400; if(is_leap_year(year) && t==1){ seccount+=86400; } } seccount += (uint32_t)(day-1) * 86400; seccount += (uint32_t)hour * 3600; seccount += second; rtc_lwoff_wait(); rtc_counter_set(seccount); rtc_lwoff_wait(); return SUCCESS; }

x0系列RTC的日历配置如代码清单 RTC x0系列日历配置所示,该函数提供了日历配置的入口参数,参数为BCD码格式,写入后对RTC日历结构体赋初值,日历结构体还可以配置星期、时间格式等,这里默认配置了24小时制。函数入口参数使用16进制写入。

代码清单 RTC x0 系列日历配置

uint32_t rtc_time_set(uint16_t year,uint8_t month,uint8_t day,uint32_t tmp_hh,uint32_t tmp_mm,uint32_t tmp_ss) { rtc_initpara.rtc_factor_asyn = prescaler_a; rtc_initpara.rtc_factor_syn = prescaler_s; rtc_initpara.rtc_year = year&0x00ff; rtc_initpara.rtc_day_of_week = RTC_SATURDAY; rtc_initpara.rtc_month = month; rtc_initpara.rtc_date = day; rtc_initpara.rtc_display_format = RTC_24HOUR; rtc_initpara.rtc_am_pm = RTC_AM; rtc_initpara.rtc_hour = tmp_hh; rtc_initpara.rtc_minute = tmp_mm; rtc_initpara.rtc_second = tmp_ss; if(ERROR == rtc_init(&rtc_initpara)){ return ERROR; } return SUCCESS; }

4xx系列RTC的日历配置如代码清单 0-52 RTC 4xx系列日历配置所示,和x0系列基本相同, 唯一区别只是日历结构体成员名字少了“RTC_”的前缀。

代码清单 RTC 4xx 系列日历配置

uint32_t rtc_time_set(uint16_t year,uint8_t month,uint8_t day,uint32_t tmp_hh,uint32_t tmp_mm,uint32_t tmp_ss) { rtc_initpara.factor_asyn = prescaler_a; rtc_initpara.factor_syn = prescaler_s; rtc_initpara.year = year&0x00ff; rtc_initpara.day_of_week = RTC_SATURDAY; rtc_initpara.month = month; rtc_initpara.date = day; rtc_initpara.display_format = RTC_24HOUR; rtc_initpara.am_pm = RTC_AM; rtc_initpara.hour = tmp_hh; rtc_initpara.minute = tmp_mm; rtc_initpara.second = tmp_ss; if(ERROR == rtc_init(&rtc_initpara)){ return ERROR; } return SUCCESS; }

闹钟配置

0x系列的RTC通过32位计数器运行时间,所以其闹钟也是32位数据,当计数器和闹钟值匹配时会产生闹钟事件或中断,所需配置的闹钟值为闹钟剩余倒计时加上当前计数器值;而x0系列和4xx系列是硬件BCD日历功能,所以其闹钟也是BDC格式,且具有位域屏蔽功能,根据需要直接配置具体的时间即可。

0x系列RTC的闹钟配置如代码清单 RTC 0x系列闹钟配置所示,该函数提供了闹钟配置的入口参数,先将需要配置的时间信息转换成秒单位,再加上当前计数器的值写入闹钟寄存器即可。

0x系列配置的闹钟参数为闹钟中断的倒计时时间,写入参数为十进制。

代码清单 RTC 0x 系列闹钟配置

void rtc_alarm_set(uint8_t hour, uint8_t minute, uint8_t second) { alarm_second = 3600 * hour + minute * 60 + second; rtc_lwoff_wait(); rtc_alarm_config(rtc_counter_get() + alarm_second); rtc_lwoff_wait(); } seccount += (uint32_t)(day-1) * 86400; seccount += (uint32_t)hour * 3600; seccount += (uint32_t)minute * 60; seccount += second; rtc_lwoff_wait(); rtc_counter_set(seccount); rtc_lwoff_wait(); return SUCCESS; }

x0系列RTC的闹钟配置如代码清单 RTC x0系列闹钟配置所示,该函数提供了闹钟配置的入口参数,参数为BCD码格式,写入后对RTC闹钟结构体赋初值,闹钟结构体可以配置位域屏蔽、选择配置日期或星期、时间格式等,这里默认配置了屏蔽天、小时、分钟,所以配置最后实际生效的只有秒,所以配置后闹钟均是1分钟产生一次。闹钟配置前需失能闹钟,配置后再使能,4xx系列配置的闹钟参数为闹钟产生的日期时间,因BCD格式写入参数参数使用16进制。

代码清单 RTC x0 系列闹钟配置

void rtc_alarm_set(uint32_t tmp_hh,uint32_t tmp_mm,uint32_t tmp_ss) { rtc_alarm_struct rtc_alarm; rtc_alarm_disable(); rtc_alarm.rtc_alarm_mask = RTC_ALARM_DATE_MASK|RTC_ALARM_HOUR_MASK|RTC_ALARM_MINUTE_MASK; rtc_alarm.rtc_weekday_or_date = RTC_ALARM_DATE_SELECTED; rtc_alarm.rtc_alarm_day = 0x31; rtc_alarm.rtc_am_pm = RTC_AM; rtc_alarm.rtc_alarm_hour = tmp_hh; rtc_alarm.rtc_alarm_minute = tmp_mm; rtc_alarm.rtc_alarm_second = tmp_ss; rtc_alarm_config(&rtc_alarm); rtc_alarm_enable(); }

4xx系列RTC的闹钟配置如代码清单 0-55 RTC 4xx系列闹钟配置所示,和x0系列基本相同, 唯一区别只是闹钟结构体成员名字少了“RTC_”的前缀。

代码清单 RTC 4xx 系列闹钟配置

uint32_t rtc_time_set(uint16_t year,uint8_t month,uint8_t day,uint32_t tmp_hh,uint32_t tmp_mm,uint32_t tmp_ss) { rtc_initpara.factor_asyn = prescaler_a; rtc_initpara.factor_syn = prescaler_s; rtc_initpara.year = year&0x00ff; rtc_initpara.day_of_week = RTC_SATURDAY; rtc_initpara.month = month; rtc_initpara.date = day; rtc_initpara.display_format = RTC_24HOUR; rtc_initpara.am_pm = RTC_AM; rtc_initpara.hour = tmp_hh; rtc_initpara.minute = tmp_mm; rtc_initpara.second = tmp_ss; if(ERROR == rtc_init(&rtc_initpara)){ return ERROR; } return SUCCESS; }

主函数说明 主函数如代码清单 RTC_Example主函数所示,主要包含了中断配置、RTC时钟源和预分频配置、日历设置以及闹钟设置,成功设置好日历和闹钟后在备份域数据寄存器写入一个标志位,下次非备份域复位的情况就可以不再重复配置RTC。While1中循环调用rtc_current_time_get()函数获取日历信息。4xx系列和x0系列中固件库底层已经提供了rtc_current_time_get()函数,直接更新至日历结构体;而0x系列固件库没有此函数,额外编写了相同接口的函数,通过读取32位计数器软件计算出日历信息更新至自定义的日历结构体中。通过仿真或串口打印可以看到结构体中的时间数据在更新。

代码清单 RTC_Example 主函数

int main(void) { /* NVIC configure */ nvic_config(); rtc_config(); alarm_second=5; if (RTC_BKP0 != 0xA5A5){ /* backup data register value is not correct or not yet programmed (when the first time the program is executed) */ #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X if(SUCCESS==rtc_time_set(2019, 10, 14, 12, 0, 0)){ rtc_alarm_set(12, 12, alarm_second); #elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X if(SUCCESS==rtc_time_set(0x2019, 0x10, 0x14, 0x12, 0, 0)){ rtc_alarm_set(0x12, 0x12, alarm_second); #endif RTC_BKP0=0xA5A5; } } while (1){ /* updata time in infinite loop */ rtc_current_time_get(&rtc_initpara); } }

代码清单 0x 系列自定义 rtc_current_time_get()主函数

void rtc_current_time_get(rtc_parameter_struct* RTC_Calend) { static uint16_t daycnt = 0; uint32_t temp = 0,timevar=rtc_counter_get(); uint16_t temp1 = 0; temp = timevar / 86400; if(daycnt != temp) { daycnt = temp; temp1 = 1970; while(temp >= 365){ if(is_leap_year(temp1)){ if(temp >= 366) temp-=366; else break; }else temp -= 365; temp1++; } RTC_Calend->years = temp1; temp1=0; while(temp >= 28) { if(is_leap_year(RTC_Calend->years) && temp1 == 1){ if(temp >= 29) temp -= 29; else break; }else{ if(temp >= month_table[temp1]) temp -= month_table[temp1]; else break; } temp1++; } RTC_Calend->months = temp1 + 1; RTC_Calend->days = temp + 1; } temp = timevar % 86400; RTC_Calend->hours = temp / 3600; RTC_Calend->minutes = (temp % 3600) / 60; RTC_Calend->seconds = (temp % 3600) % 60; }

闹钟中断说明

例程中开启了闹钟中断,初始化调用rtc_alarm_set(uint8_t hour, uint8_t minute, uint8_t second)函数分别配置了“0时0分5秒”的闹钟。

◼ 对0x系列来说这个配置是倒计时“0时0分5秒”后产生闹钟,进入闹钟中断后再配置新的5s实现5s一次的闹钟周期;

◼ 对x0和4xx系列这个配置是时间在“0时0分5秒”时产生闹钟,但因为闹钟配置中已经屏蔽了闹钟的天、时、分位域,所以闹钟会在每分钟的5秒产生,闹钟周期为一分钟产生一次。

14.4.RTC 使用注意事项

1、 因为内部低速时钟是在VDDA电源域,所以VDD断电后VBAT供电情况下保持RTC运行需要使用外部低速时钟;此外使用LXTAL在非备份域复位时可以不用在初始化阶段配置,但使用内部低速时钟需要每次复位都进行内部时钟的初始化。

2、 内部低速时钟精度相对较差,如必须使用内部且对精度有一定要求,4xx和0x系列可以使用TIMER4、x0系列可以使用TIMER13捕获内部低速时钟,计算出实际的频率值来进行合适分频。

3、 日历信息意外被清零的话注意是否发生过备份域复位,是否有Vbat掉电或入侵事件发生。

4、 调试中如果修改了RTC代码的配置,请先擦除全片Flash,然后断电并上电后再下载新的代码。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分