吴忠躺衫网络科技有限公司

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

【GD32F303紅楓派開發(fā)板使用手冊】第九講 RTC-萬年歷實驗

聚沃科技 ? 2024-06-07 09:43 ? 次閱讀
wKgaomZVdiiAfR9BAB3mDFhHnZc972.png

9.1實驗內(nèi)容

通過本實驗主要學(xué)習(xí)以下內(nèi)容:

  • RTC簡介
  • RTC復(fù)位
  • RTC實現(xiàn)萬年歷
  • RTC使用注意事項

9.2實驗原理

9.2.1RTC簡介

RTC(Real Time Clock)——實時時鐘定時器,可以用作日歷。RTC電路分兩個電源域部分,其一位于備份域中,該部分包括一個32位的累加計數(shù)器、一個鬧鐘、一個預(yù)分頻器、一個分頻器以及RTC時鐘配置寄存器。備份域這部分電路不會因為系統(tǒng)復(fù)位或者MCU進(jìn)入低功耗而丟失數(shù)據(jù),所以在系統(tǒng)復(fù)位或MCU從低功耗下喚醒,RTC的設(shè)置和時間都可以保持不變。另一部分位于VDD電源域中,該部分只包括APB接口以及一組控制寄存器。

關(guān)于RTC的兩個電源域及分布在兩個電源域中的內(nèi)容,需要讀者牢記,否則會由于細(xì)節(jié)沒處理好導(dǎo)致RTC工作異常。

以下為GD32F303的RTC框圖:

wKgaomZiZNyAGxZyAAE4ZXdvRok560.png

圖中RTC_CNT為計數(shù)值,每個SC_CLK時鐘到來時,這個計數(shù)值增加+1。SC_CLK時鐘源有三個:LXTAL(外部低速晶振)、IRC40K(內(nèi)部40K晶振)和HXTAL/128,三個時鐘源經(jīng)過RTC_DIV產(chǎn)生SC_CLK。RTC_DIV的配置是通過RTC_PSC加載所得,RTC_PSC由寄存器RTC預(yù)分頻寄存器高位(RTC_PSCH)和RTC預(yù)分頻寄存器低位(RTC_PSCL)配置,有效位20bit,即RTC的時鐘分頻器最大值為2的20次方,完全足夠應(yīng)用了。

了解了上面的內(nèi)容,RTC的工作原理就很好理解了。舉個例子,RTC的時鐘源選擇LXTAL,頻率為32.768KHz,然后設(shè)置RTC_PSC為32768,那么SC_CLK即為1Hz,也就是說,每秒鐘RTC_CNT值+1,所以我們只要獲得一段時間內(nèi)RTC_CNT值增加了多少數(shù),也就知道經(jīng)過了多少秒。

我們從手冊中可以看到RTC_CNT由RTC計數(shù)寄存器高位(RTC_CNTH)和RTC計數(shù)寄存器低位(RTC_CNTL)設(shè)置,這兩個寄存器組合起來的有效位為32bit,即RTC_CNT可以記錄2的32次方,即4,294,967,296個數(shù),按照每秒增加一次的話,可以記錄136多年,

除了基礎(chǔ)的記時間的功能,RTC還有一個鬧鐘功能,RTC運(yùn)行時,當(dāng)RTC_CNT的值增加到和RTC_ALRM(由RTC鬧鐘寄存器高位(RTC_ALRMH)和RTC鬧鐘寄存器低位(RTC_ALRML)設(shè)置)相等時,則會產(chǎn)生ALRM中斷,當(dāng)然,程序中需要實現(xiàn)使能ALARM中斷(ALRMIE)。

RTC還有另外兩個中斷,一個是秒中斷,另一個是溢出中斷。秒中斷好理解,即每秒鐘進(jìn)入一個中斷;溢出中斷則是當(dāng)RTC_CNT溢出時產(chǎn)生中斷。

9.2.2RTC復(fù)位

