|
要使用RTC,一般來(lái)說(shuō)也順帶地使用上后備寄存器—這是因?yàn)镽TC是一個(gè)簡(jiǎn)單的秒中斷定時(shí)器,年月日時(shí)分秒的信息必須要找個(gè)地方能掉電保存才有意義.STM32的備份寄存器(BKP)是42個(gè)16位的寄存器,可用來(lái)存儲(chǔ)84個(gè)字節(jié)的用戶(hù)應(yīng)用程序數(shù)據(jù)。他們處在備份域里,當(dāng)VDD電源被切斷,他們?nèi)匀挥蒝BAT維持供電。當(dāng)系統(tǒng)在待機(jī)模式下被喚醒,或系統(tǒng)復(fù)位或電源復(fù)位時(shí),他們也不會(huì)被復(fù)位。此外,BKP控制寄存器用來(lái)管理侵入檢測(cè)和RTC校準(zhǔn)功能。復(fù)位后,對(duì)備份寄存器和RTC的訪問(wèn)被禁止,并且備份域被保護(hù)以防止可能存在的意外的寫(xiě)操作它是用后備電池供電的,只要配置好后,即使系統(tǒng)關(guān)電,32768的晶振和后備寄存器的數(shù)據(jù)也會(huì)得以維持.而且RTC的計(jì)數(shù)器是會(huì)繼續(xù)秒遞增的。

