目錄
- 一、RTC簡介
- 1、RTC含義
- 2、RTC特徵
- 3、RTC原理框圖
- 3、RTC具體流程
- 4、 RTC時鐘選擇
- 5、RTC復位過程
- 6、RTC中斷
- 二、STM32CubeMX配置RTC
- 1、配置RCC
- 2、配置SYS
- 3、 配置RTC
- 4、配置串口
- 5、配置時鐘
- 6、生成項目
- 三、KEIL配置代碼
- 1、printf函數
- 2、RTC_HAL庫函數
- 3、定義結構體
- 4、循環添加
- 四、實驗總結
- 五、實驗參考
一、RTC簡介
1、RTC含義
RTC (Real Time Clock):實時時鐘
RTC是個獨立的定時器。
RTC模塊擁有一個連續計數的計數器,在相應的軟件配置下,可以提供時鐘日曆的功能。修改計數器的值可以重新設置當前時間和日期 RTC還包含用於管理低功耗模式的自動喚醒單元。
在斷電情況下 RTC仍可以獨立運行 只要芯片的備用電源一直供電,RTC上的時間會一直走。
RTC實質是一個掉電後還繼續運行的定時器,從定時器的角度來看,相對於通用定時器TIM外設,它的功能十分簡單,只有計時功能(也可以觸發中斷)。但其高級之處也就在於掉電之後還可以正常運行。
兩個 32 位寄存器包含二進碼十進數格式 (BCD) 的秒、分鐘、小時( 12 或 24 小時制)、星期幾、日期、月份和年份。此外,還可提供二進制格式的亞秒值。系統可以自動將月份的天數補償為 28、29(閏年)、30 和 31 天。
上電覆位後,所有RTC寄存器都會受到保護,以防止可能的非正常寫訪問。
無論器件狀態如何(運行模式、低功耗模式或處於復位狀態),只要電源電壓保持在工作範圍內,RTC使不會停止工作。
2、RTC特徵
- 可編程的預分頻係數:分頻係數高為220。
- 32位的可編程計數器,可用於較長時間段的測量。
- 2個分離的時鐘:用於APB1接口的PCLK1和RTC時鐘(RTC時鐘的頻率必須小於PCLK1時鐘 頻率的四分之一以上)。
- 可以選擇以下三種RTC的時鐘源:
HSE時鐘除以128;
LSE振盪器時鐘;
LSI振盪器時鐘 - 2個獨立的復位類型:
APB1接口由系統復位;
RTC核心(預分頻器、鬧鐘、計數器和分頻器)只能由後備域復位 - 3個專門的可屏蔽中斷:
鬧鐘中斷,用來產生一個軟件可編程的鬧鐘中斷。
秒中斷,用來產生一個可編程的週期性中斷信號(長可達1秒)。
溢出中斷,指示內部可編程計數器溢出並回轉為0的狀態.
RTC時鐘源:
三種不同的時鐘源可被用來驅動系統時鐘(SYSCLK):
● HSI振盪器時鐘
● HSE振盪器時鐘
● PLL時鐘
這些設備有以下2種二級時鐘源:
● 40kHz低速內部RC,可以用於驅動獨立看門狗和通過程序選擇驅動RTC。 RTC用於從停機/待機模式下自動喚醒系統。
● 32.768kHz低速外部晶體也可用來通過程序選擇驅動RTC(RTCCLK)。
3、RTC原理框圖
RTC時鐘的框圖還是比較簡單的,這裏我們把他分成 兩個部分:
APB1 接口:用來和 APB1 總線相連。 此單元還包含一組 16 位寄存器,可通過 APB1 總線對其進行讀寫操作。APB1 接口由 APB1 總 線時鐘驅動,用來與 APB1 總線連接。
通過APB1接口可以訪問RTC的相關寄存器(預分頻值,計數器值,鬧鐘值)。
RTC 核心接口:由一組可編程計數器組成,分成 兩個主要模塊 。
第一個模塊是 RTC 的 預分頻模塊,它可編程產生 1 秒的 RTC 時間基準 TR_CLK。RTC 的預分頻模塊包含了一個 20 位的可編程分頻器(RTC 預分頻器)。如果在 RTC_CR 寄存器中設置了相應的允許位,則在每個 TR_CLK 週期中 RTC 產生一箇中斷(秒中斷)。
第二個模塊是一個 32 位的可編程計數器 (RTC_CNT),可被初始化為當前的系統時間,一個 32 位的時鐘計數器,按秒鐘計算,可以記 錄 4294967296 秒,約合 136 年左右,作為一般應用,這已經是足夠了的。
3、RTC具體流程
RTCCLK經過RTC_DIV預分頻,RTC_PRL設置預分頻係數,然後得到TR_CLK時鐘信號,我們一般設置其週期為1s,RTC_CNT計數器計數,假如1970設置為時間起點為0s,通過當前時間的秒數計算得到當前的時間。RTC_ALR是設置鬧鐘時間,RTC_CNT計數到RTC_ALR就會產生計數中斷,
- RTC_Second為秒中斷,用於刷新時間,
- RTC_Overflow是溢出中斷。
- RTC Alarm 控制開關機
4、 RTC時鐘選擇
使用HSE分頻時鐘或者LSI的時候,在主電源VDD掉電的情況下,這兩個時鐘來源都會受到影響,因此沒法保證RTC正常工作.所以RTC一般都時鐘低速外部時鐘LSE,頻率為實時時鐘模塊中常用的32.768KHz,因為32768 = 2^15,分頻容易實現,所以被廣泛應用到RTC模塊.(在主電源VDD有效的情況下(待機),RTC還可以配置鬧鐘事件使STM32退出待機模式).
5、RTC復位過程
除了RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器外,所有的系統寄存器都由系統復位或電源復位進行異步復位。
RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器僅能通過備份域復位信號復位。
系統復位後,禁止訪問後備寄存器和RCT,防止對後衞區域(BKP)的意外寫操作
6、RTC中斷
秒中斷:
這裏時鐘自帶一個秒中斷,每當計數加一的時候就會觸發一次秒中斷。注意,這裏所説的秒中斷並非一定是一秒的時間,它是由RTC時鐘源和分頻值決定的“秒”的時間,當然也是可以做到1秒鐘中斷一次。我們通過往秒中斷裏寫更新時間的函數來達到時間同步的效果
鬧鐘中斷:
鬧鐘中斷就是設置一個預設定的值,計數每自加多少次觸發一次鬧鐘中斷
二、STM32CubeMX配置RTC
1、配置RCC
- 設置高速外部時鐘HSE 選擇外部時鐘源
- 使能外部晶振LSE
RTC設備因為其獨特的運行方式(即掉電依舊運行)使用HSE分頻時鐘或者LSI的時候,在主電源VDD掉電的情況下,這兩個時鐘來源都會受到影響,資源消耗太大,小小的鈕釦電池根本吃不消。沒法保證RTC正常工作.所以RTC一般都時鐘低速外部時鐘LSE
2、配置SYS
3、 配置RTC
- Activate Clock Source 激活時鐘源
- Activate calendar激活日曆
這兩個都要點,作用也很明顯,先是使能時鐘源,再使能RTC日曆
- RTC_OUT: Not RTC_OUT
- Tamper: ×
第一個:是否使能 tamper(PC13)引腳上輸出校正的秒脈衝時鐘
第二個: RTC入侵檢測校驗功能
RTC校驗功能,使能侵入檢測功能。RTC時鐘經64分頻輸出到侵入檢測引腳TAMPER上
當 TAMPER引腳上的信號從 0變成1或者從 1變成 0(取決於備份控制寄存器BKP_CR的 TPAL位),會產生一個侵入檢測事件。侵入檢測事件將所有數據備份寄存器內容清除。
第一個是使能tamper(PC13)引腳作為時鐘脈衝輸出
第二個是使能tamper(PC13)引腳作為入侵檢測功能
RTC的中斷:
RTC全局中斷RTC_IRQHandler()
此處設置時間為2022/10/29 21:45:00
Data Format: 日期格式
Binary data format 十六進制
BCD data format BCD碼進制
使用自動配置,初始化時間必須使用BCD data format,原因是庫函數存在bug,如果使用Binary data format,月份配置會出錯,比如説11月,配置時會賦值為RTC_MONTH_NOVEMBER,而此宏定義值為0x11,也就是説其十進制值為17
Hours: 小時
Minutes: 分鐘
Seconds: 秒
Week Day: 星期
Month 月份
Date: 日期
Year: 年份
4、配置串口
5、配置時鐘
6、生成項目
三、KEIL配置代碼
1、printf函數
在main.c和usart.c中添加頭文件#include "stdio.h"之後,勾選Target中的use MicroLIB,在mian.c文件中,添加如下代碼,進行重定義
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
2、RTC_HAL庫函數
/*設置系統時間*/
HAL_StatusTypeDef HAL_RTC_SetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format)
/*讀取系統時間*/
HAL_StatusTypeDef HAL_RTC_GetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format)
/*設置系統日期*/
HAL_StatusTypeDef HAL_RTC_SetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format)
/*讀取系統日期*/
HAL_StatusTypeDef HAL_RTC_GetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format)
/*啓動報警功能*/
HAL_StatusTypeDef HAL_RTC_SetAlarm(RTC_HandleTypeDef *hrtc, RTC_AlarmTypeDef *sAlarm, uint32_t Format)
/*設置報警中斷*/
HAL_StatusTypeDef HAL_RTC_SetAlarm_IT(RTC_HandleTypeDef *hrtc, RTC_AlarmTypeDef *sAlarm, uint32_t Format)
/*報警時間回調函數*/
__weak void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
/*寫入後備儲存器*/
void HAL_RTCEx_BKUPWrite(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister, uint32_t Data)
/*讀取後備儲存器*/
uint32_t HAL_RTCEx_BKUPRead(RTC_HandleTypeDef *hrtc, uint32_t BackupRegister
前四個函數:
設置系統時間:HAL_RTC_SetTime();
讀取系統時間: HAL_RTC_GetTime();
設置系統日期: HAL_RTC_SetDate();
讀取系統日期: HAL_RTC_GetDate();
系統的時間和日期開始的時候已經設置 所以我們這裏只用兩個讀取函數
讀取系統時間函數:
/*讀取系統時間*/
HAL_StatusTypeDef HAL_RTC_GetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format)
功能: 獲取RTC時鐘的時間
參數:
- *hrtc RTC結構體參數 例:&hi2c2
- RTC_TimeTypeDef *sTime: 獲取RTC時間的結構體
- Format: 獲取時間的格式
RTC_FORMAT_BIN 使用16進制
RTC_FORMAT_BCD 使用BCD進制
讀取系統日期函數:
/*讀取系統日期*/
HAL_StatusTypeDef HAL_RTC_GetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format)
功能: 獲取RTC時鐘的日期
參數:
- *hrtc RTC結構體參數 例:&hi2c2
- RTC_DateTypeDef *sTime: 獲取RTC日期的結構體
- Format: 獲取日期的格式
RTC_FORMAT_BIN 使用16進制
RTC_FORMAT_BCD 使用BCD進制
在stm32f1xx_hal_rtc.h頭文件中,可以找到RTC_TimeTypeDef,RTC_DateTypeDef這兩個結構體的成員變量。
/**
* @brief RTC Time structure definition
*/
typedef struct
{
uint8_t Hours; /*!< Specifies the RTC Time Hour.
This parameter must be a number between Min_Data = 0 and Max_Data = 23 */
uint8_t Minutes; /*!< Specifies the RTC Time Minutes.
This parameter must be a number between Min_Data = 0 and Max_Data = 59 */
uint8_t Seconds; /*!< Specifies the RTC Time Seconds.
This parameter must be a number between Min_Data = 0 and Max_Data = 59 */
} RTC_TimeTypeDef;
/**
* @brief RTC Date structure definition
*/
typedef struct
{
uint8_t WeekDay; /*!< Specifies the RTC Date WeekDay (not necessary for HAL_RTC_SetDate).
This parameter can be a value of @ref RTC_WeekDay_Definitions */
uint8_t Month; /*!< Specifies the RTC Date Month (in BCD format).
This parameter can be a value of @ref RTC_Month_Date_Definitions */
uint8_t Date; /*!< Specifies the RTC Date.
This parameter must be a number between Min_Data = 1 and Max_Data = 31 */
uint8_t Year; /*!< Specifies the RTC Date Year.
This parameter must be a number between Min_Data = 0 and Max_Data = 99 */
} RTC_DateTypeDef;
3、定義結構體
通過定義結構體來獲取時間與日期
mian.c裏定義結構體:
RTC_DateTypeDef GetData; //獲取日期結構體
RTC_TimeTypeDef GetTime; //獲取時間結構體
4、循環添加
在while循環裏添加代碼:
(1)添加循環生成時間
/* Get the RTC current Time */
HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);
/* Get the RTC current Date */
HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN);
/* Display date Format : yy/mm/dd */
printf("%02d/%02d/%02d\r\n",2000 + GetData.Year, GetData.Month, GetData.Date);
/* Display time Format : hh:mm:ss */
printf("%02d:%02d:%02d\r\n",GetTime.Hours, GetTime.Minutes, GetTime.Seconds);
printf("\r\n");
HAL_Delay(1000);
運行結果:
(2)修改循環加上星期
HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);//獲取時間
/* Get the RTC current Date */
HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN);//獲取日期
/* Display date Format : yy/mm/dd */
printf("%02d/%02d/%02d\r\n",2000 + GetData.Year, GetData.Month, GetData.Date);
/* Display date Format : weekday */
if(GetData.WeekDay==1){
printf("星期一\r\n");
}else if(GetData.WeekDay==2){
printf("星期二\r\n");
}else if(GetData.WeekDay==3){
printf("星期三\r\n");
}else if(GetData.WeekDay==4){
printf("星期四\r\n");
}else if(GetData.WeekDay==5){
printf("星期五\r\n");
}else if(GetData.WeekDay==6){
printf("星期六\r\n");
}else if(GetData.WeekDay==7){
printf("星期日\r\n");
}
/* Display time Format : hh:mm:ss */
printf("%02d:%02d:%02d\r\n",GetTime.Hours, GetTime.Minutes, GetTime.Seconds);
printf("\r\n");
HAL_Delay(1000);
運行結果:
四、實驗總結
本次實驗實現了通過RTC實現時間和星期的串口輸出,瞭解到相關RTC的深層含義,進一步加深了對RTC的理解