這里把RTC的復(fù)位單獨作為一個章節(jié)來說,是因為這里很容易出錯導(dǎo)致想要實現(xiàn)的功能無法實現(xiàn)。

前面說過,RTC分為兩個電源域——備份域和VDD電源域,而一般的復(fù)位比如NRST腳復(fù)位、軟件復(fù)位等只能復(fù)位VDD和VDDA電源域 ,而無法復(fù)位備份域;備份域復(fù)位需要VBAT掉電或者通過備份域控制寄存器(RCU_BDCTL)的BKPDRST來進(jìn)行備份域復(fù)位。

上節(jié)中的RTC框圖中被深色框住的即屬于備份域,這里提到一個很容易出錯的地方,即RTC的時鐘源選擇。從框圖看到時鐘源由RTCSRC[1:0]來設(shè)置,這個位域?qū)儆趥浞萦蚩刂萍拇嫫鳎≧CU_BDCTL)。

備份域控制寄存器( RCU_BDCTL):

wKgaomZiZOyADpW2AACTeOREhls922.pngwKgZomZiZOyAO7mLAAEvIGqW0OQ864.png

寄存器描述中指出,一旦RTC的時鐘源選擇后,除了將備份域復(fù)位,否則時鐘不能被改變。舉個例子:一個產(chǎn)品選擇LXTAL作為RTC時鐘,但可能因為某些原因LXTAL停振了,需要將時鐘源切換到IRC40K,程序如何實現(xiàn)呢?沒錯,需要復(fù)位備份域(控制BKPDRST位)才能重新選擇時鐘源,但一旦備份域進(jìn)行了復(fù)位,包括RTC_CNT等數(shù)據(jù)都會丟失,所以在備份域復(fù)位前需要對RTC內(nèi)的各個數(shù)據(jù)進(jìn)行保存處理,待備份域復(fù)位后再重新寫入。

9.2.3RTC實現(xiàn)萬年歷

本實驗用RTC做一個萬年歷,其中還需要考慮到閏年閏月的情況。實驗設(shè)置的基準(zhǔn)時間是1970年,即當(dāng)RTC_CNT為0時,為1970年,實驗最高可記錄到2106年(1970+136)。

9.3硬件設(shè)計

本實驗實現(xiàn)每秒鐘通過串口打印實時時間,即需要使用到開發(fā)板USB串口模塊。另外RTC時鐘源使用的是外部低速晶振,外部晶振原理圖如下:

wKgZomZiZQ6AaL37AABaIpa9qvg566.png

9.4代碼解析

9.4.1RTC配置

在driver_rtc.c中定義了RTC配置函數(shù)rtc_configuration

