在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

淺談RTC實時時鐘特征與原理

GReq_mcu168 ? 來源:CSDN技術社區 ? 作者:聚優致成 ? 2021-06-30 15:54 ? 次閱讀

一、RTC實時時鐘特征與原理

查看STM32中文手冊 16 實時時鐘(RTC)(308頁)

RTC (Real Time Clock):實時時鐘

實時時鐘是一個獨立的定時器。RTC模塊擁有一組連續計數的計數器,在相應軟件配置下,可提供時鐘日歷的功能。修改計數器的值可以重新設置系統當前的時間和日期。

RTC模塊和時鐘配置系統(RCC_BDCR寄存器)處于后備區域,即在系統復位或從待機模式喚醒后, RTC的設置和時間維持不變。

系統復位后,對后備寄存器和RTC的訪問被禁止,這是為了防止對后備區域(BKP)的意外寫操作。執行以下操作將使能對后備寄存器和RTC的訪問:

● 設置寄存器RCC_APB1ENR的PWREN和BKPEN位,使能電源和后備接口時鐘

● 設置寄存器PWR_CR的DBP位,使能對后備寄存器和RTC的訪問。

RTC特征

編程的預分頻系數:分頻系數最高為220。

● 32位的可編程計數器,可用于較長時間段的測量。

● 2個分離的時鐘:用于APB1接口的PCLK1和RTC時鐘(RTC時鐘的頻率必須小于PCLK1時鐘

頻率的四分之一以上)。

● 可以選擇以下三種RTC的時鐘源:

— HSE時鐘除以128;

— LSE振蕩器時鐘;

— LSI振蕩器時鐘(詳見6.2.8節RTC時鐘)。

● 2個獨立的復位類型:

— APB1接口由系統復位;

— RTC核心(預分頻器、鬧鐘、計數器和分頻器)只能由后備域復位(詳見6.1.3節)。

● 3個專門的可屏蔽中斷:

— 鬧鐘中斷,用來產生一個軟件可編程的鬧鐘中斷。

— 秒中斷,用來產生一個可編程的周期性中斷信號(最長可達1秒)。

— 溢出中斷,指示內部可編程計數器溢出并回轉為0的狀態。

二、RTC由兩部分組成

**APB1接口:**用來和APB1總線相連。通過APB1接口可以訪問RTC的相關寄存器(預分頻值,計數器值,鬧鐘值)。

**RTC核心:**由一組可編程計數器組成。分兩個主要模塊。

第一個是RTC預分頻模塊,它可以編程產生最長1秒的RTC時間基TR_CLK。如果設置了秒中斷允許位,可以產生秒中斷。

第二個是32位的可編程計數器,可被初始化為當前時間。系統時間按TR_CLK周期累加并與存儲在RTC_ALR寄存器中的可編程時間相比,當匹配時候如果設置了鬧鐘中斷允許位,可以產生鬧鐘中斷。

RTC內核完全獨立于APB1接口,軟件通過APB1接口對RTC相關寄存器訪問。但是相關寄存器只在RTC APB1時鐘進行重新同步的RTC時鐘的上升沿被更新。所以軟件必須先等待寄存器同步標志位(RTC_CRL的RSF位)被硬件置1才讀。

三、RTC時鐘源

首先講一下時鐘源:

三種不同的時鐘源可被用來驅動系統時鐘(SYSCLK):

● HSI振蕩器時鐘

● HSE振蕩器時鐘

● PLL時鐘

這些設備有以下2種二級時鐘源:

● 40kHz低速內部RC,可以用于驅動獨立看門狗和通過程序選擇驅動RTC。RTC用于從停機/待機模式下自動喚醒系統。

● 32.768kHz低速外部晶體也可用來通過程序選擇驅動RTC(RTCCLK)。

參看:STM32時鐘系統

當不被使用時,任一個時鐘源都可被獨立地啟動或關閉,由此優化系統功耗。

用戶可通過多個預分頻器配置AHB、高速APB(APB2)和低速APB(APB1)域的頻率。AHB和APB2域的最大頻率是72MHz。APB1域的最大允許頻率是36MHz。SDIO接口的時鐘頻率固定為HCLK/2。

RCC通過AHB時鐘(HCLK)8分頻后作為Cortex系統定時器(SysTick)的外部時鐘。通過對SysTick控制與狀態寄存器的設置,可選擇上述時鐘或Cortex(HCLK)時鐘作為SysTick時鐘。ADC時鐘由高速APB2時鐘經2、 4、 6或8分頻后獲得。

定時器時鐘頻率分配由硬件按以下2種情況自動設置:

如果相應的APB預分頻系數是1,定時器的時鐘頻率與所在APB總線頻率一致。

否則,定時器的時鐘頻率被設為與其相連的APB總線頻率的2倍。

如上圖,有五個時鐘源,為HSI、HSE、LSI、LSE、PLL。

接下來我們一一看一下:

HSE時鐘

**高速外部時鐘信號(HSE)**由以下兩種時鐘源產生:

