一,背景知識
1、RTC時鐘源:有三種:IRC32K,內(nèi)部低速時鐘源,不精確,溫漂大;LXTAL:外部低速時鐘源,32.768KHz,精度高;HXTAL:外部高速時鐘源。
2、實(shí)時時鐘 (RTC) 是一個獨(dú)立的 BCD 定時器/計(jì)數(shù)器;32 位寄存器包含 BCD 格式的秒、分鐘、小時(12 或 24 小時制)、星期幾、日期、月份和年份。
3、BCD進(jìn)制:BCD進(jìn)制是便于人們快速進(jìn)行二進(jìn)制和十進(jìn)制之間的轉(zhuǎn)換產(chǎn)生的,是由4位bit表示十進(jìn)制中的0~9。4位bit可以表示的范圍是2^4=16,所以BCD進(jìn)制也有幾種分類:
8421碼:因?yàn)閺淖蟮接疫@4位bit,每位為1其他位為0時分別對應(yīng)十進(jìn)制數(shù)值8/4/2/1,以此得名。
余3碼:在8421碼的基礎(chǔ)上偏移3
2421碼:
二、RTC初始化
初始化部分按照GD的RTC例程,去掉提示信息printf這些不需要的東西。初始化先隨意設(shè)置一個時間,第二章節(jié)會講解如何按照用戶需求設(shè)定時間。
1、宏定義和全局變量:
選定RTC的時鐘源--LXTAL,定義RTC的句柄全局變量。
#define RTC_CLOCK_SOURCE_LXTAL //使用外部32.768K晶振#define BKP_VALUE 0x32F1 rtc_parameter_struct rtc_initpara; //RTC句柄
2、RTC的初始化:
使能寄存器寫入,選擇時鐘源,設(shè)置分頻值產(chǎn)生1Hz時鐘頻率:時鐘源頻率/( prescaler_a * prescaler_s)=32768/(0x7f * 0xff)=1,使能外設(shè)時鐘。
void RTC_Init(void){ /* enable PMU clock */ rcu_periph_clock_enable(RCU_PMU); /* enable the access of the RTC registers */ pmu_backup_write_enable(); rtc_pre_config(); /* get RTC clock entry selection */ RTCSRC_FLAG = GET_BITS(RCU_BDCTL, 8, 9); /* check if RTC has aready been configured */ if ((BKP_VALUE != RTC_BKP0) || (0x00 == RTCSRC_FLAG)) { /* backup data register value is not correct or not yet programmed or RTC clock source is not configured (when the first time the program is executed or data in RCU_BDCTL is lost due to Vbat feeding) */ rtc_setup(); } rcu_all_reset_flag_clear();} /*! \brief RTC configuration function \param[in] none \param[out] none \retval none*/void rtc_pre_config(void){ #if defined (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 defined (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();} /*! \brief use hyperterminal to setup RTC time and alarm \param[in] none \param[out] none \retval none*/void rtc_setup(void){ /* setup RTC time value */ uint32_t tmp_hh = 0x00, tmp_mm = 0x00, tmp_ss = 0x00; rtc_initpara.factor_asyn = prescaler_a; rtc_initpara.factor_syn = prescaler_s; rtc_initpara.year = 0x16; rtc_initpara.day_of_week = 0; rtc_initpara.month = RTC_APR; rtc_initpara.date = 0x30; 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; /* RTC current time configuration */ if(ERROR != rtc_init(&rtc_initpara)) { RTC_BKP0 = BKP_VALUE; }}
三、設(shè)置時間和獲取時間1、BCD和二進(jìn)制轉(zhuǎn)換函數(shù):
/** * @brief Convert a 2 digit decimal to BCD format. * @param Value: Byte to be converted * @retval Converted byte */uint8_t byte_to_bcd(uint8_t Value){ uint32_t bcdhigh = 0; while(Value >= 10) { bcdhigh++; Value -= 10; } return ((uint8_t)(bcdhigh << 4) | Value);} /** * @brief Convert from 2 digit BCD to Binary. * @param Value: BCD value to be converted * @retval Converted word */uint8_t bcd_to_byte(uint8_t Value){ uint32_t tmp = 0; tmp = ((uint8_t)(Value & (uint8_t)0xF0) >> (uint8_t)0x4) * 10; return (tmp + (Value & (uint8_t)0x0F));}
2、設(shè)置指定時間:
注意一定要將年月日時分秒等參數(shù)從二進(jìn)制轉(zhuǎn)換成BCD,再賦值給rtc_initpara
typedefstruct{uint8_t year;uint8_t month;uint8_t date;uint8_t hour;uint8_t minute;uint8_t second;}S_RTCTimeInfo;//均為二進(jìn)制格式 S_RTCTimeInfo RTCTime;//RTC全局變量,存儲外界輸入的待設(shè)定的時間 /*需要設(shè)定時間時調(diào)用此函數(shù),將時間賦值給RTC句柄*/void RtcSetTime(S_RTCTimeInfo time){ rtc_initpara.year = byte_to_bcd(time.year); rtc_initpara.month= byte_to_bcd(time.month); rtc_initpara.date= byte_to_bcd(time.date); rtc_initpara.hour= byte_to_bcd(time.hour); rtc_initpara.minute= byte_to_bcd(time.minute); rtc_initpara.second= byte_to_bcd(time.second); rtc_init(&rtc_initpara);}
3、獲取當(dāng)前時間:
void RtcGetTime(void){ rtc_current_time_get(&rtc_initpara); RTCTime.year = bcd_to_byte(rtc_initpara.year); RTCTime.month= bcd_to_byte(rtc_initpara.year); RTCTime.date= bcd_to_byte(rtc_initpara.year); RTCTime.hour= bcd_to_byte(rtc_initpara.year); RTCTime.minute= bcd_to_byte(rtc_initpara.year); RTCTime.second= bcd_to_byte(rtc_initpara.year);}
四、遇到的問題
1、如果不使用周幾,可以將rtc_initpara.day_of_week設(shè)為0,這樣就不啟用這項(xiàng)了。如果初始化時設(shè)置了day_of_week,后續(xù)修改設(shè)定時間時沒有將這項(xiàng)對應(yīng)修改,會造成設(shè)置的時間不準(zhǔn)。因?yàn)樵O(shè)定時間賦值后會進(jìn)行rtc_init,day_of_week會影響reg_date。
/*gd32f4xx_rtc.c文件中*/ErrStatus rtc_init(rtc_parameter_struct *rtc_initpara_struct){ ErrStatus error_status = ERROR; uint32_t reg_time = 0U, reg_date = 0U; reg_date = (DATE_YR(rtc_initpara_struct->year) | \ DATE_DOW(rtc_initpara_struct->day_of_week) | \ DATE_MON(rtc_initpara_struct->month) | \ DATE_DAY(rtc_initpara_struct->date));...省略部分代碼}
2、當(dāng)沒有使用宏定義,而是使用數(shù)字給rtc_initpara 的年月日時分秒賦值時,一定要進(jìn)行二進(jìn)制到BCD的轉(zhuǎn)換。對于此問題,STM32H7的HAL庫就封裝的很人性化,HAL庫函數(shù)提供了可以選擇使用哪種進(jìn)制,,用戶只需要選擇對應(yīng)的進(jìn)制,傳入?yún)?shù)即可,不需要自己進(jìn)行進(jìn)制轉(zhuǎn)換。
/*stm32h7xx_hal_rtc.c文件*/ /** * @brief Set RTC current date. * @param hrtc: RTC handle * @param sDate: Pointer to date structure * @param Format: specifies the format of the entered parameters. * This parameter can be one of the following values: * @arg RTC_FORMAT_BIN: Binary data format * @arg RTC_FORMAT_BCD: BCD data format * @retval HAL status */HAL_StatusTypeDefHAL_RTC_SetDate(RTC_HandleTypeDef*hrtc,RTC_DateTypeDef*sDate,uint32_tFormat);
-
BCD
+關(guān)注
關(guān)注
1文章
85瀏覽量
29646 -
RTC
+關(guān)注
關(guān)注
2文章
522瀏覽量
66227 -
時鐘源
+關(guān)注
關(guān)注
0文章
92瀏覽量
15921
發(fā)布評論請先 登錄
相關(guān)推薦
評論