C
void rtc_configuration(void)
{
/*使能備份域和PMU時鐘*/
rcu_periph_clock_enable(RCU_BKPI);
rcu_periph_clock_enable(RCU_PMU);
/*使能備份域?qū)懝δ?/
pmu_backup_write_enable();
/*備份域復(fù)位*/
bkp_deinit();
/*依據(jù)選擇的時鐘源進(jìn)行時鐘配置*/
/*使用LXTAL*/
#ifdef RTC_CLOCK_SOURCE_LXTAL
/* 使能 LXTAL */
rcu_osci_on(RCU_LXTAL);
/* 等待LXTAL Ready */
rcu_osci_stab_wait(RCU_LXTAL);
/*選擇LXTAL作為RTC時鐘*/
rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
#endif
/*使用IRC40K*/
#ifdef RTC_CLOCK_SOURCE_IRC40K
/* 使能 IRC40K*/
rcu_osci_on(RCU_IRC40K);
/* 等待IRC40K Ready */
rcu_osci_stab_wait(RCU_IRC40K);
/*選擇IRC40K作為RTC時鐘*/
rcu_rtc_clock_config(RCU_RTCSRC_IRC40K);
#endif

#ifdef RTC_CLOCK_SOURCE_HXTAL_DIV_128
/* 使能LXTAL */
rcu_osci_on(RCU_HXTAL);
/* 等待HXTAL Ready */
rcu_osci_stab_wait(RCU_HXTAL);

/*選擇HXTAL/128作為RTC時鐘*/
rcu_rtc_clock_config(RCU_RTCSRC_HXTAL_DIV_128);
#endif
/*使能RTC時鐘*/
rcu_periph_clock_enable(RCU_RTC);
/*等待RTC寄存器同步*/
rtc_register_sync_wait();
/*等待上一次操作完成*/
rtc_lwoff_wait();
/*使能RTC秒中斷*/
rtc_interrupt_enable(RTC_INT_SECOND);
/*等待上一次操作完成*/
rtc_lwoff_wait();
/*依據(jù)選擇的時鐘源來設(shè)置分頻,使RTC周期為1s*/
#ifdef RTC_CLOCK_SOURCE_LXTAL
rtc_prescaler_set(32767);
#endif
#ifdef RTC_CLOCK_SOURCE_IRC40K
rtc_prescaler_set(40000);
#endif
#ifdef RTC_CLOCK_SOURCE_HXTAL_DIV_128
rtc_prescaler_set(HXTAL_VALUE/128);
#endif
/*等待上一次操作完成*/
rtc_lwoff_wait();
}

時鐘源通過driver_rtc.h中的宏定義來選擇:

C
#define RTC_CLOCK_SOURCE_LXTAL
//#define RTC_CLOCK_SOURCE_IRC40K
//#define RTC_CLOCK_SOURCE_HXTAL_DIV_128

9.4.2萬年歷實現(xiàn)

在bsp_rtc.c中定義了實現(xiàn)萬年歷的幾個函數(shù):rtc_time_set、rtc_time_display、is_leap_year等。

rtc_time_set函數(shù)——第一次需要手動設(shè)置當(dāng)前時間:

C
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 (bkp_read_data(BKP_DATA_0) != 0xA5A5)
{
rtc_configuration();

if(year < 1970 || year > 2099)
return 1;

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 += (uint32_t)minute * 60;
seccount += second;
rtc_counter_set(seccount);
bkp_write_data(BKP_DATA_0, 0xA5A5);
return 0;
}
else
{
if (rcu_flag_get(RCU_FLAG_PORRST) != RESET){
printf("Power On Reset occurred....\r\n");
}else if (rcu_flag_get(RCU_FLAG_EPRST) != RESET){
printf("External Reset occurred....\r\n");
}
rcu_all_reset_flag_clear();
rcu_periph_clock_enable(RCU_PMU);
pmu_backup_write_enable();
rtc_register_sync_wait();
rtc_interrupt_enable(RTC_INT_SECOND);
rtc_lwoff_wait();
return 0;
}
}

該函數(shù)中在第一次上電運(yùn)行時,會進(jìn)行初始時間設(shè)置,然后寫入特定數(shù)據(jù)到備份域數(shù)據(jù)寄存器中。當(dāng)發(fā)生系統(tǒng)復(fù)位但Vbat未掉電的情況下,則不會重新進(jìn)行時間設(shè)置,但需要重新開啟秒時鐘中斷,因為SCIE處于VDD電源域而不在備份域。

rtc_time_display函數(shù)——打印實時時間:

C
void rtc_time_display(uint32_t timevar)
{
static uint16_t daycnt = 0;
uint32_t temp = 0;
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++;
}

calendar.years = temp1;
temp1=0;

while(temp >= 28)
{
if(is_leap_year(calendar.years) && temp1 == 1){
if(temp >= 29)
temp -= 29;
else
break;
}else{
if(temp >= month_table[temp1])
temp -= month_table[temp1];
else
break;
}
temp1++;
}
calendar.months = temp1 + 1;
calendar.days = temp + 1;
}