● HSE外部晶體/陶瓷諧振器

● HSE用戶外部時鐘

為了減少時鐘輸出的失真和縮短啟動穩定時間,晶體/陶瓷諧振器和負載電容器必須盡可能地靠

近振蕩器引腳。負載電容值必須根據所選擇的振蕩器來調整。

外部時鐘源(HSE旁路)

在這個模式里,必須提供外部時鐘。它的頻率最高可達25MHz。用戶可通過設置在時鐘控制寄存器中的HSEBYP和HSEON位來選擇這一模式。外部時鐘信號(50%占空比的方波、正弦波或三角波)必須連到SOC_IN引腳,同時保證OSC_OUT引腳懸空。見圖9。

外部晶體/陶瓷諧振器(HSE晶體)

**4~16Mz外部振蕩器可為系統提供更為精確的主時鐘。**相關的硬件配置可參考圖9,進一步信息可參考數據手冊的電氣特性部分。

在時鐘控制寄存器RCC_CR中的HSERDY位用來指示高速外部振蕩器是否穩定。在啟動時,直到這一位被硬件置’1’,時鐘才被釋放出來。如果在時鐘中斷寄存器RCC_CIR中允許產生中斷,將會產生相應中斷。

HSE晶體可以通過設置時鐘控制寄存器里RCC_CR中的HSEON位被啟動和關閉。

HSI時鐘

HSI時鐘信號由內部8MHz的RC振蕩器產生,可直接作為系統時鐘或在2分頻后作為PLL輸入。

HSI RC振蕩器能夠在不需要任何外部器件的條件下提供系統時鐘。它的啟動時間比HSE晶體振蕩器短。然而,即使在校準之后它的時鐘頻率精度仍較差。

校準

制造工藝決定了不同芯片的RC振蕩器頻率會不同,這就是為什么每個芯片的HSI時鐘頻率在出廠前已經被ST校準到1%(25°C)的原因。系統復位時,工廠校準值被裝載到時鐘控制寄存器的HSICAL[7:0]位。

如果用戶的應用基于不同的電壓或環境溫度,這將會影響RC振蕩器的精度。可以通過時鐘控制寄存器里的HSITRIM[4:0]位來調整HSI頻率。

時鐘控制寄存器中的HSIRDY位用來指示HSI RC振蕩器是否穩定。在時鐘啟動過程中,直到這一位被硬件置’1’, HSI RC輸出時鐘才被釋放。HSI RC可由時鐘控制寄存器中的HSION位來啟動和關閉。

如果HSE晶體振蕩器失效, HSI時鐘會被作為備用時鐘源。

PLL

內部PLL可以用來倍頻HSI RC的輸出時鐘或HSE晶體輸出時鐘。

PLL的設置(選擇HIS振蕩器除2或HSE振蕩器為PLL的輸入時鐘,和選擇倍頻因子)必須在其被激活前完成。一旦PLL被激活,這些參數就不能被改動。

如果PLL中斷在時鐘中斷寄存器里被允許,當PLL準備就緒時,可產生中斷申請。

如果需要在應用中使用USB接口, PLL必須被設置為輸出48或72MHZ時鐘,用于提供48MHz的USBCLK時鐘。

LSE時鐘

**LSE晶體是一個32.768kHz的低速外部晶體或陶瓷諧振器。**它為實時時鐘或者其他定時功能提供一個低功耗且精確的時鐘源。

LSE晶體通過在備份域控制寄存器(RCC_BDCR)里的LSEON位啟動和關閉。

在備份域控制寄存器(RCC_BDCR)里的LSERDY指示LSE晶體振蕩是否穩定。在啟動階段,直到這個位被硬件置’1’后, LSE時鐘信號才被釋放出來。如果在時鐘中斷寄存器里被允許,可產生中斷申請。

外部時鐘源(LSE旁路)

在這個模式里必須提供一個32.768kHz頻率的外部時鐘源。你可以通過設置在備份域控制寄存器(RCC_BDCR)里的LSEBYP和LSEON位來選擇這個模式。具有50%占空比的外部時鐘信號(方波、正弦波或三角波)必須連到OSC32_IN引腳,同時保證OSC32_OUT引腳懸空,見圖9。

LSI時鐘

LSI RC擔當一個低功耗時鐘源的角色,它可以在停機和待機模式下保持運行,為獨立看門狗和自動喚醒單元提供時鐘。**LSI時鐘頻率大約40kHz(在30kHz和60kHz之間)。**進一步信息請參考數據手冊中有關電氣特性部分。

LSI RC可以通過控制/狀態寄存器(RCC_CSR)里的LSION位來啟動或關閉。

在控制/狀態寄存器(RCC_CSR)里的LSIRDY位指示低速內部振蕩器是否穩定。在啟動階段,直到這個位被硬件設置為’1’后,此時鐘才被釋放。如果在時鐘中斷寄存器(RCC_CIR)里被允許,將產生LSI中斷申請。

注意:只有大容量和互聯型產品可以進行LSI校準

LSI校準