這里引用手冊(cè)里一段概述“RTC由兩個(gè)主要部分組成。第一部分(APB1接口)用來(lái)和 APB1總線相連。此單元還包含一組16位寄存器,可通過(guò) APB1總線對(duì)其進(jìn)行讀寫(xiě)操作。APB1接口以APB1總線時(shí)鐘為時(shí)鐘,用來(lái)與 APB1總線接口。
另一部分(RTC核)由一系列可編程計(jì)數(shù)器組成,分成兩個(gè)主要模塊。第一個(gè)模塊是RTC的預(yù)分頻模塊,它可編程產(chǎn)生最長(zhǎng)為 1秒的 RTC時(shí)間基準(zhǔn)TR_CLK。RTC的預(yù)分頻模塊包含了一個(gè)20位的可編程分頻器(RTC預(yù)分頻器)。在每個(gè)TR_CLK周期中,如果在 RTC_CR寄存器中設(shè)置了相應(yīng)允許位,則 RTC產(chǎn)生一個(gè)中斷(秒中斷)。第 2個(gè)模塊是一個(gè)32位的可編程的計(jì)數(shù)器,它可被初始化為當(dāng)前的系統(tǒng)時(shí)間。系統(tǒng)時(shí)間以 TR_CLK速度增長(zhǎng)并與存儲(chǔ)在RTC_ALR寄存器中的可編程的時(shí)間相比較,如果RTC_CR控制寄存器中設(shè)置了相應(yīng)允許位,則比較匹配時(shí)將產(chǎn)生一個(gè)鬧鐘中斷!
對(duì)于第一次實(shí)用RTC的時(shí)候我們要對(duì)它進(jìn)行配置一番,現(xiàn)在大致說(shuō)一下(代碼是通過(guò)調(diào)用RTC_Config函數(shù)來(lái)實(shí)現(xiàn)的):
1.打開(kāi)電源管理和備份寄存器時(shí)鐘,提到備份寄存器這里要說(shuō)一下,引用手冊(cè)--“備份寄存器是10個(gè) 16位的寄存器,可用來(lái)存儲(chǔ) 20個(gè)字節(jié)的用戶(hù)應(yīng)用程序數(shù)據(jù)。他們處在備份域里,當(dāng)VDD電源被切斷,他們?nèi)匀挥?/strong>VBAT維持供電。當(dāng)系統(tǒng)在待機(jī)模式下被喚醒,或系統(tǒng)復(fù)位或電源復(fù)位時(shí),他們也不會(huì)被復(fù)位。”我們正式通過(guò)在備份寄存器寫(xiě)固定的數(shù)據(jù)來(lái)判斷芯片是否第一次實(shí)用RTC,從而在系統(tǒng)運(yùn)行RTC時(shí)提示配置時(shí)鐘的。
2.使能RTC和備份寄存器的訪問(wèn)(復(fù)位默認(rèn)關(guān)閉)。引用手冊(cè)--“復(fù)位后,對(duì)備份寄存器和RTC的訪問(wèn)被禁止,并且備份域被保護(hù)以防止可能存在的意外的寫(xiě)操作。電源控制寄存器(PWR_CR)的 DBP位必須被置1,以允許訪問(wèn)備份寄存器和RTC.”因?yàn)槌绦蛞獙?duì)RTC和備份寄存器操作,所以必須使能。
3.選擇外部低速晶體為RTC時(shí)鐘,并使能時(shí)鐘;
4.使能秒中斷,程序里在秒中斷里置位標(biāo)志位來(lái)通知主程序顯示時(shí)間數(shù)據(jù),同時(shí)在32位計(jì)數(shù)器到23:59:59時(shí)清零;
5.設(shè)置RTC預(yù)分頻器值產(chǎn)生1秒信號(hào)計(jì)算公式fTR_CLK = fRTCCLK/(PRL+1),我們?cè)O(shè)置32767來(lái)產(chǎn)生秒信號(hào);
下面是RTC初始化程序
void RTC_configuration()
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP|RCC_APB1Periph_PWR,ENABLE);
PWR_BackupAccessCmd(ENABLE);//使能RTC后備寄存器的寫(xiě)
BKP_DeInit();//BKP寄存器全部設(shè)為缺省值
RCC_LSEConfig(RCC_LSE_ON); //RCC打開(kāi)了LSE時(shí)鐘
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET);//等待LSE就緒,一般來(lái)說(shuō),如果諧振不對(duì),就會(huì)死在這里,實(shí)際代碼請(qǐng)慎重
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//RTC使用時(shí)鐘源LSE
RCC_RTCCLKCmd(ENABLE);//RTC的時(shí)鐘開(kāi)啟
RTC_WaitForSynchro();//RTC等待同步,
RTC_WaitForLastTask();//這個(gè)代碼在RTC中常常出現(xiàn),類(lèi)似于等待就緒的含義
//RTC_ITConfig(RTC_IT_SEC, ENABLE);//RTC秒中斷
RTC_WaitForLastTask();//
RTC_SetPrescaler(32767);//RTC預(yù)分頻,32768HZ,分為一秒一個(gè)振蕩,RTCperiod = RTCCLK/RTC_PR = (32.768KHz)/(32767+1)
RTC_WaitForLastTask(); //等待同步
PWR_BackupAccessCmd(DISABLE);//禁止RTC后備寄存器的寫(xiě)
}
為啥要不停的等呢??
在這里要注意一下,所有在對(duì)RTC寄存器操作之前都要判斷讀寫(xiě)操作是否完成,也就是說(shuō)當(dāng)前是否有讀寫(xiě)操作。系統(tǒng)內(nèi)核是通過(guò)RTC的APB1接口來(lái)訪問(wèn)RTC內(nèi)部寄存器的,所以在上電復(fù)位,休眠喚醒的時(shí)候,我們要先對(duì)RTC時(shí)鐘與RTCAPB1時(shí)鐘進(jìn)行重新同步,在同步完成后再對(duì)器進(jìn)行操作,因?yàn)镽TC的AP1接口使用的系統(tǒng)APB1的時(shí)鐘。上述配置在初次使用RTC時(shí)進(jìn)行配置,在以后使用過(guò)程中,只要RTC外部電池持續(xù)供電,無(wú)論系統(tǒng)掉電還復(fù)位我們都無(wú)需重復(fù)配置,使用使能秒中斷就可以了這一點(diǎn)很是方便嘿嘿...
RTC核完全獨(dú)立于RTCAPB1接口。軟件通過(guò)APB1接口訪問(wèn)RTC的預(yù)分頻值、計(jì)數(shù)器值和鬧鐘值。但是,相關(guān)的可讀寄存器只在與RTCAPB1時(shí)鐘進(jìn)行重新同步的RTC時(shí)鐘的上升沿被更新。RTC標(biāo)志也是如此的。這意味著,如果APB1接口曾經(jīng)被關(guān)閉,而讀操作又是在剛剛重新開(kāi)啟APB1之后,則在第一次的內(nèi)部寄存器更新之前,從APB1上讀出的RTC寄存器數(shù)值可能被破壞了(通常讀到0)。
因此,若在讀取RTC寄存器時(shí),RTC的APB1接口曾經(jīng)處于禁止?fàn)顟B(tài),則軟件首先必須等待RTC_CRL寄存器中的RSF位(寄存器同步標(biāo)志)被硬件置’1’。
注: RTC的APB1接口不受WFI和WFE等低功耗模式的影響。
NVIC的配置
void NVIC_Configuration()
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 搶占式優(yōu)先級(jí)別
NVIC_InitStructure.NVIC_IRQChannel =RTC_IRQChannel;//指定中斷源
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;// 指定響應(yīng)優(yōu)先級(jí)別1
NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void RTC_IRQHandler(void)
{
if(RTC_GetITStatus(RTC_IT_SEC) != RESET)//RTC發(fā)生了秒中斷(也有可能是溢出或者鬧鐘中斷)
{
//此處添加代碼
RTC_ClearITPendingBit(RTC_IT_SEC);
}
}
|
|