temp = timevar % 86400;
calendar.hours = temp / 3600;
calendar.minutes = (temp % 3600) / 60;
calendar.seconds = (temp % 3600) % 60;

printf("Time: %0.4d-%0.2d-%0.2d,%0.2d:%0.2d:%0.2d\r\n", calendar.years, calendar.months, calendar.days, calendar.hours, calendar.minutes, calendar.seconds);
}

is_leap_year函數(shù)——判斷當(dāng)前年是否為閏年:

C
uint8_t is_leap_year(uint16_t year)
{
if((year%4 == 0 && year % 100 != 0) || (year % 400 == 0)){
return 1;
}else{
return 0;
}
}

9.4.3main函數(shù)和中斷函數(shù)實現(xiàn)

以下為main函數(shù)代碼:

C
int main(void)
{
delay_init();//delay函數(shù)初始化
bsp_uart_init(&BOARD_UART);//BOARD_UART串口初始化
nvic_irq_enable(RTC_IRQn,1,0);//打開RTC的NVIC
rtc_time_set(year_set,month_set,day_set,hour_set,minute_set,second_set); //設(shè)置當(dāng)前時間
while (1){
/* 判斷是否到1s了*/
if (timedisplay == 1){
/* 顯示實時時間*/
rtc_time_display(rtc_counter_get());
timedisplay = 0;
}
}
}

本例程main函數(shù)首先進(jìn)行了延時函數(shù)初始化,再初始化開發(fā)板USB串口,開啟RTC的NVIC后設(shè)置了當(dāng)前時間,在while(1)循環(huán)中等待RTC數(shù)據(jù)更新,然后將實時時間打印出來。

中斷函數(shù)代碼:

C
void RTC_IRQHandler(void)
{
if (rtc_flag_get(RTC_FLAG_SECOND) != RESET){
/* 清除RTC秒中斷標(biāo)志位*/
rtc_flag_clear(RTC_FLAG_SECOND);
timedisplay = 1;
/* 等待上一次操作完成 */
rtc_lwoff_wait();

}
}

9.5實驗結(jié)果

為了驗證萬年歷是否工作正常,設(shè)定初始時間為2022年12月31日23時59分50s,當(dāng)程序開始運(yùn)行時,每秒鐘打印時間,經(jīng)過10s后,可以看到時間變?yōu)?023年1月1日0時0分0秒,說明萬年歷有效。

wKgZomZiZXaAM8nXAAAfiD_RaEg908.png

教程GD32 MCU方案商聚沃科技原創(chuàng)發(fā)布,了解更多GD32 MCU教程,關(guān)注聚沃科技官網(wǎng)

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 單片機(jī)
    +關(guān)注

    關(guān)注

    6043

    文章

    44622

    瀏覽量

    638557
  • 開發(fā)板
    +關(guān)注

    關(guān)注

    25

    文章

    5121

    瀏覽量

    98195
  • 萬年歷
    +關(guān)注

    關(guān)注

    3

    文章

    187

    瀏覽量

    23976
  • RTC
    RTC
    +關(guān)注

    關(guān)注

    2

    文章

    542

    瀏覽量

    67030
