GD32 MCU內(nèi)部提供了一個(gè)RTC(實(shí)時(shí)時(shí)鐘)模塊,通過(guò)RTC可以實(shí)現(xiàn)日歷時(shí)鐘、鬧鐘等功能。RTC也可以用于深度睡眠或待機(jī)模式的低功耗喚醒。不同系列的GD32 MCU在RTC設(shè)計(jì)和功能上有所區(qū)別,總體可以分為三大系列:
(1)F10x、F30x、E10x系列RTC功能基本相同,后文簡(jiǎn)稱0x系列。
(2)F1x0、F3x0、E23x系列RTC功能基本相同,后文簡(jiǎn)稱x0系列。
(3)F405、F407、F450系列RTC功能基本相同,后文簡(jiǎn)稱4xx系列。后文會(huì)對(duì)0x系列、x0系列、4xx系列的RTC模塊分別進(jìn)行介紹,簡(jiǎn)單介紹RTC的工作原理、配置使用方法。
14.1.GD32 RTC 外設(shè)簡(jiǎn)介
0x 系列 RTC
0x系列RTC整體架構(gòu)相對(duì)精簡(jiǎn),主要依靠32位累加計(jì)數(shù)器配置分頻實(shí)現(xiàn)時(shí)鐘計(jì)數(shù)。日歷功能可通過(guò)軟件計(jì)算并寫(xiě)入備份域中實(shí)現(xiàn);同時(shí)具有鬧鐘功能可用于定時(shí)產(chǎn)生中斷和喚醒喚醒事件;RTC的核心計(jì)數(shù)部分在備份域中,可在VDD斷電時(shí)VBAT供電的情況保持RTC的計(jì)數(shù),正常上電工作時(shí)通過(guò)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接口用來(lái)和APB1總線相連。此單元還包含一組16位寄存器,可通過(guò)APB1總線對(duì)其進(jìn)行讀寫(xiě)操作。對(duì)RTC模塊進(jìn)行相關(guān)配置。
另一部分(RTC核心)由一組可編程計(jì)數(shù)器組成,分成兩個(gè)主要模塊。第一個(gè)模塊是RTC的預(yù)分頻模塊,RTC時(shí)鐘源輸入后經(jīng)過(guò)預(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可以工作在省電模式下,并通過(guò)軟件配置來(lái)智能喚醒。RTC支持外接更高精度的低頻時(shí)鐘,用以達(dá)到更高的日歷精度。
x0系列RTC主要特點(diǎn):
? 通過(guò)軟件設(shè)置來(lái)實(shí)現(xiàn)夏令時(shí)補(bǔ)償。
? 參考時(shí)鐘檢測(cè)功能:通過(guò)外接更高精度的低頻率時(shí)鐘源(50Hz/60Hz)來(lái)提高日歷精度。
? 數(shù)字校準(zhǔn)功能:通過(guò)調(diào)整最小時(shí)間單位(最大可調(diào)精度0.95ppm)來(lái)進(jìn)行日歷校準(zhǔn)。
? 通過(guò)移位功能進(jìn)行亞秒級(jí)調(diào)整。
? 記錄事件時(shí)間的時(shí)間戳功能。
? 兩個(gè)模式可配置的獨(dú)立的侵入檢測(cè)。
? 可編程的日歷和一個(gè)位域可屏蔽的鬧鐘。
? 5個(gè)32位(共20字節(jié))通用備份寄存器,能夠在省電模式下保存數(shù)據(jù)。當(dāng)有外部事件侵入時(shí),備份寄存器將會(huì)復(fù)位。
? 可屏蔽的中斷源:
– 鬧鐘0;
– 時(shí)間戳檢測(cè);
– 侵入檢測(cè);
x0系列RTC框圖介紹:
x0系列RTC工作在備份域,可在低功耗模式下保持工作,通過(guò)APB總線可對(duì)RTC寄存器進(jìn)行讀取和配置。如下圖x0系列RTC結(jié)構(gòu)框圖所示,RTC時(shí)鐘源可配置通過(guò)數(shù)字平滑校準(zhǔn)或直接輸入到7位異步預(yù)分頻器輸出ck_apre時(shí)鐘用于RTC_SS亞秒寄存器自減計(jì)數(shù),ck_apre時(shí)鐘又經(jīng)過(guò)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管腳可以作為侵入事件檢測(cè)功能輸入管腳,檢測(cè)模式有兩種可供用戶選擇:邊沿檢測(cè)模式或者是帶可配置濾波功能的電平檢測(cè)模式。侵入事件會(huì)將備份域復(fù)位,可產(chǎn)生一個(gè)中斷。
? 可選的RTC輸出功能:
512Hz( 默認(rèn)預(yù)分頻值): RTC_OUT;
1Hz( 默認(rèn)預(yù)分頻值): RTC_ OUT;
鬧鐘事件( 極性可配置): RTC_ OUT。
? 可選的RTC輸入功能:
時(shí)間戳事件檢測(cè)( RTC_TS);
侵入事件檢測(cè) 0( RTC_TAMP0);
侵入事件檢測(cè) 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可以工作在省電模式下,并通過(guò)軟件配置來(lái)智能喚醒。RTC支持外接更高精度的低頻時(shí)鐘,用以達(dá)到更高的日歷精度。
- 4xx系列RTC主要特點(diǎn):
? 通過(guò)軟件設(shè)置來(lái)實(shí)現(xiàn)夏令時(shí)補(bǔ)償。
? 參考時(shí)鐘檢測(cè)功能:通過(guò)外接更高精度的低頻率時(shí)鐘源(50Hz或60Hz)來(lái)提高日歷精度。
? 數(shù)字校準(zhǔn)功能:通過(guò)調(diào)整最小時(shí)間單位(最大可調(diào)精度0.95ppm)來(lái)進(jìn)行日歷校準(zhǔn)。
? 通過(guò)移位功能進(jìn)行亞秒級(jí)調(diào)整。
? 記錄事件時(shí)間的時(shí)間戳功能。
? 兩個(gè)模式可配置的獨(dú)立的侵入檢測(cè)。
? 可編程的日歷和一個(gè)位域可屏蔽的鬧鐘。
? 20個(gè)32位(共80字節(jié))通用備份寄存器,能夠在省電模式下保存數(shù)據(jù)。當(dāng)有外部事件侵入時(shí),備份寄存器將會(huì)復(fù)位。
? 可屏蔽的中斷源:
– 鬧鐘0和鬧鐘1;
– 時(shí)間戳檢測(cè);
– 自動(dòng)喚醒事件;
– 侵入檢測(cè);
? 可配置周期的自動(dòng)喚醒定時(shí)器
4xx系列RTC框圖介紹:
4xx系列RTC工作在備份域,可在低功耗模式下保持工作,通過(guò)APB總線可對(duì)RTC寄存器進(jìn)行讀取和配置。如下圖4xx系列RTC結(jié)構(gòu)框圖所示,RTC時(shí)鐘源可配置通過(guò)數(shù)字平滑校準(zhǔn)或直接輸入到7位異步預(yù)分頻器輸出ck_apre時(shí)鐘用于RTC_SS亞秒寄存器自減計(jì)數(shù),ck_apre時(shí)鐘又可通過(guò)數(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管腳可以作為侵入事件檢測(cè)功能輸入管腳,檢測(cè)模式有兩種可供用戶選擇:邊沿檢測(cè)模式或者是帶可配置濾波功能的電平檢測(cè)模式。侵入事件會(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í)間戳事件檢測(cè)(RTC_TS):RTC_AF0、RTC_AF1;
侵入事件檢測(cè) 0(RTC_TAMP0):RTC_AF0、RTC_AF1;
侵入事件檢測(cè) 1(RTC_TAMP1):RTC_AF1;
參考時(shí)鐘輸入 RTC_REFIN(50或60Hz)。
? RTC中斷
所有的RTC中斷(鬧鐘0、鬧鐘1、喚醒、時(shí)間戳、侵入0、侵入1)都被連接到EXTI控制器。
各系列 RTC 模塊功能對(duì)比
x0系列中的E23x系列均沒(méi)有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電容,如果沒(méi)有外部電池需要將VBAT和一個(gè)0.1uF電容連接至Vdd電源上。
? RTC_TAMPx引腳
入侵事件會(huì)導(dǎo)致備份域復(fù)位,如使用該功能需注意檢測(cè)引腳的濾波,可在RTC_TAMPx引腳上并聯(lián)0.1uf電容。
14.3.GD32 RTC 軟件配置
GD32MCU_Example下的RTC_Example例程配置了日歷和鬧鐘功能,并開(kāi)啟了鬧鐘中斷。本小節(jié)講解RTC_Example例程中RTC模塊的配置說(shuō)明,主要包括時(shí)鐘及分頻配置、日歷配置、鬧鐘配置、主函數(shù)說(shuō)明。本例程主要介紹GD32 MCU各系列RTC模塊的時(shí)間、鬧鐘配置,有關(guān)RTC其他功能例程可參考各系列固件庫(kù)例程。
時(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ù)配置過(guò)程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系列由于沒(méi)有硬件日歷功能,所以需要讀取計(jì)數(shù)器通過(guò)軟件計(jì)算出日歷;而x0系列和4xx系列具有硬件日歷功能,日期信息均是BCD碼,所以在日歷配置的格式和方式均有差別。
0x系列RTC的日歷配置如代碼清單 RTC 0x系列日歷配置所示,該函數(shù)提供了日歷配置的入口參數(shù),先將需要配置的日歷信息轉(zhuǎn)換成秒單位,再寫(xiě)入RTC計(jì)數(shù)器即可。入口參數(shù)使用十進(jìn)制寫(xiě)入。
代碼清單 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碼格式,寫(xiě)入后對(duì)RTC日歷結(jié)構(gòu)體賦初值,日歷結(jié)構(gòu)體還可以配置星期、時(shí)間格式等,這里默認(rèn)配置了24小時(shí)制。函數(shù)入口參數(shù)使用16進(jìn)制寫(xiě)入。
代碼清單 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通過(guò)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ù)器的值寫(xiě)入鬧鐘寄存器即可。
0x系列配置的鬧鐘參數(shù)為鬧鐘中斷的倒計(jì)時(shí)時(shí)間,寫(xiě)入?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碼格式,寫(xiě)入后對(duì)RTC鬧鐘結(jié)構(gòu)體賦初值,鬧鐘結(jié)構(gòu)體可以配置位域屏蔽、選擇配置日期或星期、時(shí)間格式等,這里默認(rèn)配置了屏蔽天、小時(shí)、分鐘,所以配置最后實(shí)際生效的只有秒,所以配置后鬧鐘均是1分鐘產(chǎn)生一次。鬧鐘配置前需失能鬧鐘,配置后再使能,4xx系列配置的鬧鐘參數(shù)為鬧鐘產(chǎn)生的日期時(shí)間,因BCD格式寫(xiě)入?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ù)說(shuō)明 主函數(shù)如代碼清單 RTC_Example主函數(shù)所示,主要包含了中斷配置、RTC時(shí)鐘源和預(yù)分頻配置、日歷設(shè)置以及鬧鐘設(shè)置,成功設(shè)置好日歷和鬧鐘后在備份域數(shù)據(jù)寄存器寫(xiě)入一個(gè)標(biāo)志位,下次非備份域復(fù)位的情況就可以不再重復(fù)配置RTC。While1中循環(huán)調(diào)用rtc_current_time_get()函數(shù)獲取日歷信息。4xx系列和x0系列中固件庫(kù)底層已經(jīng)提供了rtc_current_time_get()函數(shù),直接更新至日歷結(jié)構(gòu)體;而0x系列固件庫(kù)沒(méi)有此函數(shù),額外編寫(xiě)了相同接口的函數(shù),通過(guò)讀取32位計(jì)數(shù)器軟件計(jì)算出日歷信息更新至自定義的日歷結(jié)構(gòu)體中。通過(guò)仿真或串口打印可以看到結(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; }
鬧鐘中斷說(shuō)明
例程中開(kāi)啟了鬧鐘中斷,初始化調(diào)用rtc_alarm_set(uint8_t hour, uint8_t minute, uint8_t second)函數(shù)分別配置了“0時(shí)0分5秒”的鬧鐘。
? 對(duì)0x系列來(lái)說(shuō)這個(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í)際的頻率值來(lái)進(jìn)行合適分頻。
3、 日歷信息意外被清零的話注意是否發(fā)生過(guò)備份域復(fù)位,是否有Vbat掉電或入侵事件發(fā)生。
4、 調(diào)試中如果修改了RTC代碼的配置,請(qǐng)先擦除全片F(xiàn)lash,然后斷電并上電后再下載新的代碼。
-
單片機(jī)
+關(guān)注
關(guān)注
6037文章
44558瀏覽量
635284 -
嵌入式
+關(guān)注
關(guān)注
5082文章
19126瀏覽量
305184 -
開(kāi)發(fā)板
+關(guān)注
關(guān)注
25文章
5050瀏覽量
97468 -
RTC
+關(guān)注
關(guān)注
2文章
538瀏覽量
66527
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論