GD32 MCU內(nèi)部提供了一個(gè)RTC(實(shí)時(shí)時(shí)鐘)模塊,通過RTC可以實(shí)現(xiàn)日歷時(shí)鐘、鬧鐘等功能。RTC也可以用于深度睡眠或待機(jī)模式的低功耗喚醒。不同系列的GD32 MCU在RTC設(shè)計(jì)和功能上有所區(qū)別,總體可以分為三大系列:
(1)F10x、F30x、E10x系列RTC功能基本相同,后文簡稱0x系列。
(2)F1x0、F3x0、E23x系列RTC功能基本相同,后文簡稱x0系列。
(3)F405、F407、F450系列RTC功能基本相同,后文簡稱4xx系列。后文會(huì)對(duì)0x系列、x0系列、4xx系列的RTC模塊分別進(jìn)行介紹,簡單介紹RTC的工作原理、配置使用方法。
14.1.GD32 RTC 外設(shè)簡介
0x 系列 RTC
0x系列RTC整體架構(gòu)相對(duì)精簡,主要依靠32位累加計(jì)數(shù)器配置分頻實(shí)現(xiàn)時(shí)鐘計(jì)數(shù)。日歷功能可通過軟件計(jì)算并寫入備份域中實(shí)現(xiàn);同時(shí)具有鬧鐘功能可用于定時(shí)產(chǎn)生中斷和喚醒喚醒事件;RTC的核心計(jì)數(shù)部分在備份域中,可在VDD斷電時(shí)VBAT供電的情況保持RTC的計(jì)數(shù),正常上電工作時(shí)通過APB總線接口可對(duì)RTC寄存器進(jìn)行配置。
0x系列RTC主要特點(diǎn):
? 32位可編程計(jì)數(shù)器,用于計(jì)數(shù)運(yùn)行時(shí)間
– 可編程的預(yù)分頻器: 分頻系數(shù)最高可達(dá)220
? 獨(dú)立時(shí)鐘域:
– PCLK1時(shí)鐘域
– RTC時(shí)鐘域(該時(shí)鐘必須比PCLK1時(shí)鐘至少慢4倍)
? RTC時(shí)鐘源:
– HXTAL時(shí)鐘分頻
– LXTAL振蕩電路時(shí)鐘
– IRC40K振蕩電路時(shí)鐘
? 可屏蔽的中斷源:
– 鬧鐘中斷
– 秒中斷
– 溢出中斷
0x系列RTC框圖介紹:
RTC由兩個(gè)主要部分組成,如下圖0x系列RTC結(jié)構(gòu)框圖所示,位于PCLK1時(shí)鐘域的APB接口和位于RTC時(shí)鐘域的RTC內(nèi)核。