收藏 人收藏

    評論

    相關(guān)推薦

    [分享]萬年歷算法

    萬年歷算法
    發(fā)表于 02-25 17:33

    電子萬年歷設(shè)計

    電子萬年歷設(shè)計
    發(fā)表于 08-20 22:46

    萬年歷

    如何在萬年歷加上鬧鐘
    發(fā)表于 09-24 15:29

    萬年歷

    萬年歷
    發(fā)表于 02-16 22:57

    萬年歷電路圖

    萬年歷電路圖萬年歷電路圖
    發(fā)表于 08-05 14:59

    萬年歷

    萬年歷萬年歷萬年歷萬年歷
    發(fā)表于 03-20 21:08

    萬年歷 仿真

    游戲 萬年歷
    發(fā)表于 07-08 11:19

    STM32RTC萬年歷制作本設(shè)計

    STM32RTC萬年歷制作本設(shè)計是用STM32F103c8t6制作的簡單萬年歷首先是配置RTC時鐘然后是配置時鐘,年月日等的處理頭文件本設(shè)計
    發(fā)表于 08-12 06:26

    如何去實現(xiàn)一種基于STM32F103的可調(diào)時鐘萬年歷

    如何用STM32F103內(nèi)部RTC實現(xiàn)可調(diào)時鐘萬年歷?如何去實現(xiàn)一種基于STM32F103的可調(diào)時鐘萬年歷呢?
    發(fā)表于 11-22 06:44

    星空GD32F303開發(fā)板的相關(guān)資料下載

    一、開發(fā)板介紹星空GD開發(fā)板是由旗點科技推出的一款GD32開發(fā)板,板載
    發(fā)表于 12-10 08:27

    萬年歷

    電子萬年歷,可以運(yùn)行的哦,單片機(jī)相關(guān)知識。
    發(fā)表于 05-17 11:09 ?16次下載

    萬年歷

    基于C51單片機(jī)的萬年歷
    發(fā)表于 12-17 20:48 ?119次下載

    ds1302萬年歷protues仿真 51單片機(jī)萬年歷仿真 實時

    ds1302萬年歷protues仿真 51單片機(jī)萬年歷仿真 實時時鐘仿真程序
    發(fā)表于 01-14 22:32 ?124次下載

    萬年歷protues仿真 實時時鐘仿真 12864萬年歷仿真 5

    萬年歷protues仿真 實時時鐘仿真 12864萬年歷仿真 51萬年歷設(shè)計
    發(fā)表于 01-14 22:32 ?175次下載

    GD32F303紅楓開發(fā)板使用手冊】第二十 SPI-SPI NAND FLASH讀寫實驗

    通過本實驗主要學(xué)習(xí)以下內(nèi)容: ?SPI通信協(xié)議,參考19.2.1東方紅開發(fā)板使用手冊 ?GD32F303 SPI操作方式,參考19.2.2東方紅
    的頭像 發(fā)表于 06-20 09:50 ?1072次閱讀
    【<b class='flag-5'>GD32F303</b><b class='flag-5'>紅楓</b><b class='flag-5'>派</b><b class='flag-5'>開發(fā)板</b><b class='flag-5'>使用手冊</b>】第二十<b class='flag-5'>講</b> SPI-SPI NAND FLASH讀寫<b class='flag-5'>實驗</b>
    百家乐百家乐游戏| 威尼斯人娱乐场荷官| 大西洋百家乐的玩法技巧和规则| 百家乐出千方法技巧| 新全讯网网址g5vvv| 罗甸县| 闲和庄百家乐官网娱乐场| 百家乐网址讯博网| 大发888赢钱技巧| 永利高百家乐官网进不去| 百家乐官网怎么| 百家乐筹码价格| 品尊国际娱乐| 澳门档百家乐官网的玩法技巧和规则| 玩百家乐出千方法| 皇家平台| 网上赌百家乐官网被抓应该怎么处理 | 百家乐官网正式版| 庞博百家乐的玩法技巧和规则| 本溪亿酷棋牌下载| 安桌百家乐官网游戏百家乐官网| 新濠百家乐现金网| 太阳城管理| 百家乐官网赌经| 百家乐游戏什么时间容易出| 威尼斯人娱乐成| 真人百家乐官网开户优惠| 网上玩百家乐的玩法技巧和规则| 鹤壁市| 菲律宾百家乐的说法| 在线棋牌游戏| 单机百家乐棋牌| 百家乐官网注册送免费金| 百家乐专业赌博| 澳门百家乐官网赢钱公式不倒翁| 八卦图24山代表的| 德州扑克保险| 百家乐娱乐城官方网| 235棋牌游戏| 百家乐投资心得| 大发888娱乐城主页|