本帖最后由 聚沃科技 于 2024-9-18 16:05 编辑
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中断 所有的RTC中断(闹钟、时间戳、侵入事件)都被连接到EXTI控制器。 4xx 系列 RTC 4xx系列RTC在x0系列RTC的基础上做了部分功能的升级。提供了一个包含日期(年/月/日)和时间(时/分/秒/亚秒)的日历功能。除亚秒用二进制码显示外,时间和日期都以BCD码的形式显示。 RTC可以进行夏令时补偿。RTC可以工作在省电模式下,并通过软件配置来智能唤醒。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,然后断电并上电后再下载新的代码。
教程由GD32 MCU方案商聚沃科技原创发布,了解更多GD32 MCU教程,关注聚沃科技官网,GD32MCU技术交流群:859440462
|