第一部分APB接口用來和APB1總線相連。此單元還包含一組16位寄存器,可通過APB1總線對(duì)其進(jìn)行讀寫操作。對(duì)RTC模塊進(jìn)行相關(guān)配置。
另一部分(RTC核心)由一組可編程計(jì)數(shù)器組成,分成兩個(gè)主要模塊。第一個(gè)模塊是RTC的預(yù)分頻模塊,RTC時(shí)鐘源輸入后經(jīng)過預(yù)分頻模塊,可編程產(chǎn)生RTC時(shí)間基準(zhǔn)SC_CLK。RTC的預(yù)分頻模塊包含了一個(gè)20位的可編程分頻器(RTC預(yù)分頻器);如果在RTC_INTEN寄存器中設(shè)置了相應(yīng)的允許位,則在每個(gè)SC_CLK周期中RTC產(chǎn)生一個(gè)中斷(秒中斷)。
第二個(gè)模塊是一個(gè)32位的可編程計(jì)數(shù)器,可被初始化為當(dāng)前的系統(tǒng)時(shí)間。系統(tǒng)時(shí)間按SC_CLK周期累加并與存儲(chǔ)在RTC_ALRM寄存器中的可編程時(shí)間相比較,如果RTC_INTEN控制寄存器中設(shè)置了相應(yīng)允許位,比較匹配時(shí)將產(chǎn)生一個(gè)鬧鐘中斷。
x0 系列 RTC
0x系列RTC提供了一個(gè)包含日期(年/月/日)和時(shí)間(時(shí)/分/秒/亞秒)的日歷功能。除亞秒用二進(jìn)制碼顯示外,時(shí)間和日期都以BCD碼的形式顯示。RTC可以進(jìn)行夏令時(shí)補(bǔ)償。RTC可以工作在省電模式下,并通過軟件配置來智能喚醒。RTC支持外接更高精度的低頻時(shí)鐘,用以達(dá)到更高的日歷精度。
x0系列RTC主要特點(diǎn):
? 通過軟件設(shè)置來實(shí)現(xiàn)夏令時(shí)補(bǔ)償。
? 參考時(shí)鐘檢測功能:通過外接更高精度的低頻率時(shí)鐘源(50Hz/60Hz)來提高日歷精度。
? 數(shù)字校準(zhǔn)功能:通過調(diào)整最小時(shí)間單位(最大可調(diào)精度0.95ppm)來進(jìn)行日歷校準(zhǔn)。
? 通過移位功能進(jìn)行亞秒級(jí)調(diào)整。
? 記錄事件時(shí)間的時(shí)間戳功能。
? 兩個(gè)模式可配置的獨(dú)立的侵入檢測。
? 可編程的日歷和一個(gè)位域可屏蔽的鬧鐘。
? 5個(gè)32位(共20字節(jié))通用備份寄存器,能夠在省電模式下保存數(shù)據(jù)。當(dāng)有外部事件侵入時(shí),備份寄存器將會(huì)復(fù)位。
? 可屏蔽的中斷源:
– 鬧鐘0;
– 時(shí)間戳檢測;
– 侵入檢測;
x0系列RTC框圖介紹:
x0系列RTC工作在備份域,可在低功耗模式下保持工作,通過APB總線可對(duì)RTC寄存器進(jìn)行讀取和配置。如下圖x0系列RTC結(jié)構(gòu)框圖所示,RTC時(shí)鐘源可配置通過數(shù)字平滑校準(zhǔn)或直接輸入到7位異步預(yù)分頻器輸出ck_apre時(shí)鐘用于RTC_SS亞秒寄存器自減計(jì)數(shù),ck_apre時(shí)鐘又經(jīng)過15位同步預(yù)分頻器后輸出1HZ的ck_spre時(shí)鐘提供日歷寄存器使用;基于日歷寄存器還實(shí)現(xiàn)了鬧鐘和時(shí)間戳功能;RTC還具有鬧鐘、時(shí)鐘輸出功能,對(duì)RTC_TS、RTC_TAMP0、RTC_TAMP1引腳的有效輸入可觸發(fā)時(shí)間戳和侵入事件并產(chǎn)生中斷。侵入事件會(huì)將備份域復(fù)位。