可以通過校準內部低速振蕩器LSI來補償其頻率偏移,從而獲得精度可接受的RTC時間基數,以及獨立看門狗(IWDG)的超時時間(當這些外設以LSI為時鐘源)。

**校準可以通過使用TIM5的輸入時鐘(TIM5_CLK)測量LSI時鐘頻率實現。**測量以HSE的精度為保證,軟件可以通過調整RTC的20位預分頻器來獲得精確的RTC時鐘基數,以及通過計算得到精確的獨立看門狗(IWDG)的超時時間。

LSI校準步驟如下:

打開TIM5,設置通道4為輸入捕獲模式;

設置AFIO_MAPR的TIM5_CH4_IREMAP位為’1’,在內部把LSI連接到TIM5的通道4;

通過TIM5的捕獲/比較4事件或者中斷來測量LSI時鐘頻率;

根據測量結果和期望的RTC時間基數和獨立看門狗的超時時間,設置20位預分頻器。

四、RTC時鐘

**通 過 設 置 備 份 域 控 制 寄 存 器 (RCC_BDCR) 里 的 RTCSEL[1:0] 位 , RTCCLK 時鐘源可以由HSE/128、LSE或LSI時鐘提供。**除非備份域復位,此選擇不能被改變。

LSE時鐘在備份域里,但HSE和LSI時鐘不是。因此:

● 如果LSE被選為RTC時鐘:

— 只要VBAT維持供電,盡管VDD供電被切斷, RTC仍繼續工作。

● 如果LSI被選為自動喚醒單元(AWU)時鐘:

— 如果VDD供電被切斷, AWU狀態不能被保證。有關LSI校準,詳見6.2.5節LSI時鐘。

● 如果HSE時鐘128分頻后作為RTC時鐘:

— 如果VDD供電被切斷或內部電壓調壓器被關閉(1.8V域的供電被切斷),則RTC狀態不確定。

— 必須設置電源控制寄存器(見4.4.1節)的DPB位(取消后備區域的寫保護)為’1’。

五、RTC寄存器

上面都是從STM32中文手冊里摘取的。大概了解一下RTC和時鐘。

不過講的有點扯,里面有多好寄存器,不知道是干啥的。接下來重點看一下這些寄存器。

RTC控制寄存器高位(RTC_CRH)

RTC控制寄存器低位(RTC_CRL)

①修改CRH/CRL寄存器,必須先判斷RSF位,確定已經同步。

②修改CNT,ALR,PRL的時候,必須先配置CNF位進入配置模式,修改完之后,設置CNF位為0退出配置模式

③同時在對RTC相關寄存器寫操作之前,必須判斷上一次寫操作已經結束,也就是判斷RTOFF位是否置位。

RTC預分頻裝載寄存器(RTC_PRLH/RTC_PRLL)

預分頻裝載寄存器用來保存RTC預分頻器的周期計數值。它們受RTC_CR寄存器的RTOFF位保護,僅當RTOFF值為’1’時允許進行寫操作。

配置RTC寄存器

必須設置RTC_CRL 寄 存 器 中 的CNF位 , 使RTC進入配置模式后 , 才能寫 入RTC_PRL、RTC_CNT、 RTC_ALR寄存器。

另外,對RTC任何寄存器的寫操作,都必須在前一次寫操作結束后進行。可以通過查詢RTC_CR寄存器中的RTOFF狀態位,判斷RTC寄存器是否處于更新中。僅當RTOFF狀態位是’1’時,才可以寫入RTC寄存器。

配置過程:

查詢RTOFF位,直到RTOFF的值變為’1’

置CNF值為1,進入配置模式

對一個或多個RTC寄存器進行寫操作

清除CNF標志位,退出配置模式

查詢RTOFF,直至RTOFF位變為’1’以確認寫操作已經完成。

僅當CNF標志位被清除時,寫操作才能進行,這個過程至少需要3個RTCCLK周期。

讀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等低功耗模式的影響

六、RTC相關庫函數講解

庫函數所在文件:stm32f10x_rtc.c / stm32f10x_rtc.h

RTC時鐘源和時鐘操作函數:

void RCC_RTCCLKConfig(uint32_t CLKSource);//時鐘源選擇 void RCC_RTCCLKCmd(FunctionalState NewState)//時鐘使能RTC配置函數(預分頻,計數值:

void RTC_SetPrescaler(uint32_t PrescalerValue);//預分頻配置:PRLH/PRLLvoid RTC_SetCounter(uint32_t CounterValue);//設置計數器值:CNTH/CNTLvoid RTC_SetAlarm(uint32_t AlarmValue);//鬧鐘設置:ALRH/ALRLRTC中斷設置函數:

void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState);//CRH

RTC允許配置和退出配置函數:

void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState);//CRH

同步函數:

void RTC_WaitForLastTask(void);//等待上次操作完成:CRL位RTOFFvoid RTC_WaitForSynchro(void);//等待時鐘同步:CRL位RSF相關狀態位獲取清除函數:

