簡單初始化STM32的RTC
要使用 RTC,一般來說也順帶地使用上后備寄存器—這是因為RTC 是一個簡單的秒中斷
定時器,年月日時分秒的信息必須要找個地方能掉電保存才有意義.STM32 的備份寄存器(BKP)是42個16位的寄存器,可用來存儲84個字節(jié)的用戶應(yīng)用程序數(shù)據(jù)。他們處在備份域里,當(dāng)VDD電源被切斷,他們?nèi)匀挥蒝BAT維持供電。當(dāng)系統(tǒng)在待機(jī)模式下被喚醒,或系統(tǒng)復(fù)位或電源復(fù)位時,他們也不會被復(fù)位。 此外,BKP控制寄存器用來管理侵入檢測和RTC校準(zhǔn)功能。 復(fù)位后,對備份寄存器和RTC的訪問被禁止,并且備份域被保護(hù)以防止可能存在的意外的寫操作它是用后備電池供電的,只要配置好后,即使系統(tǒng)關(guān)電,32768 的
晶振和后備寄存器的數(shù)據(jù)也會得以維持.而且RTC的計數(shù)器是會繼續(xù)秒遞增的.那么要配
置RTC,就必須開放以下東西:
#include "stm32f10x_bkp.h" 這個是后備寄存器
#include "stm32f10x_pwr.h" 電源管理
#include "stm32f10x_rtc.h" RTC庫
開始吧.....先是中斷
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure on
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/*RTC*/
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;//RTC全局中斷
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
然后設(shè)置 RTC
#include "STM32Lib\stm32f10x.h"
#include "hal.h"
static u8 RTC_Blank=0;
/***********************************
**函數(shù)名:RTC_Configuration
**功能:RTC設(shè)置
**注意事項:要根據(jù)是否是第一次設(shè)置,才進(jìn)入下面的RTC設(shè)定
判斷是否第一次設(shè)置,只需要判斷RTC后備寄存器1的值是否為事先寫入的0XA5A5,如果不是,則
RTC是第一次上電,需要初始化RTC,并把實際時間轉(zhuǎn)化為RTC計數(shù)值,這里沒有設(shè)置實際時間,只是簡單地初始化了RTC
************************************/
void RTC_Configuration(void)
{
/*PWR時鐘(電源控制)與BKP時鐘(RTC后備寄存器)使能*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
/*使能RTC和后備寄存器訪問*/
PWR_BackupAccessCmd(ENABLE);
/*從指定的后備寄存器(BKP_DR1)中讀出數(shù)據(jù)*/
if(BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
{
/* 將外設(shè)BKP的全部寄存器重設(shè)為缺省值 */
BKP_DeInit();
/*啟用 LSE(外部低速晶振)*/
RCC_LSEConfig(RCC_LSE_ON);
/*等待外部晶振震蕩 需要等待比較長的時間*/
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
/*使用外部晶振32.768K作為RTC時鐘*/
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
//允許RTC
RCC_RTCCLKCmd(ENABLE);
//等待RTC寄存器同步 原因下文說明
RTC_WaitForSynchro();
//等待最近一次對RTC寄存器的寫操作完成
RTC_WaitForLastTask();
//允許RTC的秒中斷(還有鬧鐘中斷和溢出中斷可設(shè)置)
RTC_ITConfig(RTC_IT_SEC, ENABLE);
//又是等待上一次對RTC寄存器的寫操作完成
RTC_WaitForLastTask();
//32768晶振預(yù)分頻值是32767,不過一般來說晶振都不那么準(zhǔn)
RTC_SetPrescaler(32776);//如果需要校準(zhǔn)晶振,可修改此分頻值
RTC_WaitForLastTask();
//寫入RTC后備寄存器1 0xa5a5
BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
RTC_Blank=1;/*這個標(biāo)志代表RTC是沒有預(yù)設(shè)的(或者說是沒有上紐扣電池) 用串口呀啥的輸出來。*/
}
//如果RTC已經(jīng)設(shè)置
else
{
//等待RTC與APB同步
RTC_WaitForSynchro();
RTC_WaitForLastTask();
//使能秒中斷
RTC_ITConfig(RTC_IT_SEC, ENABLE);//這句可以放到前面嗎?
RTC_WaitForLastTask();//又等....
}
//清除標(biāo)志
RCC_ClearFlag();
}
為啥要不停的等呢??
RTC核完全獨立于RTC APB1接口。 軟件通過APB1接口訪問RTC的預(yù)分頻值、計數(shù)器值和鬧鐘值。但是,相關(guān)的可讀寄存器只在與RTC APB1時鐘進(jìn)行重新同步的RTC時鐘的上升沿被更新。RTC標(biāo)志也是如此的。 這意味著,如果APB1接口曾經(jīng)被關(guān)閉,而讀操作又是在剛剛重新開啟APB1之后,則在第一次的內(nèi)部寄存器更新之前,從APB1上讀出的RTC寄存器數(shù)值可能被破壞了(通常讀到0)。
因此,若在讀取RTC寄存器時,RTC的APB1接口曾經(jīng)處于禁止?fàn)顟B(tài),則軟件首先必須等待RTC_CRL寄存器中的RSF位(寄存器同步標(biāo)志)被硬件置’1’。
注:RTC的 APB1接口不受WFI和WFE等低功耗模式的影響。
/*******************************************************************************
* Function Name : RTC_IRQHandler RTC中斷
* Description :
* Input : None
* Output : None
* Return : None
*******************************************************************************/
extern volatile bool Sec;//1S標(biāo)志
void RTC_IRQHandler(void)
{
if(RTC_GetITStatus(RTC_IT_SEC) != RESET)//RTC發(fā)生了秒中斷(也有可能是溢出或者鬧鐘中斷)
/*RTC_IT_OW溢出中斷/RTC_IT_ALR鬧鐘中斷/RTC_IT_SEC秒中斷*/
{
RTC_ClearITPendingBit(RTC_IT_SEC);
Sec=TRUE;
//以免RTC計數(shù)溢出,這里限制了RTC計數(shù)值的大小.0x0001517f實際就是一天的秒數(shù)
if(RTC_GetCounter() >= 0x0001517f)
{
RTC_SetCounter(0x0);
RTC_WaitForLastTask();
}
}
}
#include"STM32Lib\stm32f10x.h"
#include"hal.h"
volatilebool Sec=FALSE;
int main(void)
{
ChipHalInit();//片內(nèi)硬件初始化
ChipOutHalInit();//片外硬件初始化
TestRtc();//測試RTC
for(;;)
{
if(Sec==TRUE)
{
Sec=FALSE;
GPIOA->ODR^=GPIO_Pin_8;//閃燈
}
}
}
最簡單 最基層的CRT寫好了..........其實還有好多很酷的功能 比如是否掉電重啟 是否是SeSET 復(fù)位 等 應(yīng)該在CRT前 都檢測好........
評論