STM32處理器內部集成了實時時鐘控制器(RTC),因此在實現實時時鐘功能時,無須外擴時鐘芯片即可構建實時時鐘系統。
實時時鐘 (RTC) 是一個獨立的 BCD 定時器/計數器。RTC 提供一個日歷時鐘、兩個可編程鬧鐘中斷,以及一個具有中斷功能的周期性可編程喚醒標志。RTC 還包含用于管理低功耗模式的自動喚醒單元。
兩個 32 位寄存器包含二進碼十進數格式 (BCD) 的秒、分鐘、小時(12 或 24 小時制)、星期幾、日期、月份和年份。此外,還可提供二進制格式的亞秒值。系統可以自動將月份的天數補償為 28、29(閏年)、30 和 31天。并且還可以進行夏令時補償。其它 32 位寄存器還包含可編程的鬧鐘亞秒、秒、分鐘、小時、星期幾和日期。
此外,還可以使用數字校準功能對晶振精度的偏差進行補償。
上電復位后,所有 RTC 寄存器都會受到保護,以防止可能的非正常寫訪問。無論器件狀態如何(運行模式、低功耗模式或處于復位狀態),只要電源電壓保持在工作范圍內,RTC 便不會停止工作。
STM32F4XX的RTC模塊和時鐘配置可設置在備份區域,這樣系統復位或者從待機模式喚醒后RTC的設置和時間依然維持不變,只要備份域供電正常,RTC模塊就能持續地走時。為防止備份域被意外寫操作,備份區域也是被寫保護的。
備份區域包含20個備份寄存器,共80個字節。可利用備份寄存器模擬EEPROM,實現非易失功能,但是必須保證備份區域供電正常。通常,為保證系統掉電后RTC能夠正常走時且備份寄存器非易失,都會為RTC模塊配備一枚紐扣電池。
RTC框圖
時鐘和預分頻器
RTC 時鐘源 (RTCCLK) 通過時鐘控制器從 LSE 時鐘、LSI 振蕩器時鐘以及 HSE 時鐘三者中選擇。
可編程的預分頻器階段可生成 1 Hz 的時鐘,用于更新日歷。為最大程度地降低功耗,預分頻器分為 2 個可編程的預分頻器:
● 一個通過 RTC_PRER 寄存器的 PREDIV_A 位配置的 7 位異步預分頻器。
● 一個通過 RTC_PRER 寄存器的 PREDIV_S 位配置的 15 位同步預分頻器。
實時時鐘和日歷
RTC 日歷時間和日期寄存器可通過與 PCLK1(APB1 時鐘)同步的影子寄存器來訪問。這些時間和日期寄存器也可以直接訪問,這樣可避免等待同步的持續時間。
● RTC_SSR 對應于亞秒
● RTC_TR 對應于時間
● RTC_DR 對應于日期
每隔兩個 RTCCLK 周期,便將當前日歷值復制到影子寄存器,并將 RTC_ISR 寄存器的 RSF位置 1。在停機和待機模式下不會執行復制操作。退出這兩種模式時,影子寄存器會在最長 2 個 RTCCLK 周期后進行更新。
當應用讀取日歷寄存器時,它會訪問影子寄存器的內容。也可以通過將 RTC_CR 寄存器的
BYPSHAD 控制位置 1 來直接訪問日歷寄存器。默認情況下,該位被清零,用戶訪問影子寄存器。
在 BYPSHAD=0 模式下讀取 RTC_SSR、RTC_TR 或 RTC_DR 寄存器時,APB 時鐘頻率(f APB ) 必須至少為 RTC 時鐘頻率 (f RTCCLK ) 的 7 倍。
影子寄存器通過系統復位來復位。
RTC 寄存器寫保護
系統復位后,可通過 PWR 電源控制寄存器 (PWR_CR) 的 DBP 位保護 RTC 寄存器以防止非正常的寫訪問。必須將 DBP 位置 1 才能使能 RTC 寄存器的寫訪問。
上電復位后,所有 RTC 寄存器均受到寫保護。通過向寫保護寄存器 (RTC_WPR) 寫入一個密鑰來使能對 RTC 寄存器的寫操作。
要解鎖所有 RTC 寄存器(RTC_ISR[13:8]、RTC_TAFCR 和 RTC_BKPxR 除外)的寫保護,需要執行以下步驟:
- 將“0xCA”寫入 RTC_WPR 寄存器。
- 將“0x53”寫入 RTC_WPR 寄存器。
寫入一個錯誤的關鍵字會再次激活寫保護。保護機制不受系統復位影響。
日歷初始化和配置
要編程包括時間格式和預分頻器配置在內的初始時間和日期日歷值,需按照以下順序操作:
- 將 RTC_ISR 寄存器中的 INIT 位置 1 以進入初始化模式。在此模式下,日歷計數器將停止工作并且其值可更新。
- 輪詢 RTC_ISR 寄存器中的 INITF 位。當 INITF 置 1 時進入初始化階段模式。大約需要2 個 RTCCLK 時鐘周期(由于時鐘同步)。
- 要為日歷計數器生成 1 Hz 時鐘,應首先編程 RTC_PRER 寄存器中的同步預分頻系數,然后編程異步預分頻系數。即使只需要更改這兩個字段中之一,也必須對 RTC_PRER寄存器執行兩次單獨的寫訪問。
- 在影子寄存器(RTC_TR 和 RTC_DR)中加載初始時間和日期值,然后通過 RTC_CR寄存器中的 FMT 位配置時間格式(12 或 24 小時制)。
- 通過清零 INIT 位退出初始化模式。隨后,自動加載實際日歷計數器值,在 4 個 RTCCLK時鐘周期后重新開始計數。
當初始化序列完成之后,日歷開始計數。
注意:系統復位后,應用可讀取 RTC_ISR 寄存器中的 INITS 標志,以檢查日歷是否已初始化。如果該標志為 0 ,表明日歷尚未初始化,因為年份字段設置為其上電復位時的默認值 (0x00) 。
要在初始化之后讀取日歷,必須首先用軟件檢查 RTC_ISR 寄存器的 RSF 標志是否置 1 。
接著查看寄存器描述:
RTC 時間寄存器 (RTC_TR)
RTC_TR 是日歷時間影子寄存器。只能在初始化模式下對該寄存器執行寫操作。
位 22 PM:AM/PM 符號 (AM/PM notation)
0:AM 或 24 小時制
1:PM
位 21:20 HT[1:0]: 小時的十位(BCD 格式)(Hour tens in BCD format)
位 16:16 HU[3:0]: 小時的個位(BCD 格式)(Hour units in BCD format)
位 14:12 MNT[2:0]: 分鐘的十位(BCD 格式)(Minute tens in BCD format)
位 11:8 MNU[3:0]: 分鐘的個位(BCD 格式)(Minute units in BCD format)
位 6:4 ST[2:0]: 秒的十位(BCD 格式)(Second tens in BCD format)
位 3:0 SU[3:0]: 秒的個位(BCD 格式)(Second units in BCD format)
RTC 日期寄存器 (RTC_DR)
RTC_DR 是日歷日期影子寄存器。只能在初始化模式下對該寄存器執行寫操作。
位 23:20 YT[3:0]: 年份的十位(BCD 格式)(Year tens in BCD format)
位 19:16 YU[3:0]: 年份的個位(BCD 格式)(Year units in BCD format)
位 15:13 WDU[2:0]: 星期幾的個位 (Week day units)
000:禁止
001:星期一
...
111:星期日
位 12 MT: 月份的十位(BCD 格式)(Month tens in BCD format)
位 11:8 MU: 月份的個位(BCD 格式)(Month units in BCD format)
位 5:4 DT[1:0]: 日期的十位(BCD 格式)(Date tens in BCD format)
位 3:0 DU[3:0]: 日期的個位(BCD 格式)(Date units in BCD format)
RTC 控制寄存器 (RTC_CR)
位 23 COE:校準輸出使能 (Calibration output enable)
該位使能 RTC_CALIB 輸出
0:禁止校準輸出
1:使能校準輸出
位 22:21 OSEL[1:0]:輸出選擇 (Output selection)
這些位用于選擇要連接到 RTC_ALARM 輸出的標志
00:禁止輸出
01:使能鬧鐘 A 輸出
10:使能鬧鐘 B 輸出
11:使能喚醒輸出
位 20 POL:輸出極性 (Output polarity)
該位用于配置 RTC_ALARM 輸出的極性
0:當 ALRAF/ALRBF/WUTF 置 1 時(取決于 OSEL[1:0]),該引腳為高電平
1:當 ALRAF/ALRBF/WUTF 置 1 時(取決于 OSEL[1:0]),該引腳為低電平
位 19 COSEL:校準輸出選擇 (Calibration output selection)
當 COE=1 時,該位可選擇 RTC_CALIB 上輸出的信號。
0:校準輸出為 512 Hz
1:校準輸出為 1 Hz
在 RTCCLK 為 32.768 kHz 且預分頻器為其默認值(PREDIV_A=127 且 PREDIV_S=255)的條件下,這些頻率有效。
位 18 BKP:備份 (Backup)
用戶可對此位執行寫操作以記錄是否已對夏令時進行更改。
位 17 SUB1H:減少 1 小時(冬季時間更改)(Subtract 1 hour (winter time change))
當該位在初始化模式以外的模式下置 1 時,如果當前小時不是 0,則日歷時間將減少 1 小時。此位始終讀為 0。當前小時為 0 時,將此位置 1 沒有任何作用。
0:無作用。
1:將當前時間減少 1 小時。這可用于冬季時間更改。
位 16 ADD1H:增加 1 小時(夏季時間更改)(Add 1 hour (summer time change))
當該位在初始化模式以外的模式下置 1 時,日歷時間將增加 1 小時。此位始終讀為 0。
0:無作用。
1:將當前時間增加 1 小時。這可用于夏季時間更改
位 15 TSIE:時間戳中斷使能 (Timestamp interrupt enable)
0:禁止時間戳中斷
1:使能時間戳中斷
位 14 WUTIE:使能喚醒定時器使能 (Wakeup timer interrupt enable)
0:禁止喚醒定時器中斷
1:使能喚醒定時器中斷
位 13 ALRBIE: ** 鬧鐘 B 中斷使能 (Alarm B interrupt enable)**
0:鬧鐘 B 中斷禁止
1:鬧鐘 B 中斷使能
位 12 ALRAIE:鬧鐘 A 中斷使能 (Alarm A interrupt enable)
0:禁止鬧鐘 A 中斷
1:使能鬧鐘 A 中斷
位 11 TSE:時間戳使能 (Time stamp enable)
0:禁止時間戳
1:使能時間戳
位 10 WUTE:喚醒定時器使能 (Wakeup timer enable)
0:禁止喚醒定時器
1:使能喚醒定時器
位 9 ALRBE: ** 鬧鐘 B 使能 (Alarm B enable)**
0:禁止鬧鐘 B
1:使能鬧鐘 B
位 8 ALRAE :鬧鐘 A 使能 (Alarm A enable)
0:禁止鬧鐘 A
1:使能鬧鐘 A
位 7 DCE :粗略數字校準使能 (Coarse digital calibration enable)
0:禁止數字校準
1:使能數字校準
PREDIV_A 必須大于或等于 6
位 6 FMT:小時格式 (Hour format)
0:24 小時/天格式
1:AM/PM 小時格式
位 5 BYPSHAD:旁路影子寄存器 (Bypass the shadow registers)
0:日歷值(從 RTC_SSR、RTC_TR 和 RTC_DR 讀取時)取自影子寄存器,該影子寄存器每兩個 RTCCLK 周期更新一次。
1:日歷值(從 RTC_SSR、RTC_TR 和 RTC_DR 讀取時)直接取自日歷計數器。
注意:如果 APB1 時鐘的頻率低于 7 倍的 RTCCLK 頻率,則必須將 BYPSHAD 置“ 1 ”。
位 4 REFCKON: **參考時鐘檢測使能(50 Hz 或 60 Hz)(Reference clock detection enable (50 or **60 Hz))
0:禁止參考時鐘檢測
1:使能參考時鐘檢測
注意:PREDIV_S 必須為 0x00FF 。
位 3 TSEDGE:時間戳事件有效邊沿 (Timestamp event active edge)
0:TIMESTAMP 上升沿生成時間戳事件
1:TIMESTAMP 下降沿生成時間戳事件
TSEDGE 發生更改時,必須復位 TSE 以避免將 TSF 意外置 1
位 2:0 WUCKSEL[2:0]:喚醒時鐘選擇 (Wakeup clock selection)
000:選擇 RTC/16 時鐘
001:選擇 RTC/8 時鐘
010:選擇 RTC/4 時鐘
011:選擇 RTC/2 時鐘
10x:選擇 ck_spre 時鐘(通常為 1 Hz)
11x:選擇 ck_spre 時鐘(通常為 1 Hz)并將 WUT 計數器值增加 216
RTC 初始化和狀態寄存器 (RTC_ISR)
位 16 RECALPF:重新校準掛起標志 (Recalibration pending Flag)
當軟件對 RTC_CALR 寄存器執行寫操作時,RECALPF 狀態標志將自動置“1”,指示RTC_CALR 寄存器已屏蔽。當采用新的校準設置時,該位恢復為“0”。
位 14 TAMP2F:TAMPER2 檢測標志 (TAMPER2 detection flag)
在入侵輸入 2 上檢測到入侵檢測事件時,由硬件將此標志置 1。
該標志由軟件寫零清除。
位 13 TAMP1F:入侵檢測標志 (Tamper detection flag)
當檢測到入侵檢測事件時,由硬件將此標志置 1。
該標志由軟件寫零清除。
位 12 TSOVF:時間戳溢出標志 (Timestamp overflow flag)
當在 TSF 已置 1 的情況下發生時間戳事件時,由硬件將此標志置 1。
該標志由軟件寫零清除。建議僅在 TSF 位清零之后再檢查并清TSOVF 位。否則,如果時間戳事件恰好在清零 TSF 位之前剛剛發生,則溢出事件可能會被漏掉。
位 11 TSF:時間戳標志 (Timestamp flag)
發生時間戳事件時,由硬件將此標志置 1。
該標志由軟件寫零清除。
位 10 WUTF:喚醒定時器標志 (Wakeup timer flag)
當喚醒自動重載計數器計數到 0 時,由硬件將此標志置 1。
該標志由軟件寫零清除。
軟件必須在 WUTF 再次置 1 的 1.5 個 RTCCLK 周期之前將該標志清零。
位 9 ALRBF:鬧鐘 B 標志 (Alarm B flag)
當時間/日期寄存器(RTC_TR 和 RTC_DR)與鬧鐘 B 寄存器 (RTC_ALRMBR) 匹配時,由硬件將該標志置 1。該標志由軟件寫零清除。
位 8 ALRAF:鬧鐘 A 標志 (Alarm A flag)
當時間/日期寄存器(RTC_TR 和 RTC_DR)與鬧鐘 A 寄存器 (RTC_ALRMAR) 匹配時,由
硬件將該標志置 1。
該標志由軟件寫零清除。
位 7 INIT:初始化模式 (Initialization mode)
0:自由運行模式。
1:初始化模式,用于編程時間和日期寄存器(RTC_TR 和 RTC_DR)以及預分頻器寄存器(RTC_PRER)。計數器停止計數,當 INIT 被復位后,計數器從新值開始計數。
位 6 INITF:初始化標志 (Initialization flag)
當此位置 1 時,RTC 處于初始化狀態,此時可更新事件、日期和預分頻器寄存器。
0:不允許更新日歷寄存器。
1:允許更新日歷寄存器。
位 5 RSF:寄存器同步標志 (Registers synchronization flag)
每次將日歷寄存器的值復制到影子寄存器(RTC_SSRx、RTC_TRx 和 RTC_DRx)時,都會由硬件將此位置 1。在初始化模式下、平移操作掛起時 (SHPF=1) 或在旁路影子寄存器模式 (BYPSHAD=1) 下,該位由硬件清零。該位還可由軟件清零。
0:日歷影子寄存器尚未同步
1:日歷影子寄存器已同步
位 4 INITS:初始化狀態標志 (Initialization status flag)
當日歷年份字段不為 0 時(上電復位狀態),由硬件將該位置 1。
0:日歷尚未初始化
1:日歷已經初始化
位 3 SHPF:平移操作掛起 (Shift operation pending)
0:沒有平移操作掛起
1:某個平移操作掛起
只要通過對 RTC_SHIFTR 寄存器執行寫操作來啟動平移操作,此標志便由硬件置 1。執行完相應的平移操作后,此標志由硬件清零。對 SHPF 執行寫入操作不起作用。
位 2 WUTWF:喚醒定時器寫標志 (Wakeup timer write flag)
在 RTC_CR 寄存器中的 WUTE 位置 0 后,當喚醒定時器值可更改時,由硬件將該位置 1。
0:不允許更新喚醒定時器配置
1:允許更新喚醒定時器配置
位 1 ALRBWF:鬧鐘 B 寫標志 (Alarm B write flag)
在 RTC_CR 寄存器中的 ALRBIE 位置 0 之后,當鬧鐘 B 的值可更改時,由硬件將該位置 1。該位在初始化模式下由硬件清零。
0:不允許更新鬧鐘 B
1:允許更新鬧鐘 B
位 0 ALRAWF:鬧鐘 A 寫標志 (Alarm A write flag)
在 RTC_CR 寄存器中的 ALRAE 位置 0 后,當鬧鐘 A 的值可更改時,由硬件將該位置 1。
該位在初始化模式下由硬件清零。
0:不允許更新鬧鐘 A
1:允許更新鬧鐘 A
RTC 預分頻器寄存器 (RTC_PRER)
預分頻器寄存器復位值剛好使時鐘頻率為1Hz,滿足RTC的需求,所以這里不對其進行配置。
RTC初始化程序如下:
#include "RTC.h"
#include "stm32f4xx.h"
void RTC_Init(u8 hour,u8 fen,u8 miao,u8 nian,u8 yue,u8 ri,u8 xingqi)
{
u32 temp = 0;
RCC- >APB1ENR |= 1< 28; //開電源管理模塊時鐘
PWR- >CR |= 1< 8; //解除保護
RCC- >BDCR &=~ (1< 2); //調試模式下不旁路LSE
RCC- >BDCR |= 1< 0; //開啟LSE振蕩器
while(!(RCC- >BDCR & 1< 1));
RCC- >BDCR &=~ (0x3< 8);
RCC- >BDCR |= 1< 8; //選擇LSE為RTC時鐘源
RCC- >BDCR |= 1< 15; //使能RTC模塊
RTC- >WPR = 0xCA; //解除寫保護
RTC- >WPR = 0x53; //解除寫保護
RTC- >ISR |= 1< 7; //INIT位置1
while((RTC- >ISR & (1< 6))==0); //等待進入初始化模式
temp |= (hour/10)< 20 | (hour%10)< 16 | (fen/10)< 12 | (fen%10)< 8 | (miao/10)< 4 | (miao%10);
RTC- >TR = temp;
temp = 0;
temp |= (nian/10)< 20 | (nian%10)< 16 | (xingqi)< 13 | (yue/10)< 12 | (yue%10)< 8 | (ri/10)< 4 | (ri%10);
RTC- >DR = temp;
RTC- >CR = 0;
RTC- >ISR &=~(1< 7); //退出初始化模式
RTC- >WPR = 0; //寫任意值,再次保護
}
編寫主函數測試:
#include "stm32f4xx.h"
#include "usart.h"
#include "delay.h"
#include "stdio.h"
#include "RTC.h"
typedef struct
{
u8 shi;
u8 fen;
u8 miao;
u8 nian;
u8 yue;
u8 ri;
u8 xingqi;
}TIME_Typedef;
TIME_Typedef time = {1};
int main()
{
Usart1_Init(115200);
RTC_Init(23,59,50,19,7,9,2);
while(1)
{
time.shi = ((RTC- >TR & 0x300000) >>20)*10 + ((RTC- >TR & 0xf0000) >>16);
time.fen = ((RTC- >TR & 0x7000) >>12)*10 + ((RTC- >TR & 0xf00) >>8);
time.miao = ((RTC- >TR & 0x70) >>4)*10 + (RTC- >TR & 0xf);
printf("%d:%d:%drn",time.shi,time.fen,time.miao);
Delay_ms(1000);
}
}
運行后可以看到串口輸出了設置的時分秒計數,時間不會出錯,RTC實時時鐘測試成功。
但是在系統復位后,發現又重新從剛開始設的時間計時,這顯然不是我們想要的,所以在這里再添加備份域的讀寫函數。
RTC 備份寄存器 (RTC_BKPxR)
RTC的備份域是在RTC基地址上偏移了0x50開始到偏移0x9c的范圍。
//備份域
//注意:備份域寄存器也受DBP位保護,在未初始化RTC模塊的條件下,如果要使用備份域,
//需單獨開啟DBP位
//num:0~19
void RTC_WriteBKPxR(u8 num,u32 dat)
{
u32 add = 0;
num %= 20;
add = RTC_BASE + 0x50 + 4*num;
*((volatile u32 *)add) = dat;
}
u32 RTC_ReadBKPxR(u8 num)
{
u32 add = 0;
num %= 20;
add = RTC_BASE + 0x50 + 4*num;
add = *((volatile u32 *)add);
return add;
}
然后再在初始化函數中調用讀取備份域函數,判斷是否已經設置過時間,如果第一次設時間就寫備份域的標記,再設置時間;不是第一次就直接開啟計時。初始化函數更改如下:
void RTC_Init(u8 hour,u8 fen,u8 miao,u8 nian,u8 yue,u8 ri,u8 xingqi)
{
u32 temp = 0;
RCC- >APB1ENR |= 1< 28; //開電源管理模塊時鐘
PWR- >CR |= 1< 8; //解除保護
RCC- >BDCR &=~ (1< 2); //調試模式下不旁路LSE
RCC- >BDCR |= 1< 0; //開啟LSE振蕩器
while(!(RCC- >BDCR & 1< 1));
RCC- >BDCR &=~ (0x3< 8);
RCC- >BDCR |= 1< 8; //選擇LSE為RTC時鐘源
RCC- >BDCR |= 1< 15; //使能RTC模塊
RTC- >WPR = 0xCA; //解除寫保護
RTC- >WPR = 0x53; //解除寫保護
RTC- >ISR |= 1< 7; //INIT位置1
while((RTC- >ISR & (1< 6))==0); //等待進入初始化模式
temp = RTC_ReadBKPxR(0);
if(temp != 0xaa)
{
RTC_WriteBKPxR(0,0xaa);
temp = 0;
temp |= (hour/10)< 20 | (hour%10)< 16 | (fen/10)< 12 | (fen%10)< 8 | (miao/10)< 4 | (miao%10);
RTC- >TR = temp;
temp = 0;
temp |= (nian/10)< 20 | (nian%10)< 16 | (xingqi)< 13 | (yue/10)< 12 | (yue%10)< 8 | (ri/10)< 4 | (ri%10);
RTC- >DR = temp;
}
RTC- >CR = 0;
RTC- >ISR &=~(1< 7); //退出初始化模式
RTC- >WPR = 0; //寫任意值,再次保護
}
主函數依舊不變,運行程序發現系統復位后,時間是繼續復位之前的計時,不會再被重新設置,所以在用RTC時加上備份域就可以防止系統復位造成計時不理想。
-
控制器
+關注
關注
114文章
16918瀏覽量
182652 -
EEPROM
+關注
關注
9文章
1079瀏覽量
83173 -
RTC
+關注
關注
2文章
605瀏覽量
68209 -
STM32F4
+關注
關注
3文章
194瀏覽量
28785 -
STM32處理器
+關注
關注
0文章
5瀏覽量
1191
發布評論請先 登錄
stm32f4 RTC實時時鐘解析

STM32CubeMX系列|RTC實時時鐘

評論