FlagStatus RTC_GetFlagStatus(uint16_t RTC_FLAG);void RTC_ClearFlag(uint16_t RTC_FLAG);ITStatus RTC_GetITStatus(uint16_t RTC_IT);void RTC_ClearITPendingBit(uint16_t RTC_IT);其他相關函數(BKP等)

PWR_BackupAccessCmd();//BKP后備區域訪問使能RCC_APB1PeriphClockCmd();//使能PWR和BKP時鐘RCC_LSEConfig();//開啟LSE,RTC選擇LSE作為時鐘源PWR_BackupAccessCmd();//BKP后備區域訪問使能uint16_t BKP_ReadBackupRegister(uint16_t BKP_DR);//讀BKP寄存器void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data);//寫BKP 七、RTC配置一般步驟 1) 使能電源時鐘和備份區域時鐘。 前面已經介紹了,我們要訪問 RTC 和備份區域就必須先使能電源時鐘和備份區域時鐘。

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

2) 取消備份區寫保護。

要向備份區域寫入數據,就要先取消備份區域寫保護(寫保護在每次硬復位之后被使能),否則是無法向備份區域寫入數據的。我們需要用到向備份區域寫入一個字節,來標記時鐘已經配置過了,這樣避免每次復位之后重新配置時鐘。取消備份區域寫保護的庫函數實現方法是:

PWR_BackupAccessCmd(ENABLE); //使能 RTC 和后備寄存器訪問

3) 復位備份區域,開啟外部低速振蕩器。

在取消備份區域寫保護之后,我們可以先對這個區域復位,以清除前面的設置,當然這個操作不要每次都執行,因為備份區域的復位將導致之前存在的數據丟失,所以要不要復位,要看情況而定。然后我們使能外部低速振蕩器,注意這里一般要先判斷 RCC_BDCR 的 LSERDY位來確定低速振蕩器已經就緒了才開始下面的操作。

備份區域復位的函數是:

BKP_DeInit();//復位備份區域

開啟外部低速振蕩器的函數是:

RCC_LSEConfig(RCC_LSE_ON);// 開啟外部低速振蕩器

4) 選擇 RTC 時鐘,并使能。

這里我們將通過 RCC_BDCR 的 RTCSEL 來選擇選擇外部 LSI 作為 RTC 的時鐘。然后通過RTCEN 位使能 RTC 時鐘。庫函數中,選擇 RTC 時鐘的函數是:

RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //選擇 LSE 作為 RTC 時鐘

對于 RTC 時鐘的選擇,還有 RCC_RTCCLKSource_LSI 和RCC_RTCCLKSource_HSE_Div128 這兩個,顧名思義,前者為 LSI,后者為 HSE 的 128 分頻,這在時鐘系統章節有講解過。

使能 RTC 時鐘的函數是:

RCC_RTCCLKCmd(ENABLE); //使能 RTC 時鐘

5) 設置 RTC 的分頻,以及配置 RTC 時鐘。

在開啟了 RTC 時鐘之后,我們要做的就是設置 RTC 時鐘的分頻數,通過 RTC_PRLH 和RTC_PRLL 來設置,然后等待 RTC 寄存器操作完成,并同步之后,設置秒鐘中斷。然后設置RTC 的允許配置位(RTC_CRH 的 CNF 位),設置時間(其實就是設置 RTC_CNTH 和 RTC_CNTL兩個寄存器)。下面我們一一這些步驟用到的庫函數:在進行 RTC 配置之前首先要打開允許配置位(CNF),庫函數是:

RTC_EnterConfigMode();/// 允許配置

在配置完成之后,千萬別忘記更新配置同時退出配置模式,函數是:

RTC_ExitConfigMode();//退出配置模式, 更新配置

設置 RTC 時鐘分頻數, 庫函數是:

void RTC_SetPrescaler(uint32_t PrescalerValue);

這個函數只有一個入口參數,就是 RTC 時鐘的分頻數,很好理解。

然后是設置秒中斷允許, RTC 使能中斷的函數是:

void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState);

這個函數的第一個參數是設置秒中斷類型,這些通過宏定義定義的。對于使能秒中斷方法是:

RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC 秒中斷

八、RTC程序

這篇文章復制粘貼了這么多,感覺不到一絲有用的東西。算了,還是看一下,程序是怎么寫的吧。

RTC_Init

