STM32處理器 RTC分析
前言:
1.博客基于ARM Cortex-M3內(nèi)核的STM32F103ZET6和標(biāo)準(zhǔn)3.5.0庫(kù);
2.如有不足之處,還請(qǐng)多多指教
一 RTC是什么?
1. 從結(jié)構(gòu)上講就是一個(gè)獨(dú)立的定時(shí)器;
2. 從功能上來(lái)說(shuō)就是為系統(tǒng)提供系統(tǒng)掉電不復(fù)位的日歷時(shí)間;
RTC分為兩個(gè)完全能獨(dú)立的部分:1. APB1接口;2. RTC核心;
功能:
(1)APB1總線連接APB1接口并負(fù)責(zé)驅(qū)動(dòng)APB1接口,接口內(nèi)部包含一組16位寄存器,可以通過(guò)APB1總線對(duì)其進(jìn)行讀寫(xiě)操作。
(2)RTC核心由RTC20位預(yù)分頻模塊和32位可編程計(jì)數(shù)器模塊組成;
Ⅰ RTC預(yù)分頻模塊包含一個(gè)20位的可編程分頻器RTC_DIV。預(yù)分頻模塊為32位計(jì)數(shù)器模塊提供時(shí)基單元,這個(gè)很重要;預(yù)分頻器內(nèi)的是一遞變(遞減)的值,當(dāng)遞減結(jié)束時(shí)如果開(kāi)啟相應(yīng)的中斷,將會(huì)觸發(fā)中斷,并且RTC_PRL重裝載寄存器將會(huì)將之前寫(xiě)入的分頻值再次裝載到預(yù)分頻器;
Ⅱ 計(jì)數(shù)器(RTC_CNT)概念很好理解,當(dāng)時(shí)基單元是1S時(shí),計(jì)數(shù)器可以記錄136年左右的時(shí)間,夠用了;若配置并使能了RTC_ALR(鬧鐘寄存器),當(dāng)RTC_CNT的值與其相等時(shí),將會(huì)觸發(fā)鬧鐘中斷;
二 RTC的時(shí)鐘源的選擇
(1)從圖片中可以看出有三個(gè)時(shí)鐘源:
1. HSE的128分頻
2. LSE (用的最多)
3. LSI
三 相關(guān)寄存器
(1)備份域控制寄存器RCC_BDCR
LSEON,LSEBYP,RTCSEL和RTCEN位都處于備份域,這些位在復(fù)位后處于寫(xiě)保護(hù)的狀態(tài),只有在電源控制寄存器PWR_CR中的DBP位置1后才能對(duì)這些位進(jìn)行改動(dòng);
RTCEN:RTC時(shí)鐘使能位;0:RTC關(guān)閉;1:RTC開(kāi)啟
RTCSEL[1:0]:RTC時(shí)鐘源選擇 00:無(wú)時(shí)鐘,01:LSE振蕩器(用的最多),10:LSI振蕩器,11:HSE振蕩器/128
LSEBYP:外部低速時(shí)鐘振蕩器旁路(旁路可以理解為開(kāi)關(guān),被旁路既是被關(guān)閉);0:LSE時(shí)鐘未被旁路(關(guān)閉);1:LSE時(shí)鐘被旁路(關(guān)閉);
LSEON:外部低速振蕩器使能;0:外部32KHz振蕩器關(guān)閉;1:外部32KHz振蕩器開(kāi)啟;
(2)控制寄存器(高位)RTC_CRH
RTC_CRH是用來(lái)控制RTC的相關(guān)中斷的
OWIE:允許溢出中斷位; 0:屏蔽RTC_CNT溢出中斷;1:使能RTC_CNT溢出中斷;
ALRIE:允許鬧鐘中斷; 0:屏蔽鬧鐘中斷;1:使能鬧鐘中斷;
SECIE:允許秒中斷; 0:屏蔽秒中斷;1:使能秒中斷;
(3)控制寄存器(低位)RTC_CRL(重要)
RTOFF(只讀):RTC操作; 0:上次對(duì)RTC寄存器的寫(xiě)操作仍在進(jìn)行;1:上次對(duì)RTC寄存器的寫(xiě)操作已經(jīng)完成;對(duì)RTC寄存器操作時(shí),必須要完成一次寫(xiě)操作之后(RTOFF=1)才能進(jìn)行下次寫(xiě)操作
CNF:配置標(biāo)志(重要);在對(duì)ALR,DIV,CNT寄存器配置之前,必須先配置該位軟件寫(xiě)1:進(jìn)入如配置模式,對(duì)CNT,ALR,PRL進(jìn)行賦值;0:退出配置模式(開(kāi)始更新RTC寄存器);
RSF:寄存器同步標(biāo)志;0:寄存器尚未同步;1:寄存器已經(jīng)同步;
每當(dāng)RTC_CNT和RTC_DIV由軟件更新或清0時(shí),此位由硬件置1;應(yīng)用程序必須等待這位被硬件置1,以確保CNT,ALR,PRL已經(jīng)被同步;
在APB1復(fù)位或APB1時(shí)鐘停止后,此位必須由軟件清0;
重要:由于APB1接口和RTC核心完全獨(dú)立,處理器在復(fù)位,睡眠,停機(jī)環(huán)境下是繼續(xù)工作的,但APB1接口停止了工作所以這里就出現(xiàn)了一個(gè)問(wèn)題是:當(dāng)處理器從復(fù)位睡眠停機(jī)情況下恢復(fù)過(guò)來(lái)的前一段時(shí)間,APB1接口和RTC核心還沒(méi)有完成同步工作;此時(shí)不能讀取RTC的值,不能對(duì)CRH/CRL進(jìn)行配置,要等RSF=1后,才可以對(duì)RTC的值進(jìn)行讀??;
OWF:溢出標(biāo)志; 0:CNT無(wú)溢出; 1:CNT溢出;
ALRF:鬧鐘標(biāo)志: 0:CNT≠ALR,沒(méi)有產(chǎn)生鬧鐘; 1:CNT≥ALR,鬧鐘產(chǎn)生;
SECF:秒標(biāo)志; 0:RTC_DIV沒(méi)有溢出;1:RTC_DIV溢出;
(4)RTC預(yù)分頻裝載寄存器RTC_PRLH(高)和RTC_PRLL(低)
這是兩個(gè)寄存器(唉!搞不懂為什么要整兩個(gè),可能為后期分頻系數(shù)增大做準(zhǔn)備把)
分頻公式為: Ftr_clk = Frtcclk/[19:0]+1
比如我們最常用的Frtc_clk = 32.768KHz ,([19:0]+1)=32768 ,代入得Ftr_clk = 1Hz = 1S;
(5)RTC預(yù)分頻器余數(shù)寄存器RTC_DIVH(高)和RTC_DIVL(低)
(6)備份寄存器BKP
和其他寄存器不同,備份寄存器包含42個(gè)16位的寄存器(共84字節(jié),中小容量STM芯片存儲(chǔ)空間為20字節(jié) );
功能:
1. 侵入檢測(cè);2. RTC校準(zhǔn);3. (常用)用BKP來(lái)存儲(chǔ)RTC的校驗(yàn)值或者記錄些重要的數(shù)據(jù),但是這里不要誤理解為是EEPROM,功能類(lèi)似,但是這個(gè)所在備份區(qū)域一旦完全掉電,就GG了;
特性:(重要)
1. BKP處于備份域,當(dāng)Vdd掉電時(shí),仍然有Vbat來(lái)供電。
2. 在系統(tǒng)待機(jī)喚醒,系統(tǒng)復(fù)位,掉電復(fù)位時(shí),備份域內(nèi)的數(shù)據(jù)將不會(huì)被復(fù)位,但一旦這些情況出現(xiàn),備份域和RTC都不能被訪問(wèn)了,這是為了保護(hù)這些情況發(fā)生時(shí)備份域和RTC的值不會(huì)被改變;這時(shí)需要下面操作才能繼續(xù)訪問(wèn):
Ⅰ 配置寄存器RCC_APB1ENR的PWREN位和BKPEN位來(lái)打開(kāi)電源和后備接口電源;
Ⅱ 電源控制寄存器PWR_CR的DBP位來(lái)使能對(duì)后備寄存器和RTC的訪問(wèn);
四 編程步驟
(1)使能電源時(shí)鐘和備份區(qū)域時(shí)鐘;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR " RCC_APB1Periph_BKP,ENABLE);
在上面解釋備份寄存器中講到的特性“Ⅰ”可以找到解釋?zhuān)?/p>
(2)取消備份區(qū)寫(xiě)保護(hù);
PWR_BackupAccessCmd(ENABLE);
對(duì)備份區(qū)域?qū)懭氡Wo(hù)是在每次復(fù)位后被使能,即復(fù)位后不能向備份區(qū)域?qū)懭霐?shù)據(jù)或修改寄存器,RTC核心的屬于備份區(qū)域,在進(jìn)行時(shí)鐘初始化的時(shí)候,不能對(duì)其寫(xiě)入數(shù)據(jù)是不合理的,所以必須要取消備份區(qū)寫(xiě)保護(hù);在上面解釋備份寄存器中講到的特性“Ⅱ”可以找到解釋?zhuān)?/p>
(3)復(fù)位備份區(qū);
BKP_DeInit();
在取消對(duì)備份區(qū)域的寫(xiě)保護(hù)完成后,備份區(qū)域可能還存在以前設(shè)置過(guò)的一些數(shù)據(jù)和配置;因?yàn)橐匦屡渲?,所以這里要初始化一下;
(4)開(kāi)啟外部低速振蕩器
RCC_LSEConfig(RCC_LSE_ON); //配置RCC_BDCR的LSEON位,開(kāi)啟RTC常用的時(shí)鐘源:LSE ;
特別注意:這個(gè)函數(shù)執(zhí)行完畢后不能急著執(zhí)行其他操作,因?yàn)槭且獑?dòng)外部晶振,所以需要一些時(shí)間;如果啟動(dòng)完成,備份域控制寄存器RCC_BDCR的LSERDY位將會(huì)被硬件置1;
(5)配置并使能RTC時(shí)鐘源
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //配置RCC_BDCR的RTCSEL[1:0]位,三個(gè)時(shí)鐘源,LSE最常用;
RCC_RTCCLKCmd(ENABLE); //配置RCC_BDCR的RTCEN位,啟動(dòng)RTC時(shí)鐘
**特別注意:**RTC時(shí)鐘源開(kāi)啟之后,需要等到時(shí)鐘源RTC_CNT,ALR,PRL三個(gè)寄存器同步了,才能對(duì)RTC進(jìn)行操作;
所以這里要等待一下:
RTC_WaitForSynchro(); //檢測(cè)RTC_CRL的RSF位,知道同步完成,結(jié)束函數(shù);
(6)配置RTC核心:分頻和時(shí)鐘;
Ⅰ RTC_EnterConfigMode(); //配置RTC_CRL的CNF位,允許配置
Ⅱ RTC_SetPrescaler( u32 ); //設(shè)置分頻數(shù) 通常為32767
RTC_WaitForLastTask(); //等待分頻數(shù)配置完成
Ⅲ RTC_Set(2009,12,2,10,0,55); //這個(gè)函數(shù)是自己寫(xiě)的;
Ⅳ RTC_ExitConfigMode(); //配置RTC_CRL的CNF位,禁止配置
(7)向備份區(qū)域?qū)懭胪瓿蓵r(shí)鐘配置的信息;
BKP_WriteBackupRegister(BKP_DR1,0x5050);
//有寫(xiě)入函數(shù)必然會(huì)有讀函數(shù),關(guān)于這個(gè)應(yīng)用的解釋可以在上面的備份寄存器中找到解釋?zhuān)?/p>
補(bǔ)充:以上程序步驟中如果還要添加鬧鐘中斷,秒中斷,溢出中斷,均可以添加;
下面為原子例程:
u8RTC_Init(void){u8temp=0;if(BKP_ReadBackupRegister(BKP_DR1)!=0x5050){RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP,ENABLE);PWR_BackupAccessCmd(ENABLE);BKP_DeInit();RCC_LSEConfig(RCC_LSE_ON);while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET&&temp<250){temp++;delay_ms(10);}if(temp>=250)return1;RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);RCC_RTCCLKCmd(ENABLE);RTC_WaitForLastTask();RTC_WaitForSynchro();RTC_ITConfig(RTC_IT_SEC,ENABLE);RTC_WaitForLastTask();RTC_EnterConfigMode();RTC_SetPrescaler(32767);RTC_WaitForLastTask();RTC_Set(2009,12,2,10,0,55);RTC_ExitConfigMode();BKP_WriteBackupRegister(BKP_DR1,0x5050);}else{RTC_WaitForLastTask();RTC_ITConfig(RTC_IT_SEC,ENABLE);RTC_WaitForLastTask();}RTC_NVIC_Config();RTC_Get();return0;}