在STM32里,一個CPU已經(jīng)足夠,不需要像DS1302這樣的實時時鐘芯片。實際上,RTC就只一個定時器而已,掉電之后所有信息都會丟失,因此我們需要找一個地方來存儲這些信息,于是就找到了備份寄存器。因為它掉電后仍然可以通過紐扣電池供電,所以能時刻保存這些數(shù)據(jù)。
- STM32的RTC模塊
RTC模塊之所以具有實時時鐘功能,是因為它內(nèi)部維持了一個獨立的定時器,通過配置,可以讓它準(zhǔn)確地每秒鐘中斷一次。
1.1 RTC的組成
RTC由兩個部分組成:APB1接口部分以及RTC核心部分。 STM32所有的外設(shè)默認(rèn)時鐘無效,使用某個外設(shè)時,再開啟時鐘,用這樣的方式來降低功耗。 這里的RTC,APB1 接口由APB1總線時鐘來驅(qū)動。為了突出時鐘吧?不過據(jù)說APB1接口部分還包括一組16 位寄存器。
RTC核心部分又分為預(yù)分頻模塊和一個32位的可編程計數(shù)器。前者可使每個TR_CLK 周期中RTC產(chǎn)生一個秒中斷,后者可被初始化為當(dāng)前系統(tǒng)時間。此后系統(tǒng)時間會按照TR_CLK周期進(jìn)行累加,實現(xiàn)時鐘功能。
1.2 對RTC的操作
我們對RTC的訪問,是通過APB1接口來進(jìn)行的。注意,APB1剛被開啟的時候(比如剛上電,或剛復(fù)位后),從APB1上讀出來的RTC寄存器的第一個值有可能是被破壞了的(通常讀到0)。這個不幸,STM32是如何預(yù)防的呢?我們在程序中,會先等待RTC_CRL寄存器中的RSF位(寄存器同步標(biāo)志)被硬件置1,然后才開始讀操作,這時候讀出來的值就是OK的。
那么對RTC寄存器的寫操作會不會有類似的情況呢?對于寫操作,我們只要注意, 每一次寫操作,必須確保在前一次寫操作完成后進(jìn)行。 這個“確保”,是通過查詢RTC_CR寄存器中的RTOFF狀態(tài)位,判斷RTC寄存器是否處于更新中。只有當(dāng)RTOFF狀態(tài)位是1,才可以寫RTC寄存器。
- RTC的編程
RTC的例程,主要是設(shè)置RTC時鐘,使得其在超級終端上顯示出當(dāng)前的時鐘。這個時鐘的顯示是“不停地走”。而且掉電后,重新上電,時鐘仍然在走,仍然顯示當(dāng)前的時間。當(dāng)然,如果感興趣,您可以讓它在LCD上顯示—— 那就是一個名副其實的電子鐘了。
編程的時候,首先要注意備份寄存器BKP_DR1,它做了一件關(guān)鍵的事情:判斷RTC是否已經(jīng)被設(shè)置過。 因為RTC跟其他計時器不同,它是使用紐扣電池單獨供電工作,所以它不會每次上電或者復(fù)位都被重置。判斷RTC是否已經(jīng)被設(shè)置過,可以決定當(dāng)前是否需要去設(shè)置RTC。如果剛安裝電池,第一次上電,自然需要去設(shè)置。否則的話,我們只要讓它顯示當(dāng)前時鐘即可。
當(dāng)?shù)谝淮问褂肦TC的時候(第一次配置),需要做的工作總結(jié)下:
1、打開電源管理和備份寄存器時鐘。注意,一定要打開備份寄存器的時鐘。
我們正是通過在備份寄存器寫固定的數(shù)據(jù)來判斷芯片是否第一次使用RTC,從而在系統(tǒng)運行RTC 時提示配置時鐘的。
2、使能RTC 和備份寄存器的訪問(復(fù)位默認(rèn)是關(guān)閉的,以防止可能存在的意外的寫操作)。
3、選擇外部低速晶體為RTC時鐘,并使能時鐘。筆者當(dāng)初調(diào)試RTC 的時候,犯了一個低級錯誤:由于沒有定義如下:
導(dǎo)致程序一直停留在這里:
/* Wait till LSE is ready */
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
{
}
希望大家能避免這個錯誤。
4、使能秒中斷,程序里在秒中斷里置位標(biāo)志位來通知主程序顯示時間數(shù)據(jù),同時在32 位計數(shù)器到23:59:59時清零;
5 、設(shè)置RTC 預(yù)分頻器值產(chǎn)生1秒信號計算公式fTR_CLK = fRTCCLK/(PRL+1),我們設(shè)置32767來產(chǎn)生秒信號。
我們再次強(qiáng)調(diào):所有在對RTC寄存器操作之前都要判斷讀寫操作是否完成,即內(nèi)部是否有讀寫操作。
下面來看代碼:
/* System Clocks Configuration */
RCC_Configuration();
/* NVIC configuration */
NVIC_Configuration();
/* Configure the GPIOs */
GPIO_Configuration();
/* Configure the USART1 */
USART_Configuration();
注意時鐘,為避免遺漏,筆者將其代碼放在第一位:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_PWR,ENABLE);
接著我們讀取備份寄存器BKP_DR1 中的值來判斷是否是第一次上電,如果不是則直接顯示時鐘,否則進(jìn)行時間設(shè)置。當(dāng)BKP_DR1的值不為0xAAAA,說明是第一次上電,此時需要對RTC進(jìn)行初始化。注意初始化的實現(xiàn)函數(shù)RTC_Configuration();,為什么那么寫,請參考我們之前給出的“第一次使用RTC的配置工作總結(jié)”,然后進(jìn)行時鐘設(shè)置。
注意,因為我們需要進(jìn)行寫操作,所以根據(jù)固件庫手冊,要先調(diào)用RTC_WaitForLastTask(),等待標(biāo)志位RTOFF被設(shè)置,保證在前一次寫操作結(jié)束后才能進(jìn)行。調(diào)用RTC_SetCounter(Time_Regulate());,將計數(shù)值寫入RTC計數(shù)器。
由于后面要通過BKP_WriteBackupRegister()函數(shù)對BKP_DR1寫操作,因此之前還需要進(jìn)行一次RTC_WaitForLastTask(),這樣,對時間的設(shè)置就完成了。
剩下的代碼,比較簡單,主要是注意如下:
RTCCount = RTC_GetCounter(); //獲得計數(shù)值并計算當(dāng)前時鐘
/* Compute hours */
THH = RTCCount/3600;
/* Compute minutes */
TMM = (RTCCount % 3600)/60;
/* Compute seconds */
TSS = (RTCCount % 3600)% 60;
這是通過RTC_GetCounter();函數(shù)獲取計數(shù)值,然后把這個計數(shù)值分別用小時、分鐘、秒來表示的過程。最后還需要調(diào)用printf 函數(shù)把它顯示出來。
-
cpu
+關(guān)注
關(guān)注
68文章
10911瀏覽量
213152 -
STM32
+關(guān)注
關(guān)注
2273文章
10926瀏覽量
357802 -
時鐘芯片
+關(guān)注
關(guān)注
2文章
253瀏覽量
39987 -
紐扣電池
+關(guān)注
關(guān)注
2文章
112瀏覽量
7687
發(fā)布評論請先 登錄
相關(guān)推薦
基于STM32CubeMX的實時時鐘(RTC)配置
RTC實時時鐘簡介
RTC是什么?RTC實時時鐘實驗
STM32CubeMX | 40 - 實時時鐘RTC的使用(日歷和鬧鐘)
![<b class='flag-5'>STM32</b>CubeMX | 40 - <b class='flag-5'>實時時鐘</b><b class='flag-5'>RTC</b>的使用(日歷和鬧鐘)](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
STM32開發(fā) -- RTC詳解
![<b class='flag-5'>STM32</b>開發(fā) -- <b class='flag-5'>RTC</b><b class='flag-5'>詳解</b>](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
stm32f4 RTC實時時鐘解析
![<b class='flag-5'>stm32</b>f4 <b class='flag-5'>RTC</b><b class='flag-5'>實時時鐘</b>解析](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
STM32CubeMX系列|RTC實時時鐘
![<b class='flag-5'>STM32</b>CubeMX系列|<b class='flag-5'>RTC</b><b class='flag-5'>實時時鐘</b>](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
評論