? 鬧鐘
RTC鬧鐘功能被劃分為多個(gè)位域并且每一個(gè)位域有一個(gè)該域的可屏蔽位。屏蔽某些位域后可固定周期產(chǎn)生鬧鐘事件。
? 侵入事件
RTC_TAMPx管腳可以作為侵入事件檢測功能輸入管腳,檢測模式有兩種可供用戶選擇:邊沿檢測模式或者是帶可配置濾波功能的電平檢測模式。侵入事件會(huì)將備份域復(fù)位,可產(chǎn)生一個(gè)中斷。
? 可選的RTC輸出功能:
512Hz( 默認(rèn)預(yù)分頻值): RTC_OUT;
1Hz( 默認(rèn)預(yù)分頻值): RTC_ OUT;
鬧鐘事件( 極性可配置): RTC_ OUT。
? 可選的RTC輸入功能:
時(shí)間戳事件檢測( RTC_TS);
侵入事件檢測 0( RTC_TAMP0);
侵入事件檢測 1( RTC_TAMP1);
參考時(shí)鐘輸入 RTC_REFIN( 50 或 60Hz)。
? RTC中斷
所有的RTC中斷(鬧鐘、時(shí)間戳、侵入事件)都被連接到EXTI控制器。
4xx 系列 RTC 4xx系列RTC在x0系列RTC的基礎(chǔ)上做了部分功能的升級(jí)。提供了一個(gè)包含日期(年/月/日)和時(shí)間(時(shí)/分/秒/亞秒)的日歷功能。除亞秒用二進(jìn)制碼顯示外,時(shí)間和日期都以BCD碼的形式顯示。
RTC可以進(jìn)行夏令時(shí)補(bǔ)償。RTC可以工作在省電模式下,并通過軟件配置來智能喚醒。RTC支持外接更高精度的低頻時(shí)鐘,用以達(dá)到更高的日歷精度。
- 4xx系列RTC主要特點(diǎn):
? 通過軟件設(shè)置來實(shí)現(xiàn)夏令時(shí)補(bǔ)償。
? 參考時(shí)鐘檢測功能:通過外接更高精度的低頻率時(shí)鐘源(50Hz或60Hz)來提高日歷精度。
? 數(shù)字校準(zhǔn)功能:通過調(diào)整最小時(shí)間單位(最大可調(diào)精度0.95ppm)來進(jìn)行日歷校準(zhǔn)。
? 通過移位功能進(jìn)行亞秒級(jí)調(diào)整。
? 記錄事件時(shí)間的時(shí)間戳功能。
? 兩個(gè)模式可配置的獨(dú)立的侵入檢測。
? 可編程的日歷和一個(gè)位域可屏蔽的鬧鐘。
? 20個(gè)32位(共80字節(jié))通用備份寄存器,能夠在省電模式下保存數(shù)據(jù)。當(dāng)有外部事件侵入時(shí),備份寄存器將會(huì)復(fù)位。
? 可屏蔽的中斷源:
– 鬧鐘0和鬧鐘1;
– 時(shí)間戳檢測;
– 自動(dòng)喚醒事件;
– 侵入檢測;
? 可配置周期的自動(dòng)喚醒定時(shí)器
4xx系列RTC框圖介紹:
4xx系列RTC工作在備份域,可在低功耗模式下保持工作,通過APB總線可對(duì)RTC寄存器進(jìn)行讀取和配置。如下圖4xx系列RTC結(jié)構(gòu)框圖所示,RTC時(shí)鐘源可配置通過數(shù)字平滑校準(zhǔn)或直接輸入到7位異步預(yù)分頻器輸出ck_apre時(shí)鐘用于RTC_SS亞秒寄存器自減計(jì)數(shù),ck_apre時(shí)鐘又可通過數(shù)字粗平滑校準(zhǔn)或直接輸入15位同步預(yù)分頻器后輸出1HZ的ck_spre時(shí)鐘提供日歷寄存器使用;基于日歷寄存器還實(shí)現(xiàn)了鬧鐘和時(shí)間戳功能;RTC還具有鬧鐘、時(shí)鐘輸出功能,對(duì)RTC_TS、RTC_TAMP0、RTC_TAMP1引腳的有效輸入可觸發(fā)時(shí)間戳和侵入事件并產(chǎn)生中斷。侵入事件會(huì)將備份域復(fù)位。4xx系列RTC有一個(gè)獨(dú)立的自動(dòng)重加載喚醒定時(shí)器可用于產(chǎn)生喚醒事件和中斷。

? 鬧鐘
RTC鬧鐘功能被劃分為多個(gè)位域并且每一個(gè)位域有一個(gè)該域的可屏蔽位。屏蔽某些位域后可固定周期產(chǎn)生鬧鐘事件。
? 侵入事件
RTC_TAMPx管腳可以作為侵入事件檢測功能輸入管腳,檢測模式有兩種可供用戶選擇:邊沿檢測模式或者是帶可配置濾波功能的電平檢測模式。侵入事件會(huì)將備份域復(fù)位,可產(chǎn)生一個(gè)中斷。
? 可選的RTC輸出功能:
512Hz(默認(rèn)預(yù)分頻值):(RTC_OUT)PC13
1Hz(默認(rèn)預(yù)分頻值):(RTC_OUT)PC13
鬧鐘事件(極性可配置):(RTC_OUT)PC13
自動(dòng)喚醒事件(極性可配置):(RTC_OUT)PC13
? 可選的RTC輸入功能:
時(shí)間戳事件檢測(RTC_TS):RTC_AF0、RTC_AF1;
侵入事件檢測 0(RTC_TAMP0):RTC_AF0、RTC_AF1;
侵入事件檢測 1(RTC_TAMP1):RTC_AF1;
參考時(shí)鐘輸入 RTC_REFIN(50或60Hz)。
? RTC中斷
所有的RTC中斷(鬧鐘0、鬧鐘1、喚醒、時(shí)間戳、侵入0、侵入1)都被連接到EXTI控制器。
各系列 RTC 模塊功能對(duì)比
x0系列中的E23x系列均沒有VBAT引腳,不支持VDD掉電保持RTC工作。
0x系列備份域不同于x0、4xx系列,為單獨(dú)的一個(gè)外設(shè)模塊,所以使用RTC時(shí),0x系列相比x0系列和4xx系列還需使能BKP的時(shí)鐘。
各系列 RTC 模塊功能對(duì)比

