0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

聚沃科技 2024-08-23 09:18 次阅读

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,然后断电并上电后再下载新的代码。

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

    关注

    6032

    文章

    44513

    浏览量

    632865
  • 嵌入式
    +关注

    关注

    5068

    文章

    19014

    浏览量

    303158
  • 开发板
    +关注

    关注

    25

    文章

    4943

    浏览量

    97183
  • RTC
    RTC
    +关注

    关注

    2

    文章

    527

    浏览量

    66302
收藏 人收藏

    评论

    相关推荐

    GD32 MCU 入门教程GD32 MCU 常见外设介绍(12)FMC 模块介绍

    闪存控制器(FMC),提供了片上闪存需要的所有功能。FMC 也提供了页擦除,整片擦除,以及32 位整字或 16 位半字编程闪存等操作。 GD32 MCU 支持不同类型编程的具体说明如下表 GD32
    的头像 发表于 08-21 09:56 978次阅读
    <b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> <b class='flag-5'>入门教程</b>】<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> <b class='flag-5'>常见外设</b><b class='flag-5'>介绍</b>(12)FMC <b class='flag-5'>模块</b><b class='flag-5'>介绍</b>

    GD32 MCU移植

    gd32是一款国产单片机。该芯片在很多方面和STM32有异曲同工之处。资料不是很多! GD32外设方面、和STM32没有多大区别。 只是需要注意资源的引脚分配。虽然和STM32使用方式一样、但是也存在
    发表于 03-23 13:40

    GD32MCU介绍

    其实兆芯的MCU为了兼容ST,外设的寄存器设计与ST保持一致了。比如GD32VF103或者GD32E103系列的USBFS这个外设,基本等同
    发表于 11-01 06:03

    GD32 MCU原理及固件库开发指南》 + 初读感悟

    GD32 MCU原理固件库开发指南这本书内容丰富,囊括了GD32中的所有外设,书中首先介绍了如何使用MDK或IAR软件搭建
    发表于 03-31 22:11

    GD32 MCU原理及固件库开发指南》+读后感

    GD32 MCU的电源管理系统及复位、时钟系统。 第5章介绍GD32 MCU的基础外设,包括GP
    发表于 06-06 21:52

    兆易创新GD32 MCU选型手册,适用于GD32全系列MCU

    兆易创新GD32MCU选型手册,适用于GD32全系列MCUGD32MCU选型手册,适用于GD32全系列MCU
    发表于 10-19 17:26 49次下载

    你了解GD32 MCU的命名规则吗

    下面为大家介绍GD32 MCU的通用命名规则,以GD32F303ZGT6为例,其中,GD32代表GD32
    的头像 发表于 01-13 09:38 3437次阅读
    你了解<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b>的命名规则吗

    GD32 MCU的选项字节是什么?

    GD32 MCU的选项字节是什么,有什么功能呢?选项字节被误篡改如何回复?
    的头像 发表于 01-17 09:42 1257次阅读
    <b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b>的选项字节是什么?

    不同型号的GD32 MCU如何区分?

    大家是否碰到过以下应用场景:同一套软件代码希望跑在不同型号的GD32 MCU中,但有些地方需要根据MCU型号进行调整?或者上位机或其他MCUGD3
    的头像 发表于 01-27 09:32 945次阅读
    不同型号的<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b>如何区分?

    GD32 MCU 入门教程】一、GD32 MCU 开发环境搭建(1)使用Keil开发GD32

    GD32系列为通用型MCU,所以开发环境也可以使用通用型的IDE,目前使用较多的是KEIL、IAR、 GCC和Embedded Builder,客户可以根据个人喜好来选择相应的开发环境。
    的头像 发表于 08-08 15:01 1005次阅读
    【<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> <b class='flag-5'>入门教程</b>】一、<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> 开发环境搭建(1)使用Keil开发<b class='flag-5'>GD32</b>

    GD32 MCU 入门教程】一、GD32 MCU 开发环境搭建(2)使用 IAR 开发 GD32

    GD32系列为通用型MCU,所以开发环境也可以使用通用型的IDE,目前使用较多的是KEIL、IAR、 GCC和Embedded Builder,客户可以根据个人喜好来选择相应的开发环境。
    的头像 发表于 08-08 15:40 587次阅读
    【<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> <b class='flag-5'>入门教程</b>】一、<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> 开发环境搭建(2)使用 IAR 开发 <b class='flag-5'>GD32</b>

    GD32 MCU 入门教程】一、GD32 MCU 开发环境搭建(3)使用 Embedded Builder 开发 GD32

    GD32系列为通用型MCU,所以开发环境也可以使用通用型的IDE,目前使用较多的是KEIL、IAR、 GCC和Embedded Builder,客户可以根据个人喜好来选择相应的开发环境。
    的头像 发表于 08-08 16:03 824次阅读
    【<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> <b class='flag-5'>入门教程</b>】一、<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> 开发环境搭建(3)使用 Embedded Builder 开发 <b class='flag-5'>GD32</b>

    GD32 MCU 入门教程】二、GD32 MCU 烧录说明(1)ISP 烧录

    ISP:In System Programing,在系统编程,通过MCU片内的引导程序进行Flash编程。 GD32片内有一个只读信息块,用于存放引导装载程序,引导程序在MCU出厂前就会提前烧录好
    的头像 发表于 08-08 16:20 751次阅读
    【<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> <b class='flag-5'>入门教程</b>】二、<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> 烧录说明(1)ISP 烧录

    GD32 MCU 入门教程GD32 MCU FPU 使用方法

    GD32 MCU FPU 使用方法
    的头像 发表于 08-25 09:24 465次阅读
    【<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> <b class='flag-5'>入门教程</b>】<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> FPU 使用方法

    GD32 MCU入门教程GD32 MCU GPIO 结构与使用注意事项

    本文是专门为基于GD32 MCU开发的工程设计人员提供,主要介绍了GPIO的功能配置、内部结构以及在不同场景使用时的注意事项,旨在帮助GD32 MC
    的头像 发表于 09-07 10:34 580次阅读
    【<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b><b class='flag-5'>入门教程</b>】<b class='flag-5'>GD32</b> <b class='flag-5'>MCU</b> GPIO 结构与使用注意事项