//實時時鐘配置//初始化 RTC 時鐘,同時檢測時鐘是否工作正常//BKP-》DR1 用于保存是否第一次配置的設置//返回 0:正常//其他:錯誤代碼u8 RTC_Init(void){u8 temp=0;//檢查是不是第一次配置時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR |RCC_APB1Periph_BKP, ENABLE); //①使能 PWR 和 BKP 外設時鐘PWR_BackupAccessCmd(ENABLE); //②使能后備寄存器訪問if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050) //從指定的后備寄存器中//讀出數據:讀出了與寫入的指定數據不相乎{BKP_DeInit(); //③復位備份區域RCC_LSEConfig(RCC_LSE_ON); //設置外部低速晶振(LSE)while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp《250)//檢查指定的 RCC 標志位設置與否,等待低速晶振就緒{temp++;delay_ms(10);}if(temp》=250)return 1;//初始化時鐘失敗,晶振有問題RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //設置 RTC 時鐘//(RTCCLK),選擇 LSE 作為 RTC 時鐘RCC_RTCCLKCmd(ENABLE); //使能 RTC 時鐘RTC_WaitForLastTask(); //等待最近一次對 RTC 寄存器的寫操作完成RTC_WaitForSynchro(); //等待 RTC 寄存器同步RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC 秒中斷RTC_WaitForLastTask(); //等待最近一次對 RTC 寄存器的寫操作完成RTC_EnterConfigMode(); // 允許配置RTC_SetPrescaler(32767); //設置 RTC 預分頻的值RTC_WaitForLastTask(); //等待最近一次對 RTC 寄存器的寫操作完成RTC_Set(2015,1,14,17,42,55); //設置時間RTC_ExitConfigMode(); //退出配置模式BKP_WriteBackupRegister(BKP_DR1, 0X5050); //向指定的后備寄存器中//寫入用戶程序數據 0x5050}else//系統繼續計時{RTC_WaitForSynchro(); //等待最近一次對 RTC 寄存器的寫操作完成RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC 秒中斷RTC_WaitForLastTask(); //等待最近一次對 RTC 寄存器的寫操作完成}RTC_NVIC_Config(); //RCT 中斷分組設置RTC_Get(); //更新時間return 0; //ok}RTC_Set

//設置時鐘//把輸入的時鐘轉換為秒鐘//以 1970 年 1 月 1 日為基準//1970~2099 年為合法年份//返回值:0,成功;其他:錯誤代碼。//月份數據表u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正數據表//平年的月份日期表const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec){u16 t;u32 seccount=0;if(syear《1970||syear》2099)return 1;for(t=1970;t《syear;t++) //把所有年份的秒鐘相加{ if(Is_Leap_Year(t))seccount+=31622400;//閏年的秒鐘數else seccount+=31536000; //平年的秒鐘數}smon-=1;for(t=0;t《smon;t++) //把前面月份的秒鐘數相加{ seccount+=(u32)mon_table[t]*86400; //月份秒鐘數相加if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//閏年 2 月份增加一天的秒鐘數}seccount+=(u32)(sday-1)*86400; //把前面日期的秒鐘數相加seccount+=(u32)hour*3600; //小時秒鐘數seccount+=(u32)min*60; //分鐘秒鐘數seccount+=sec; //最后的秒鐘加上去RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR |RCC_APB1Periph_BKP, ENABLE); //使能 PWR 和 BKP 外設時鐘PWR_BackupAccessCmd(ENABLE); //使能 RTC 和后備寄存器訪問RTC_SetCounter(seccount); //設置 RTC 計數器的值RTC_WaitForLastTask(); //等待最近一次對 RTC 寄存器的寫操作完成return 0;}RTC_Get

//得到當前的時間,結果保存在 calendar 結構體里面//返回值:0,成功;其他:錯誤代碼.u8 RTC_Get(void){ static u16 daycnt=0;u32 timecount=0;u32 temp=0;u16 temp1=0;timecount=RTC-》CNTH; //得到計數器中的值(秒鐘數)timecount《《=16;timecount+=RTC-》CNTL;temp=timecount/86400; //得到天數(秒鐘數對應的)if(daycnt!=temp) //超過一天了{daycnt=temp;temp1=1970; //從 1970 年開始while(temp》=365){if(Is_Leap_Year(temp1)) //是閏年{if(temp》=366)temp-=366; //閏年的秒鐘數else break;}else temp-=365; //平年temp1++;}calendar.w_year=temp1; //得到年份temp1=0;while(temp》=28) //超過了一個月{if(Is_Leap_Year(calendar.w_year)&&temp1==1)//當年是不是閏年/2 月份{if(temp》=29)temp-=29;//閏年的秒鐘數else break;}else{ if(temp》=mon_table[temp1])temp-=mon_table[temp1];//平年else break;}temp1++;}calendar.w_month=temp1+1; //得到月份calendar.w_date=temp+1; //得到日期}temp=timecount%86400; //得到秒鐘數calendar.hour=temp/3600; //小時calendar.min=(temp%3600)/60; //分鐘calendar.sec=(temp%3600)%60; //秒鐘calendar.week=RTC_Get_Week(calendar.w_year,calendar.w_month,calendar.w_date);//獲取星期return 0;}RTC_NVIC_Config