14.2.GD32 RTC 硬件設(shè)計(jì)
? Vbat電源設(shè)計(jì)
Vbat可以連接至外部電池,在Vdd掉電時(shí)可以保證備份域不掉電、RTC繼續(xù)運(yùn)行。VBAT引腳需要對(duì)GND連接0.1uF電容,如果沒有外部電池需要將VBAT和一個(gè)0.1uF電容連接至Vdd電源上。

? RTC_TAMPx引腳
入侵事件會(huì)導(dǎo)致備份域復(fù)位,如使用該功能需注意檢測引腳的濾波,可在RTC_TAMPx引腳上并聯(lián)0.1uf電容。
14.3.GD32 RTC 軟件配置
GD32MCU_Example下的RTC_Example例程配置了日歷和鬧鐘功能,并開啟了鬧鐘中斷。本小節(jié)講解RTC_Example例程中RTC模塊的配置說明,主要包括時(shí)鐘及分頻配置、日歷配置、鬧鐘配置、主函數(shù)說明。本例程主要介紹GD32 MCU各系列RTC模塊的時(shí)間、鬧鐘配置,有關(guān)RTC其他功能例程可參考各系列固件庫例程。
時(shí)鐘及分頻配置
? 由于RTC工作在備份域,所以使用RTC時(shí)需要使能備份域?qū)懝δ埽刂苽浞萦驅(qū)懝δ艿募拇嫫魑挥赑MU中,所以操作RTC還需要將PMU_CTL寄存中的BKPWEN置位,從而還需使能PMU的時(shí)鐘。而對(duì)于0x系列備份域?yàn)閱为?dú)的外設(shè),還需額外使能BKP備份域時(shí)鐘。
? 為了實(shí)現(xiàn)準(zhǔn)確的日歷功能,配置RTC前需要準(zhǔn)備好需要的時(shí)鐘源,在選擇合適的時(shí)鐘源后RTC還需要進(jìn)行預(yù)分頻的配置。
0x系列時(shí)鐘及分頻配置如代碼清單 RTC 0x系列時(shí)鐘及分頻配置所示,RTC使能后需要等待RTC寄存器和APB1時(shí)鐘同步,執(zhí)行rtc_register_sync_wait()函數(shù);此外0x系列RTC在RTC寄存器配 置時(shí)需要等待上一次配置結(jié)束才能繼續(xù)新的配置,所以在每個(gè)寄存器配置前需要執(zhí)行rtc_lwoff_wait()函數(shù),等待LWOFF置位。
代碼清單 RTC 0x 系列時(shí)鐘及分頻配置
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系列時(shí)鐘及分頻配置如代碼清單 RTC x0系列時(shí)鐘及分頻配置所示,RTC使能后需要等待RTC寄存器和APB1時(shí)鐘同步,執(zhí)行rtc_register_sync_wait()函數(shù);和0x系列不同,后續(xù)配置過程x0和4xx系列均不需要執(zhí)行rtc_lwoff_wait()函數(shù)。
代碼清單 RTC x0 系列時(shí)鐘及分頻配置
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系列時(shí)鐘及分頻配置如代碼清單 RTC 4xx系列時(shí)鐘及分頻配置所示,和x0系列基本相同,但由于4xx系列內(nèi)部低速時(shí)鐘為32K,所以分頻系數(shù)和x0系列有所不同。
代碼清單 RTC 4xx 系列時(shí)鐘及分頻配置
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系列由于沒有硬件日歷功能,所以需要讀取計(jì)數(shù)器通過軟件計(jì)算出日歷;而x0系列和4xx系列具有硬件日歷功能,日期信息均是BCD碼,所以在日歷配置的格式和方式均有差別。
0x系列RTC的日歷配置如代碼清單 RTC 0x系列日歷配置所示,該函數(shù)提供了日歷配置的入口參數(shù),先將需要配置的日歷信息轉(zhuǎn)換成秒單位,再寫入RTC計(jì)數(shù)器即可。入口參數(shù)使用十進(jìn)制寫入。
代碼清單 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系列日歷配置所示,該函數(shù)提供了日歷配置的入口參數(shù),參數(shù)為BCD碼格式,寫入后對(duì)RTC日歷結(jié)構(gòu)體賦初值,日歷結(jié)構(gòu)體還可以配置星期、時(shí)間格式等,這里默認(rèn)配置了24小時(shí)制。函數(shù)入口參數(shù)使用16進(jìn)制寫入。
代碼清單 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系列基本相同, 唯一區(qū)別只是日歷結(jié)構(gòu)體成員名字少了“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位計(jì)數(shù)器運(yùn)行時(shí)間,所以其鬧鐘也是32位數(shù)據(jù),當(dāng)計(jì)數(shù)器和鬧鐘值匹配時(shí)會(huì)產(chǎn)生鬧鐘事件或中斷,所需配置的鬧鐘值為鬧鐘剩余倒計(jì)時(shí)加上當(dāng)前計(jì)數(shù)器值;而x0系列和4xx系列是硬件BCD日歷功能,所以其鬧鐘也是BDC格式,且具有位域屏蔽功能,根據(jù)需要直接配置具體的時(shí)間即可。
0x系列RTC的鬧鐘配置如代碼清單 RTC 0x系列鬧鐘配置所示,該函數(shù)提供了鬧鐘配置的入口參數(shù),先將需要配置的時(shí)間信息轉(zhuǎn)換成秒單位,再加上當(dāng)前計(jì)數(shù)器的值寫入鬧鐘寄存器即可。
0x系列配置的鬧鐘參數(shù)為鬧鐘中斷的倒計(jì)時(shí)時(shí)間,寫入?yún)?shù)為十進(jìn)制。
代碼清單 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系列鬧鐘配置所示,該函數(shù)提供了鬧鐘配置的入口參數(shù),參數(shù)為BCD碼格式,寫入后對(duì)RTC鬧鐘結(jié)構(gòu)體賦初值,鬧鐘結(jié)構(gòu)體可以配置位域屏蔽、選擇配置日期或星期、時(shí)間格式等,這里默認(rèn)配置了屏蔽天、小時(shí)、分鐘,所以配置最后實(shí)際生效的只有秒,所以配置后鬧鐘均是1分鐘產(chǎn)生一次。鬧鐘配置前需失能鬧鐘,配置后再使能,4xx系列配置的鬧鐘參數(shù)為鬧鐘產(chǎn)生的日期時(shí)間,因BCD格式寫入?yún)?shù)參數(shù)使用16進(jìn)制。
代碼清單 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系列基本相同, 唯一區(qū)別只是鬧鐘結(jié)構(gòu)體成員名字少了“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; }
主函數(shù)說明 主函數(shù)如代碼清單 RTC_Example主函數(shù)所示,主要包含了中斷配置、RTC時(shí)鐘源和預(yù)分頻配置、日歷設(shè)置以及鬧鐘設(shè)置,成功設(shè)置好日歷和鬧鐘后在備份域數(shù)據(jù)寄存器寫入一個(gè)標(biāo)志位,下次非備份域復(fù)位的情況就可以不再重復(fù)配置RTC。While1中循環(huán)調(diào)用rtc_current_time_get()函數(shù)獲取日歷信息。4xx系列和x0系列中固件庫底層已經(jīng)提供了rtc_current_time_get()函數(shù),直接更新至日歷結(jié)構(gòu)體;而0x系列固件庫沒有此函數(shù),額外編寫了相同接口的函數(shù),通過讀取32位計(jì)數(shù)器軟件計(jì)算出日歷信息更新至自定義的日歷結(jié)構(gòu)體中。通過仿真或串口打印可以看到結(jié)構(gòu)體中的時(shí)間數(shù)據(jù)在更新。
代碼清單 RTC_Example 主函數(shù)
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()主函數(shù)
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; }
鬧鐘中斷說明
例程中開啟了鬧鐘中斷,初始化調(diào)用rtc_alarm_set(uint8_t hour, uint8_t minute, uint8_t second)函數(shù)分別配置了“0時(shí)0分5秒”的鬧鐘。
? 對(duì)0x系列來說這個(gè)配置是倒計(jì)時(shí)“0時(shí)0分5秒”后產(chǎn)生鬧鐘,進(jìn)入鬧鐘中斷后再配置新的5s實(shí)現(xiàn)5s一次的鬧鐘周期;
? 對(duì)x0和4xx系列這個(gè)配置是時(shí)間在“0時(shí)0分5秒”時(shí)產(chǎn)生鬧鐘,但因?yàn)轸[鐘配置中已經(jīng)屏蔽了鬧鐘的天、時(shí)、分位域,所以鬧鐘會(huì)在每分鐘的5秒產(chǎn)生,鬧鐘周期為一分鐘產(chǎn)生一次。
14.4.RTC 使用注意事項(xiàng)
1、 因?yàn)閮?nèi)部低速時(shí)鐘是在VDDA電源域,所以VDD斷電后VBAT供電情況下保持RTC運(yùn)行需要使用外部低速時(shí)鐘;此外使用LXTAL在非備份域復(fù)位時(shí)可以不用在初始化階段配置,但使用內(nèi)部低速時(shí)鐘需要每次復(fù)位都進(jìn)行內(nèi)部時(shí)鐘的初始化。
2、 內(nèi)部低速時(shí)鐘精度相對(duì)較差,如必須使用內(nèi)部且對(duì)精度有一定要求,4xx和0x系列可以使用TIMER4、x0系列可以使用TIMER13捕獲內(nèi)部低速時(shí)鐘,計(jì)算出實(shí)際的頻率值來進(jìn)行合適分頻。
3、 日歷信息意外被清零的話注意是否發(fā)生過備份域復(fù)位,是否有Vbat掉電或入侵事件發(fā)生。
4、 調(diào)試中如果修改了RTC代碼的配置,請(qǐng)先擦除全片F(xiàn)lash,然后斷電并上電后再下載新的代碼。
-
單片機(jī)
+關(guān)注
關(guān)注
6067文章
44961瀏覽量
648873 -
嵌入式
+關(guān)注
關(guān)注
5146文章
19598瀏覽量
316243 -
開發(fā)板
+關(guān)注
關(guān)注
25文章
5622瀏覽量
103600 -
RTC
+關(guān)注
關(guān)注
2文章
619瀏覽量
68563
發(fā)布評(píng)論請(qǐng)先 登錄
GD32 MCU 入門教程】GD32 MCU 常見外設(shè)介紹(12)FMC 模塊介紹

GD32 MCU移植
GD32的MCU介紹
《GD32 MCU原理及固件庫開發(fā)指南》 + 初讀感悟
《GD32 MCU原理及固件庫開發(fā)指南》+讀后感
兆易創(chuàng)新GD32 MCU選型手冊(cè),適用于GD32全系列MCU
不同型號(hào)的GD32 MCU如何區(qū)分?

【GD32 MCU 入門教程】一、GD32 MCU 開發(fā)環(huán)境搭建(1)使用Keil開發(fā)GD32

【GD32 MCU 入門教程】一、GD32 MCU 開發(fā)環(huán)境搭建(2)使用 IAR 開發(fā) GD32

【GD32 MCU 入門教程】一、GD32 MCU 開發(fā)環(huán)境搭建(3)使用 Embedded Builder 開發(fā) GD32

【GD32 MCU 入門教程】二、GD32 MCU 燒錄說明(1)ISP 燒錄

【GD32 MCU入門教程】GD32 MCU GPIO 結(jié)構(gòu)與使用注意事項(xiàng)

評(píng)論