一、STM32F1 RTC介紹
1.1 RTC簡介
STM32 的實時時鍾( RTC)是一個獨立的定時器。 STM32 的 RTC 模 塊擁有一組連續計數的計數器,在相應軟件配置下,可提供時鍾日歷的 功能。修改計數器的值可以重新設置系統當前的時間和日期。 RTC模塊和時鍾配置是在后備區域,無論器件狀態如何(運行模式、 低功耗模式或處於復位狀態),只要保證后備區域供電正常,RTC便不會 停止工作,所以通常會在后備區域供電端加一個紐扣電池,即使主電源 停止供電,后備電源也會啟動供電,從而保證RTC時鍾不停的運行,只有 當主電源和后備紐扣電池都沒有電的時,RTC才停止工作。 從 RTC 的定時器特性來說,它是一個 32 位的計數器,只能向上計 數。它的時鍾來源有三種,分別為高速外部時鍾的 128 分頻( HSE/128 )、 低速內部時鍾 LSI 以及低速外部時鍾 LSE。
1.2電源
1.3備份寄存器(BKP)簡介
1.4實時時鍾(RTC)
二、功能描述
1、概述

2、復位過程
3、讀RTC寄存器
4、寫RTC寄存器
必須設置RTC_CRL寄存器中的CNF位,使RTC進入配置模式后,才能寫入RTC_PRL、RTC_CNT、RTC_ALR寄存器。
另外,對RTC任何寄存器的寫操作,都必須在前一次寫操作結束后進行。可以通過查詢RTC_CR寄存器中的RTOFF狀態位,判斷RTC寄存器是否處於更新中。僅當RTOFF狀態位是1時,才可以寫入RTC寄存器。
三、STM32F1 RTC配置步驟
- 使能PWR和BKP時鍾。調用函數:RCC_APB1PeriphClockCmd();
- 使能后備寄存器訪問。調用函數:PWR_BackupAccessCmd();
- 配置RTC時鍾源,使能RTC時鍾。調用函數:RCC_RTCCLKConfig();RCC_RTCCLKCmd();
- 如果使用LSE,要打開LSE:RCC_LSEConfig(RCC_LSE_ON);
- 設置RTC預分頻系數。調用函數:RTC_SetPrescaler();
- 設置時間。調用函數:RTC_SetCounter();
- 開啟相關中斷(如果需要)。調用函數:RTC_ITConfig();
- 編寫中斷服務函數。調用函數:RTC_IRQHandler();
- 部分操作要等待寫操作完成和同步。調用函數:RTC_WaitForLastTask();RTC_WaitForSynchro();
四、程序舉例
編寫RTC控制程序 本章所要實現的功能是:設置RTC時間日期初值,在RTC秒中斷內使用 串口打印出RTC日期和時間,D1指示燈閃爍提示系統運行。
程序框架如下 :
(1)初始化RTC,設置RTC時間日期初值 (2)開啟RTC的秒中斷,編寫RTC中斷函數, (3)在RTC中斷內更新時間並打印輸出 (4)編寫主函數
1 #ifndef _rtc_H 2 #define _rtc_H
3
4 #include "system.h"
5
6
7 u8 RTCx_Init(void); 8 void RTC_GET(void); 9
10 typedef struct
11 { 12 u8 hour; 13 u8 min; 14 u8 sec; 15 }_calender; 16
17 extern _calender calender; 18
19
20
21 #endif
分析RTC_Init()函數:RTC初始化函數。
初始化時按照之前的RTC一般步驟進行配置,這里需要注意的是,為了區分是否是第一次執行RTC_Init()函數,必須判斷后配寄存器中是否寫如果某個值(向BKP_DR1寄存器寫入0xA0A0,寫入其他的數字也可以)如果寫入不用再初始化。
為什么要區分是否執行過RTC_Init?
如果由於 斷電/ 復位/喚醒等待 等因素,程序中斷但RTC時鍾以及后備寄存器區域還在執行;等恢復供電重新啟動程序時,這不能再對RTC時鍾進行初始化,否則一直初始化,那么RTC作為時鍾就沒什么實際作用。
1 if (BKP_ReadBackupRegister(BKP_DR1) != 0xA0A0//(從指定的后備寄存器中讀出數據)判斷是否初始化過
2 { 3 //第一次進行初始化(RTC_Init)
4 BKP_WriteBackupRegister(BKP_DR1, 0XA0A0); //向指定的后備寄存器中寫入用戶程序數據
5 } 6 else//(已經初始化過)系統繼續計時
7 { 8 //不是第一次進行初始化(RTC_Init)
9 }
代碼44:使用外部低速晶振(LSE)時需要檢查指定的RCC相應的標志位是否設置,等待低速晶振就緒。
1 #include "rtc.h" 2 #include "systick.h" 3 #include "ustrt.h" 4 5 6 _calender calender; 7 8 9 void RTC_NVIC_Config() //設置RTC中斷優先級 10 { 11 NVIC_InitTypeDef NVIC_InitStruct; 12 13 NVIC_InitStruct.NVIC_IRQChannel=RTC_IRQn; 14 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2; 15 NVIC_InitStruct.NVIC_IRQChannelSubPriority=3; 16 NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE ; 17 NVIC_Init(&NVIC_InitStruct); 18 19 } 20 21 void RTC_GET() //獲取 RTC 計數器的值並進行處理 22 { 23 u32 timedata; 24 timedata=RTC_GetCounter(); 25 calender.hour=timedata/3600; 26 calender.min=timedata%3600/60; 27 calender.sec=timedata%3600%60; 28 } 29 30 //返回0:初始化失敗 31 //返回1:初始化成功 32 u8 RTCx_Init() 33 { 34 u8 time; 35 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); 36 RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE); 37 PWR_BackupAccessCmd(ENABLE); 38 39 40 if(BKP_ReadBackupRegister(BKP_DR1)!=0xA0a0) //從指定的后備寄存器讀數據)檢查是不是第一次配置時鍾 41 { 42 BKP_DeInit(); //將后備寄存器初始化 43 RCC_LSEConfig(RCC_LSE_ON); //將RCC_LSE時鍾開啟 44 while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET && time<250) //檢測LSE時鍾是否開啟 45 { 46 time++; 47 delay_ms(10); 48 } 49 if(time>=250) 50 { 51 return 1; 52 } 53 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //配置RTC的時鍾為LSE 54 RCC_RTCCLKCmd(ENABLE); //RTC時鍾輸入開啟 55 RTC_WaitForLastTask(); //等待直到RTC寄存器上的上一次寫操作完成。 56 RTC_WaitForSynchro(); //等待,直到RTC寄存器(RTC_CNT、RTC_ALR和RTC_PRL)與RTC APB時鍾同步。 57 RTC_ITConfig(RTC_IT_SEC, ENABLE); 58 RTC_WaitForLastTask(); //等待直到RTC寄存器上的上一次寫操作完成。 59 RTC_EnterConfigMode(); // 允許配置 60 RTC_SetPrescaler(32767); //設置 RTC 預分頻的值 61 RTC_WaitForLastTask(); //等待直到RTC寄存器上的上一次寫操作完成。 62 RTC_SetCounter(0x1111); //設置 RTC 計數器的值 初始化時間17:34:55 63 RTC_ExitConfigMode(); //退出 RTC 配置模式 64 BKP_WriteBackupRegister(BKP_DR1,0xA0a0); //向指定的后備寄存器中寫入用戶程序數據 65 66 } 67 else //(系統之前已經進行過相應初始化)系統繼續計時 68 { 69 RTC_WaitForLastTask(); //等待直到RTC寄存器上的上一次寫操作完成。 70 RTC_WaitForSynchro(); //等待,直到RTC寄存器(RTC_CNT、RTC_ALR和RTC_PRL)與RTC APB時鍾同步。 71 RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能或者失能指定的 RTC 中斷 72 } 73 74 RTC_NVIC_Config(); //RCT中斷優先級別設置 75 RTC_GET(); //獲取 RTC 計數器的值 76 return 0; 77 } 78 79 void RTC_IRQHandler(void) //RTC中斷函數 80 { 81 if(RTC_GetITStatus(RTC_IT_SEC)!=0) //檢查指定的 RTC 中斷發生與否(秒中斷) 82 { 83 RTC_GET(); 84 printf("RTC_Time:%d:%d:%d\r\n",calender.hour,calender.min,calender.sec); 85 } 86 RTC_ClearITPendingBit(RTC_IT_SEC); //清除 RTC 的中斷待處理位 87 }
1 #include "system.h"
2 #include "led.h"
3 #include "systick.h"
4 #include "ustrt.h"
5 #include "rtc.h"
6
7 int main() 8 { 9 u8 i=0; 10
11
12 SysTick_Init(72); 13 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 14 LED_Init(); 15 ustrt_Init(9600); 16 RTCx_Init(); 17
18 while(1) 19 { 20
21 i++; 22 if(i%20==0) 23 { 24 led1=!led1; 25 } 26 delay_ms(10); 27 } 28 }