static void RTC_NVIC_Config(void){NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;//RTC全局中斷NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//先占優先級1位,從優先級3位NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//先占優先級0位,從優先級4位NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能該通道中斷NVIC_Init(&NVIC_InitStructure);//根據NVIC_InitStruct中指定的參數初始化外設NVIC寄存器}RTC_IRQHandler

//RTC 時鐘中斷//每秒觸發一次void RTC_IRQHandler(void){if (RTC_GetITStatus(RTC_IT_SEC) != RESET) //秒鐘中斷{RTC_Get(); //更新時間}if(RTC_GetITStatus(RTC_IT_ALR)!= RESET) //鬧鐘中斷{RTC_ClearITPendingBit(RTC_IT_ALR); //清鬧鐘中斷RTC_Get(); //更新時間printf(“Alarm Time:%d-%d-%d %d:%d:%d ”,calendar.w_year,calendar.w_month,calendar.w_date,calendar.hour,calendar.min,calendar.sec);//輸出鬧鈴時間}RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW); //清鬧鐘中斷RTC_WaitForLastTask();}九、項目代碼

void BSP_RTC_Init(void){u32 i = 0;#if(INFO_OUT_RTC_INIT_EN 》 0)u8tmpBuf[60]=“”;#endif

/* Clear reset flags */RCC_ClearFlag();

// 這里標志必須跟測試程序一致否則時間被復位成默認if (BKP_ReadBackupRegister(BKP_DR1) != RTC_SAVE_FLAG){RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);/* Allow access to BKP Domain */PWR_BackupAccessCmd(ENABLE);

/* Backup data register value is not correct or not yet programmed (whenthe first time the program is executed) */

/* RTC Configuration */BSP_RTC_Config();

#if(DEF_RTCINFO_OUTPUTEN 》 0)if(dbgInfoSwt & DBG_INFO_RTC)myPrintf(“[RTC]: RTC finish configured.。。。 ”);#endif

/* Set default time */SYS_RTC.year=Default_year;SYS_RTC.month=Default_month;SYS_RTC.day=Default_day;SYS_RTC.hour=Default_hour;SYS_RTC.minute =Default_minute;SYS_RTC.second =Default_second;

/* Adjust time by values entred by the user on the hyperterminal */BSP_RTC_Set_Current(&SYS_RTC);

BKP_WriteBackupRegister(BKP_DR1, RTC_SAVE_FLAG);}else{/* Enable PWR and BKP clocks */RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

/* Allow access to BKP Domain */PWR_BackupAccessCmd(ENABLE);

/* Wait for RTC registers synchronization */RTC_WaitForSynchro();

/* Wait until last write operation on RTC registers has finished */RTC_WaitForLastTask();

/* Enable the RTC Second *///RTC_ITConfig(RTC_IT_SEC, ENABLE);// 不能在系統運行前使能中斷//RTC_ITConfig(RTC_IT_ALR, ENABLE);// 系統鬧鐘中斷/* Wait until last write operation on RTC registers has finished *///RTC_WaitForLastTask();// 不能在系統運行前使能中斷

/* Initialize Date structure */SYS_RTC.year = BKP_ReadBackupRegister(BKP_DR4);SYS_RTC.month= BKP_ReadBackupRegister(BKP_DR3);SYS_RTC.day = BKP_ReadBackupRegister(BKP_DR2);

if(RTC_GetCounter() / 86399 != 0){for(i = 0; i 《 (RTC_GetCounter() / 86399); i++){BSP_Date_Update(&SYS_RTC);}

/* Wait until last write operation on RTC registers has finished */RTC_WaitForLastTask();RTC_SetCounter(RTC_GetCounter() % 86399);/* Wait until last write operation on RTC registers has finished */RTC_WaitForLastTask();

BKP_WriteBackupRegister(BKP_DR4, SYS_RTC.year);BKP_WriteBackupRegister(BKP_DR3, SYS_RTC.month);BKP_WriteBackupRegister(BKP_DR2, SYS_RTC.day);}}/* Clear the RTC Second Interrupt pending bit */RTC_ClearITPendingBit(RTC_IT_SEC);// 防止系統初始化未完成前進入中斷程序RTC_ClearFlag(RTC_IT_SEC);

/* Enable one second interrupe *///RTC_ITConfig(RTC_IT_SEC,ENABLE);// 不能在系統運行前使能中斷rtcInitFinish=1;// 設置初始化完成標志}

void BSP_RTC_Config(void){//u32 counter = 0;uint32_t tmp = 0;RCC_ClocksTypeDef RCC_Clocks;TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_ICInitTypeDef TIM_ICInitStructure;

/* Enable PWR and BKP clocks */RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);/* Allow access to BKP Domain */PWR_BackupAccessCmd(ENABLE);/* Reset Backup Domain */BKP_DeInit();RCC_LSICmd(ENABLE); //啟用LSIwhile (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET){}RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);RCC_RTCCLKCmd(ENABLE); // Enable RTC ClockRTC_WaitForSynchro();RTC_WaitForLastTask();RTC_SetPrescaler(40000); // RTC period = RTCCLK/RTC_PR = (4 KHz)/(4000+1) LSIRTC_WaitForLastTask();BKP_TamperPinCmd(DISABLE);BKP_RTCOutputConfig(BKP_RTCOutputSource_Second);RCC_GetClocksFreq(&RCC_Clocks);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);GPIO_PinRemapConfig(GPIO_Remap_TIM5CH4_LSI, ENABLE);TIM_TimeBaseStructure.TIM_Prescaler = 0;TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseStructure.TIM_Period = 0xFFFF;TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;TIM_ICInitStructure.TIM_ICFilter = 0;TIM_ICInit(TIM5, &TIM_ICInitStructure);OperationComplete = 0;TIM_Cmd(TIM5, ENABLE);TIM5-》SR = 0;//TIM_ITConfig(TIM5, TIM_IT_CC4, ENABLE);

while (OperationComplete != 2){if (TIM_GetFlagStatus(TIM5, TIM_FLAG_CC4) == SET){tmpCC4[IncrementVar_OperationComplete()] = (uint16_t)(TIM5-》CCR4);TIM_ClearFlag(TIM5, TIM_FLAG_CC4);if (GetVar_OperationComplete() 》= 2){tmp = (uint16_t)(tmpCC4[1] - tmpCC4[0] + 1);SetVar_PeriodValue(tmp);}}}if (PeriodValue != 0){#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)LsiFreq = (uint32_t)((uint32_t)(RCC_Clocks.PCLK1_Frequency) / (uint32_t)PeriodValue);#elseLsiFreq = (uint32_t)((uint32_t)(RCC_Clocks.PCLK1_Frequency * 2) / (uint32_t)PeriodValue);#endif}RTC_SetPrescaler(LsiFreq - 1);RTC_WaitForLastTask();

TIM_DeInit( TIM5 );}十、HSE作為RTC時鐘源

void RTC_Configuration(void){RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);PWR_BackupAccessCmd(ENABLE);/* Reset Backup Domain */BKP_DeInit();//使用外部高速晶振8M/128 = 62.5KRCC_RTCCLKConfig(RCC_RTCCLKSource_HSE_Div128);//允許RTCRCC_RTCCLKCmd(ENABLE);//等待RTC寄存器同步RTC_WaitForSynchro();

RTC_WaitForLastTask();//允許RTC的秒中斷(還有鬧鐘中斷和溢出中斷可設置)RTC_ITConfig(RTC_IT_SEC, ENABLE);

RTC_WaitForLastTask();//62500晶振預分頻值是62500,不過一般來說晶振都不那么準RTC_SetPrescaler(62498); //如果需要校準晶振,可修改此分頻值RTC_WaitForLastTask();//清除標志RCC_ClearFlag();}編輯:jq

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 時鐘
    +關注

    關注

    11

    文章

    1740

    瀏覽量

    131627
  • 定時器
    +關注

    關注

    23

    文章

    3254

    瀏覽量

    115069
  • RTC
    RTC
    +關注

    關注

    2

    文章

    542

    瀏覽量

    66781
  • 可編程計數器

    關注

    0

    文章

    3

    瀏覽量

    5617

原文標題:STM32開發 -- RTC詳解

文章出處:【微信號:mcu168,微信公眾號:硬件攻城獅】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    RTC時鐘芯片+電池的應用案例(一)

    實時時鐘,簡稱RTC,是廣泛應用于電子產品的重要元器件。愛普生RTC實時時鐘具有高精度、高穩定性和多功能的特點,目前廣泛應用于多個行業。下面通過幾個視頻來詳細了解一下愛普生
    的頭像 發表于 01-08 11:25 ?180次閱讀
    <b class='flag-5'>RTC</b><b class='flag-5'>時鐘</b>芯片+電池的應用案例(一)

    愛普生RTC實時時鐘模塊助力車載BMS系統更好運行

    的使用壽命;此外,BMS模塊還能夠實時監測電池狀態,確保電池運行的安全性和穩定性。愛普生RTC實時時鐘模塊助力車載BMS系統更好運行,該模塊集成了32.768kHz石
    的頭像 發表于 11-20 14:18 ?279次閱讀
    愛普生<b class='flag-5'>RTC</b><b class='flag-5'>實時時鐘</b>模塊助力車載BMS系統更好運行

    實時時鐘芯片RTC

    FRTC8563是NYFEA徠飛公司推出的一款實時時鐘芯片,采用SOP-8封裝形式。這種封裝形式具有體積小、引腳間距小、便于集成等特點,使得FRTC8563能夠方便地應用于各種電子設備中
    的頭像 發表于 10-22 11:33 ?336次閱讀

    使用實時時鐘

    電子發燒友網站提供《使用實時時鐘庫.pdf》資料免費下載
    發表于 10-22 10:09 ?0次下載
    使用<b class='flag-5'>實時時鐘</b>庫

    適用于智能門鎖的低功耗RTC實時時鐘模塊RX8010SJ

    隨著智能家居的普及,智能門鎖已成為保障家庭安全的重要設備。作為智能門鎖的關鍵組件之一,實時時鐘RTC)模塊負責提供準確的時間基準,確保門鎖的各種時間相關功能正常運行。一款適用于智能門鎖的低功耗
    的頭像 發表于 08-28 14:29 ?429次閱讀
    適用于智能門鎖的低功耗<b class='flag-5'>RTC</b><b class='flag-5'>實時時鐘</b>模塊RX8010SJ

    bq32000實時時鐘(RTC)數據表

    電子發燒友網站提供《bq32000實時時鐘(RTC)數據表.pdf》資料免費下載
    發表于 08-23 11:23 ?0次下載
    bq32000<b class='flag-5'>實時時鐘</b>(<b class='flag-5'>RTC</b>)數據表

    BQ32002實時時鐘(RTC)數據表

    電子發燒友網站提供《BQ32002實時時鐘(RTC)數據表.pdf》資料免費下載
    發表于 08-23 11:23 ?0次下載
    BQ32002<b class='flag-5'>實時時鐘</b>(<b class='flag-5'>RTC</b>)數據表

    bq3285E/L實時時鐘(RTC)數據表

    電子發燒友網站提供《bq3285E/L實時時鐘(RTC)數據表.pdf》資料免費下載
    發表于 08-23 11:22 ?0次下載
    bq3285E/L<b class='flag-5'>實時時鐘</b>(<b class='flag-5'>RTC</b>)數據表

    bq3285實時時鐘(RTC)數據表

    電子發燒友網站提供《bq3285實時時鐘(RTC)數據表.pdf》資料免費下載
    發表于 08-23 11:21 ?0次下載
    bq3285<b class='flag-5'>實時時鐘</b>(<b class='flag-5'>RTC</b>)數據表

    DP8573A實時時鐘(RTC)數據表

    電子發燒友網站提供《DP8573A實時時鐘(RTC)數據表.pdf》資料免費下載
    發表于 08-23 10:11 ?0次下載
    DP8573A<b class='flag-5'>實時時鐘</b>(<b class='flag-5'>RTC</b>)數據表

    TCXO RTC實時時鐘模塊的特性

    高精度實時時鐘模塊內建TCXO數字式實時時鐘模塊的特征【序文】時間是我們日常生活中的基本概念。火車運行管理、進出場管理等各種處理系統和應用程序按照時間信息工作。在金融、股市領域中,時間操縱著巨大利益
    的頭像 發表于 08-14 11:44 ?410次閱讀
    TCXO <b class='flag-5'>RTC</b><b class='flag-5'>實時時鐘</b>模塊的特性

    RTC實時時鐘的基本概念和工作原理

    在現代電子設備中,精確的時間管理和控制是至關重要的。為了實現這一功能,實時時鐘RTC, Real-Time Clock)模塊被廣泛應用于各種設備和系統中。RTC模塊作為一個獨立的定時器,能夠提供
    的頭像 發表于 05-27 15:43 ?3883次閱讀

    stm8l051 RTC LSI作為實時時鐘不準怎么校準?

    (CLK_RTCCLKSource_LSI, CLK_RTCCLKDiv_1); CLK_PeripheralClockConfig(CLK_Peripheral_RTC, ENABLE); 現在以LSI作為實時時鐘,十分鐘內快了2分鐘,分頻2后右邊慢了 請問大神么 這個
    發表于 04-30 07:13

    愛普生實時時鐘模塊RTC

    愛普生是一家IC和晶體自主研發的公司,有自己的IC和晶振產線。所以我們能將RTC IC+晶體單元+外結電容封裝在一起,組成獨立RTC模塊。外圍不需要在接晶體和匹配電容。愛普生RTC能夠簡化客戶
    發表于 04-17 11:10 ?0次下載

    RX-4571LC、NB、SA實時時鐘模塊

    RX-4571LC實時時鐘模塊是EPSON推出的一求款額定頻率32.768KHz,接口為SPI(3-wire),月偏差為±60 s的實時時鐘模塊,12腳貼片,具有小尺寸,高穩定性。該款實時時鐘模塊
    發表于 01-31 11:46 ?0次下載
    主站蜘蛛池模板: 四虎永久在线精品| 四虎影视入口| 日韩亚洲人成在线综合| 888米奇在线视频四色| 一二三区在线观看| 99久久99这里只有免费费精品| www四虎影院| 色婷婷网| 日本wwwwwwwww| 毛片网此| 福利色播| 手机看福利片| h视频日本| 亚洲一二三四区| 一区二区三区电影| 四虎4hu| 欧美综合成人网| 色午夜影院| 欧美激情亚洲精品日韩1区2区| 久久成人国产精品青青| 94在线| 久久天天躁狠狠躁夜夜爽| 日韩草逼| 国产在线观看黄| free chinese 国产精品| 中文字幕在线观看一区二区| 扒开末成年粉嫩的小缝强文| 色婷婷色综合缴情在线| 免费播放特黄特色毛片| 377p亚洲欧洲日本大胆色噜噜| 奇米影视9999| 一区卡二区卡三区卡视频| 伊人狠狠丁香婷婷综合色| 日韩一区二区三区在线| 国产性较精品视频免费| 天天操天天射天天| 色爱区综合激情五月综合激情| 99在线国产| 欧美大香a蕉免费| 亚洲视频色| 欧美另类高清|