1. 程式人生 > >STM32 RTC實時時鐘

STM32 RTC實時時鐘

我用的是STM32庫函式:兩個知識點:
      一、RTC時鐘框圖分析(重要)
      二、時間是怎樣顯示出來的(簡析)
一、RTC時鐘框圖分析(重要)
先熟悉一下幾個知識點:
      1、STM32的實時時鐘(RTC)是一個獨立的定時器!
      2、RTC模組和時鐘配置系統(RCC_BDCR暫存器)是在後備區域,即在系統復位火從待機模式喚醒後RTC的設定和時間維持不變。

RTC這章中,對RTC相關的暫存器的操作特別重要,我在這裡不解釋了,請查閱手冊。。

先上圖!

RTC時鐘框圖

RTC時鐘框圖分為完全獨立的兩個部分:1、APB1介面部分(用來RTC相關的暫存器);2、RTC核心;
      第一部分:
APB1介面。注意:這裡涉及到暫存器RTC_CRL中的RSF位,這位是暫存器的同步標誌,具體內容去看STM32參考手冊RTC這一章。
      第二部分:
RTC核心。這裡分為兩個模組:1、RTC預分頻器模組;2、一個32位的可程式設計計數器;
      下面開始分析第二部分:
       先給大家介紹下後備區域的幾個特別重要的暫存器:
       1、RTC_DIV(重要):RTC預分頻器餘數暫存器。這個暫存器的作用是來獲得比秒鐘更加準確的時鐘(0.1s,0.01s),該暫存器是自減的,用來儲存還需要多少個時鐘週期獲得一個秒訊號。這裡加上一個公式(STM32參考手冊裡有):fTR_CLK=fRTCCLK/(PRL[19:0]+1)    到這裡是書上的原話~!
       解釋一下,
RTC_DIV暫存器的值是由RTC_PRL(RTC預分頻器裝載暫存器)提供的,而RTC_DIV暫存器的時鐘頻率是由RTCCLK提供的(看圖)。比如我們把RTC_PRL值設為32767,則RTC_DIV暫存器的值也為32767,他和RTCCLK的時鐘頻率是一樣的(這裡根據上面的公式,RTC_PRL加1,則RTC_DIV也加1)。RTCCLK的時鐘週期是1/32768(s),也就是每一個RTCCLK的時鐘週期,RTC_DIV自減1,直至到1s鍾後,被硬體重新裝載,也就是1s鍾減32768次。那他到底是怎麼提供0.1s,甚至是0.01s的呢?
       舉個例子就明白了。比如我想要得到1.12秒的這個時間,就要求RTC_DIV自減0.12/(1/32768)次。RTC_DIV只得到0.12s的時間,還有1s時間從哪兒來?他是TR_CLK提供的。這個問題會在下文講解。。
→_→
      2、RTC_PRL:RTC預分頻裝載暫存器。這個暫存器有兩個作用:1、提供給RTC_DIV的重新裝載值;2、設定時鐘分頻係數。
       第一個作用不講了。第二個作用:
設定時鐘分頻係數。比如我們使用32.768KHz的晶振作為時鐘輸入,那麼我們配置這個暫存器值位32767,就可以得到1s鐘的計數頻率(32768/(32767+1),單位(HZ))。
       3、RTC_CNT(重要):RTC計數器暫存器。這個暫存器較簡單,用來記錄秒鐘值。如果之前對RTC_CR(控制暫存器),的相關中斷允許位配置的話,RTC_CNT暫存器可以產生一個溢位中斷
       4、RTC_ALR:RTC鬧鐘暫存器。從圖中就可以看出來,很簡單。用來標記鬧鐘產生時間,如果RTC_CNT的值和RTC_ALR的值相等的話,並使能中斷的話(
在RTC_CR(控制暫存器)中配置),會產生一個鬧鐘中斷
       後備區域的暫存器就給大家介紹到這兒。相比大家通過上面的介紹結合框圖,頭腦裡面應該有個大致流程了吧。沒有~!?臥槽~那就給大家理一遍思路
→_→
       首先外部加進來一個時鐘訊號RTCCLK(32.768K),然後設定RTC_PRL的分頻係數為32767,得到一個秒時鐘訊號TR_CLK(1HZ)。當TR_CLK每過一個時鐘週期,產生一個RTC_Second(秒鐘中斷),同時RTC_CNT計數器(記錄秒值)加1。如果要求更精準的時間,還可以在RTC_CR暫存器的RSF位被置1時去讀RTC_DIV的值。

二、時間是怎樣顯示出來的(簡析)
      主函式中有這麼兩條語句:
      LCD_ShowString(60,130,200,16,16,"    -  -  ");       ①
      LCD_ShowString(60,162,200,16,16,"  :  :  ");          ②
      在看這三條語句(這裡統稱”中間三條語句“):
      LCD_ShowNum(60,130,calendar.w_year,4,16);                                     
      LCD_ShowNum(100,130,calendar.w_month,2,16);                                     
      LCD_ShowNum(124,130,calendar.w_date,2,16);
      和這三條語句(
這裡統稱”最後三條語句“):
      LCD_ShowNum(60,162,calendar.hour,2,16);                                     
      LCD_ShowNum(84,162,calendar.min,2,16);                                     
      LCD_ShowNum(108,162,calendar.sec,2,16);
      很顯然,中間三條語句是顯示年月日的對應①,最後三條語句是顯示時分秒的對應②。這些結構體成員都在初始化函式(RTC_Init();)中被賦值了,怎麼賦值的,大家自己去研究吧。。。然後在硬體中,TR_CLK的每個時鐘週期都會觸發秒中斷,在秒中斷服務函式中又對時間進行了更新。
       想顯示時間,是不是先得設定一個基礎時間,然後讓系統在基礎時間上,進行自加。
      
第一步:設定一個基礎時間。在對時鐘進行配置時(在初始化函式(RTC_Init();中配置),裡面有個RTC_Set();函式,此函式會你設定的年月日時分秒進行計算,算出從1970年到你設定那個時刻總共是多少秒(這博主也不知道為什麼是1970年),然後把算出來的這個秒值賦給RTC_CNT計數器作為初值。
       第二步:系統自己更新時間(自加)。時間是怎麼更新的,這裡給大家簡單提一下。。在更新函式(RTC_Get();)中,首先會讀取RTC_CNT計數器中的值,然後經過一番倒計算,計算出年月日時分秒和星期,分別賦值給那些時間的結構體變數。於是在主函式的while(1)中,會不斷的被秒中斷重新整理時間,並顯示在LCD上。
       這樣,一個完整的時鐘就顯示在LCD螢幕上了。大功告成!
      
博主不才,大牛不喜勿噴哦~