(stm32f103學習總結)—RTC獨立定時器—實時時鍾實驗


一、STM32F1 RTC介紹

1.1 RTC簡介

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

1.2電源

電池備份區域
使用電池或其他電源連接到VBAT腳上,當VDD斷電時,可以保存備份寄存器的內容和維持RTC的
功能。
VBAT腳也為RTC、LSE振盪器和PC13至PC15供電,這保證當主要電源被切斷時RTC能繼續工作。切換到VBAT供電由復位模塊中的掉電復位功能控制。
如果應用中沒有使用外部電池,VBAT必須連接到VDD引腳上。
 

1.3備份寄存器(BKP)簡介

  備份寄存器是42個16位的寄存器,可用來存儲84個字節的用戶應用程序數據。他們處在備份域里,當VDD電源被切斷,他們仍然由VBAT維持供電。當系統在待機模式下被喚醒,或系統復位或電源復位時,他們也不會被復位。
此外,BKP控制寄存器用來管理侵入檢測和RTC校准功能。
復位后,對備份寄存器和RTC的訪問被禁止,並且備份域被保護以防止可能存在的意外的寫操作。執行以下操作可以使能對備份寄存器和RTC的訪問。
  ● 通過設置寄存器RCC_APB1ENR的PWREN和BKPEN位來打開電源和后備接口的時鍾
  ● 電源控制寄存器(PWR_CR)的DBP位來使能對后備寄存器和RTC的訪問。
 

1.4實時時鍾(RTC) 

RTC簡介
  實時時鍾是一個獨立的定時器。RTC模塊擁有一組連續計數的計數器,在相應軟件配置下,可提供時鍾日歷的功能。修改計數器的值可以重新設置系統當前的時間和日期。
  RTC模塊和時鍾配置系統(RCC_BDCR寄存器)處於后備區域,即在系統復位或從待機模式喚醒后,RTC的設置和時間維持不變。
  系統復位后,對后備寄存器和RTC的訪問被禁止,這是為了防止對后備區域(BKP)的意外寫操作。執行以下操作將使能對后備寄存器和RTC的訪問:(BKP中也提到過)
  ● 設置寄存器RCC_APB1ENR的PWREN和BKPEN位,使能電源和后備接口時鍾
  ● 設置寄存器PWR_CR的DBP位,使能對后備寄存器和RTC的訪問。 
 

二、功能描述

1、概述

  RTC由兩個主要部分組成(參見下圖)。第一部分(APB1接口)用來和APB1總線相連。此單元還包含一組16位寄存器,可通過APB1總線對其進行讀寫操作(參見16.4節)。APB1接口由APB1總線時鍾驅動,用來與APB1總線接口。
  另一部分(RTC核心)由一組可編程計數器組成,分成兩個主要模塊。
  第一個模塊是RTC的預分頻模塊,它可編程產生最長為1秒的RTC時間基准TR_CLK。RTC的預分頻模塊包含了一個20位的可編程分頻器(RTC預分頻器)。如果在RTC_CR寄存器中設置了相應的允許位,則在每個實時時鍾(RTC)TR_CLK周期中RTC產生一個中斷(秒中斷)。
  第二個模塊是一個32位的可編程計數器,可被初始化為當前的系統時間。系統時間按TR_CLK周期累加並與存儲在RTC_ALR寄存器中的可編程時間相比較,如果RTC_CR控制寄存器中設置了相應允許位,比較匹配時將產生一個鬧鍾中斷。
 

2、復位過程

  除了RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器外,所有的系統寄存器都由系統復位或電源復位進行異步復位。
  RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器僅能通過備份域復位信號復位。

3、讀RTC寄存器

RTC核完全獨立於RTC APB1接口。
軟件通過APB1接口訪問RTC的預分頻值、計數器值和鬧鍾值。但是,相關的可讀寄存器只在與RTC與 APB1時鍾進行重新同步的RTC時鍾的上升沿被更新RTC標志也是如此的。這意味着,如果APB1接口曾經被關閉,而讀操作又是在剛剛重新開啟APB1之后,則在第一次的內部寄存器更新之前,從APB1上讀出的RTC寄存器數值可能被破壞了(通常讀到0)。下述幾種情況下能夠發生這種情形:
● 發生系統復位或電源復位
● 系統剛從待機模式喚醒(參見第4.3節:低功耗模式)。
● 系統剛從停機模式喚醒(參見第4.3節:低功耗模式)。
所有以上情況中,APB1接口被禁止時(復位、無時鍾或斷電)RTC核仍保持運行狀態。
因此,若在讀取RTC寄存器時,RTC的APB1接口曾經處於禁止狀態,則軟件首先必須等待RTC_CRL寄存器中的RSF位(寄存器同步標志)被硬件置’1’。
注:RTC的 APB1接口不受WFI和WFE等低功耗模式的影響。

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 }

 

 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM