第4章
時鐘的驅動-RTC
4.1 RTC簡介
RTC是一種提供日期/時間的周邊硬體元件,常用於嵌入式系統中顯示時間資訊和紀錄事件發生的時間,RTC擁有一組連續計數的計數器,在相應軟體配置下,可以修改計數器的值來重新配置當前的時間和日期。
RTC模塊和時鐘的配置系統(RCC_BDCR暫存器)位於後備區(BKP),一旦系統主電源斷電,RTC仍可藉由輔助電力(例如鈕扣電池)維持運作,因而可實現不中斷的即時時鐘功能。但是在系統使用輔助電力時,會禁止訪問後備區(BKP)的暫存器和RTC,以防止對後備區(BKP)的意外寫入操作,所以在設置時間之前,先要取消後備區(BKP)寫入保護,可用以下方式:
l 藉由設置RCC_APB1ENR暫存器中的PWREN與 BKPEN 位,將電源與後備區的時鐘起始。
l 設置Power Control Register (PWR_CR)的DBP位,將後備區暫存器與RTC的存取機制啟動。
4.2 功能概述
RTC 主要分成兩個部分(如下圖),第一個部分(APB1介面)是用來和APB1的匯流排連接,此單元包含一個16位的暫存器,可以透過APB1匯流排對此暫存器進行讀寫的操作,APB1介面由APB1匯流排的時鐘所驅動,藉此與APB1匯流排連接。
另一部分(RTC核心)由一組可編程計數器組成,分成兩個主要模塊。第一塊模塊是RTC的除頻器模塊,可編程產生最長為1秒的TR_CLK作為RTC基準時間。 RTC的除頻器模塊包含了一個20位的可編程除頻器(RTC除頻器)。如果在RTC_CR暫存器起始相應的Enable bit,則在每個TR_CLK週期中RTC產生一個中斷(秒中斷)。第二個模塊是一個32位的可編程計數器,可被初始化為當前的系統時間,一個32位的時鐘計數器,按秒鐘計算,可以記錄4294967296秒,約為136年左右,作為一般應用這已經非常足夠了,此外,除頻的時間計算為 RTCCLK/RTC_PR = (32.768 KHz)/(32767+1)。
RTC還有一個鬧鐘暫存器RTC_ALR,用於產生鬧鐘,比較系統時間TR_CLK與存儲在RTC_ALR暫存器中的可編程時間,比較匹配時將產生一個鬧鐘中斷(如果RTC_CR控制暫存器中設置了相應Enable bit)。
4.3 RTC 暫存器描述
以下介紹RTC中所使用的暫存器。
4.3.1 RTC Control register high (RTC_CRH)
這些位用來屏蔽中斷請求。注意:系統重新設置後所有的中斷都會取消,因此可通過寫RTC暫存器來確保在初始化後沒有掛起中斷的請求。當周邊正在完成前一次寫入操作時(標誌位RTOFF=0),不能對RTC_CRH暫存器進行寫操作。
RTC功能由這個控制暫存器控制。一些位的寫操作必須經過一個特殊的配置過程來完成。
4.3.2 RTC Control register low (RTC_CRL)
RTC的功能由這個控制暫存器控制,當前一個寫操作還沒完成時(RTOFF=0時),不能寫入RTC_CR暫存器。
4.3.3 RTC prescaler load register(RTC_PRLH / RTC_PRLL)
除頻器暫存器用來保存RTC除頻器的周期計數值。它們受RTC_CR暫存器的RTOFF位保護,當RTOFF值為'1'時允許進行寫操作。
註:如果輸入的時鐘頻率為32.768kHz(fRTCCLK),這個暫存器寫入7FFFh可獲得週期為1秒鐘的信號。
4.3.4 RTC prescaler divider register (RTC_DIVH / RTC_DIVL)
在TR_CLK的每個週期裡,RTC除頻器中計數器的值都會被重新設置為RTC_PRL暫存器的值。使用者可通過讀取RTC_DIV暫存器,取得除頻器計數器的當前值,而不停止除頻器的工作,從而獲得精確的時間測量。此暫存器是只讀暫存器,其值在RTC_PRL或RTC_CNT暫存器中的值發生改變後,由硬體重新裝載。
4.3.5 RTC counter register (RTC_CNTH / RTC_CNTL)
RTC核心有一個32位可編程的計數器,可通過兩個16位的暫存器訪問。計數器以除頻器產生的TR_CLK時間基準為參考進行計數。 RTC_CNT暫存器用來存放計數器的計數值。他們受RTC_CR上的位RTOFF寫保護,僅當RTOFF值為'1'時,允許寫操作。在RTC_CNTH或RTC_CNTL)上的進行寫操作,能夠直接裝載到相應的可編程計數器,並且重新裝載RTC除頻器。當進行讀操作時,直接返回計數器內的計數值(系統時間)。
4.3.6 RTC alarm register high (RTC_ALRH / RTC_ALRL)
當可編程計數器的值與RTC_ALR中的32位值相等時,即觸發一個鬧鐘事件,並且產生RTC鬧鐘中斷。此暫存器受RTC_CR暫存器裡的RTOFF位寫保護,僅當RTOFF值為'1'時,允許寫操作。
4.4 RTC Standard Driver Library
以下介紹RTC的Firmware Library functions。
3.4.1 RTC register structure
RTC 暫存器結構, RTC_TypeDef, 定義在 stm32f10x_map.h 檔案,如以下敘述:
RTC的暫存器介紹:
RTC周邊宣告在stm32f10x_map.h:
4.4.2 RTC firmware library function
以下提供了各種樣式的RTC function:
以下列舉幾項實驗會用到的Function,詳細請參考ARM-based 32-bit MCU STM32F101xx and STM32F103xx firmware library.
l RTC Interrupt Configure Function
l RTC EnterConfigure Mode Function
l RTC ExitConfigure Mode Function
l RTCGet Counter Function
l RTCSet Counter Function
l RTCSetPrescaler Function
l RTCSetAlarm Function
l RTCGetFlag Status Function
l RTCClearFlag Status Function
4.5 立即演練
嵌入式軟體架構如圖說明:
嵌入式軟體Grafcet圖:
實驗1 使用超級終端機顯示時間
實驗說明:使用RTC second interrupt來產生時間,並用Virtual COM Port 在超級終端機上顯示時間。
程式碼片段介紹:
|
|
l NVIC Configure
|
|
l RTC Configure
void RTC_Configuration(void) { /* Enable PWR and BKP clocks */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); PWR_BackupAccessCmd(ENABLE); /* Allow access to BKP Domain */ BKP_DeInit(); /* Reset Backup Domain */ RCC_LSEConfig(RCC_LSE_ON); /* Enable LSE */ while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET); /* Wait till LSE is ready */ RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); /* Select LSE as RTC Clock Source */ RCC_RTCCLKCmd(ENABLE); /* Enable RTC Clock */ RTC_WaitForLastTask(); RTC_WaitForSynchro(); /* Wait for RTC registers synchronization */ RTC_WaitForLastTask(); /* Wait until last write operation on RTC registers has finished */ RTC_ITConfig(RTC_IT_SEC, ENABLE); /* Enable the RTC Second */ RTC_WaitForLastTask(); /* Wait until last write operation on RTC registers is terminated */ /*接續上頁*/ /* Set RTC prescaler: set RTC period to 1sec */ RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */ RTC_WaitForLastTask(); /* Wait until last write operation on RTC registers has finished */ }
|
Time_Regulate( ) & Time_Adjust( ) function
u32 Time_Regulate(void)
{
u32 Tmp_HH = 0xFF, Tmp_MM = 0xFF, Tmp_SS = 0xFF;
Tmp_HH =0;
Tmp_MM = 0;
Tmp_SS = 0; *
/* Return the value to store in RTC counter register */
return((Tmp_HH*3600 + Tmp_MM*60 + Tmp_SS));
}
void Time_Adjust(void)
{ RTC_WaitForLastTask();
RTC_SetCounter(Time_Regulate()); /* Change the current time */
RTC_WaitForLastTask();
}
Time_Display( ) & Time_Show( ) function
|
l RTC Interrupt Handler
實驗結果:
第一次啟動 (BKP_DR1) != 0xA5A5
將SIOC Reset(不斷電) (BKP_DR1) == 0xA5A5
實驗2 調整RTC時間
實驗說明:利用 RTC second interrupt來產生時間,並用Virtual COM Port 在超級終端機上顯示時間,請修改u32 Time_Regulate(void) ,讓使用者自行輸入現在時間, 使用printf()與scanf() 。
程式碼片段介紹:
|
實驗結果:
實驗3 使用RTC鬧鐘
實驗說明:利用RTC alarm interrupt 製作鬧鐘,請使用者先輸入現在時間,再輸入鬧鐘時間,請參考RTC second interrupt 的使用方式,修改void TC_Configuration(void) 、void Time_Adjust(void)、void RTC_IRQHandler(void)
程式碼片段介紹:
l RTC Configure
|
l Time Adjust
|
l RTC Interrupt Handler
|
實驗結果: