天天看點

STM32-(27):RTC實時時鐘

上一篇:STM32-(26):RCC内部結構與原理分析 下一篇:STM32-(28):ADC模數轉換(理論分析)

實時時鐘的縮寫是RTC(Real_Time Clock)

實時時鐘是一個獨立的定時器。RTC子產品擁有一組連續計數的計數器,在相應軟體配置下,可提供時鐘月曆的功能。修改計數器的值可以重新設定系統目前的時間和日期

RTC由兩個主要部分組成。第一部分(APB1接口)用來和APB1總線相連。此單元還包含一組16位寄存器,可通過APB1總線對其進行讀寫操作。APB1接口以APB1總線時鐘為時鐘。

另一部分(RTC核)由一系列可程式設計計數器組成,分成兩個主要子產品:

第一個子產品是RTC的預分頻子產品,它可程式設計産生最長為1秒的RTC時間基準TR_CLK,RTC的預分頻子產品包含了一個20位的可程式設計分頻器(RTC預芬頻器)。在每個TR_CLK周期中,如果在RTC_CR寄存器中設定了相應允許位,則RTC盧生一個中斷(秒中斷)。

第二個子產品是一個32位的可程式設計的計數器,它可以被初始化為目前的系統時間。系統時間以TR_CLK速度增長并與存儲在RTC_ALR寄存器中的可程式設計的時間相比較,如果RTC_CR控制寄存器設定了相應允許位則比較比對時将産生一個鬧鐘中斷。

STM32-(27):RTC實時時鐘

分析

RTCCLK 外部低速時鐘信号進來,先進入 RTC_DIV(分頻器),RTC_PRL是裝載器,然後得到一個 TR_CLK的信号,這個信号嚴格來說是 1s來一次,産生精确的秒信号,秒信号一路可以通過 RTC_Second,産生一個 RTC_CR 的标志位 SECF,當 SECIE 打開了(這個相當于一個開關,這個信号燈額中斷允許位,表示允許秒信号輸入),(SECF和SECIE是與的關系)就會産生一個中斷;秒信号也可以輸入到後面的 RTC_CNT計數器,這個計數器可以進行32位(2的32次方)的程式設計控制,當計數器寄存器的值達到設定的值就會産生 RTC_Overflow 信号,後面的 OWIE 如果打開,也會産生中斷;如果設定的 RTC_ALR的值(報警),當計數器寄存器的值等于報警相關寄存器設定值,就會産生鬧鐘信号 RTC_Alarm,同時 ALRIE 打開,就會産生中斷。這三種信号産生的中斷就會進入下方的 NVIC INTERRUPT CONTRCLLER(中斷控制器),相當于強制讓CPU處理這個中斷信号。 RTC_Alarm 和 WKUP_pin是或的關系,有任何一個信号,就會産生中斷或者 進入 EXIT FROM ,就是從 常置狀态跳出 ,喚醒CPU的意思;上方一整個灰色陰影區域表示這塊區域的工作不是由VCC電源直接供電的(當然也可以由VCC供電),當VCC電源無效的時候或者說CPU沒有工作的時候,是由後備電池供電的,這個區域稱為“後備區”,系統在斷電複位的情況下,不會影響後備區。比如手機電腦關機開機後,時間顯示總是正确的。

主要特性

**可程式設計的預分頻系數:**分頻系數最髙為220

32位的可程式設計計數器,可用于較長命間段的測量。

2個單獨的時鐘,用于APB1接口的PCLK1和RTC時鐘(此時的RTC時鐘必須小于PCLK1時鐘的四分之一以上)

2種獨立的複位類型:

APB1接口由系統複位

RTC隻能由後備域複位

3個專門的可屏蔽中斷 :

鬧鐘中斷,用來産生一個軟體可程式設計的鬧鐘中斷。

秒中斷,用來産生一個可程式設計的周期性中斷信号

溢出中斷,檢測内部可程式設計計數器溢出并回轉為0的狀态。

RTC 的一些設定是儲存在後備域中的: RTC_PRL,RTC_ALR,RTC_CNT 和 RTC_DIV 寄存器。

這些寄存器器僅能通過備份域複位信号複位,不受系統複位或電源複位的影響。

備份域複位

當以下事件中之一發生時,産生備份區域複位。

  1. 軟體複位,備份區域複位可由設定備份區域控制寄存器 RCC _ BDCR 中的 BDRST 位産生。
  2. 在 VDD 和 VBAT 兩者掉電的前提下, VDD 或 VBAT 上電将引發備份區域複位。

對相關寄存器操作流程

要對 RTC_PRL . RTC_CNT . RTC_ALR 寄存器進行寫操作, RTC 必須進入配置模式。通過對 RTC_CRL寄存器中的 CNF 位置位使 RTC 進入配置模式。另外,對 RTC 的任何寄存器的寫操作都必須在前一次寫操作結束以後進行。要使用軟體來查詢目前的狀态,同可通過查詢 RTC_CR 寄存器中的 RTOFF狀态位來判斷 RTC 寄存器是否處于更新中,僅當 RTOFF 狀态位是“1”時,RTC 寄存器可以寫入新的值。

配置過程:

  1. 查詢 RTOFF 位,直到 RTOFF 的值變為“ 1 ”
  2. 置 CNF 值 為1 , 進入配置模式
  3. 對一個或多個 RTC 寄存器進行寫操作
  4. 清除 CNF 标志位,退出配置模式
  5. 查詢 RTOFF,直至RTOFF位變為“1”以确認寫操作已經完成。

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

RTC相關寄存器

RTC_CRH

STM32-(27):RTC實時時鐘

OWIE:允許溢出中斷位

0:屏蔽(不允許)溢出中斷

1:允許溢出中斷

ALRIE:允許鬧鐘中斷

0:屏蔽(不允許)鬧鐘中斷

1:允許鬧鐘中斷

SECIE:允許秒中斷

0:屏蔽(不允許)秒中斷

1:允許秒中斷

RTC_CRL

STM32-(27):RTC實時時鐘

RTOFF: RTC操作關閉

RTC子產品利用這位來訓示對其寄存器進行的最後一次操作的狀态,訓示操作是否完成。若此位為0,則無法對任何的RTC寄存器進行寫操作。此位為隻讀位。

0:上一次對RTC寄存器的寫操作仍在進行;

1:上一次對RTC寄存器的寫操作已經完成。

CNF:配置标志

此位必須由軟體置1以進入配置模式,進而允許向RTC_CNT、RTC_ALR或RTC_PRL寄存器寫入資料。隻有當此位在被置1後,并重新由軟體清0後,才會執行寫操作。

0:退出配置模式(開始更新RTC寄存器);

1:進入配置模式。

RSF:寄存器同步标志

每當RTC_CNT寄存器和RTC_DIV寄存器由軟體重新整理或清0時,此位由硬體置1。在APB1複位後,或APB1時鐘停止後,此位必須由軟體清0。要進行任何的讀操作之前,使用者程式必須等待這位被硬體置1,以確定RTC_CNT、RTC_ALR或RTC_PRL已經被同步。

0:寄存器尚未被同步;

1:寄存器已經被同步。

OWF:溢出标志

當32位可程式設計計數器溢出時,此位由硬體置1。如果RTC_CRH寄存器中OWIE=1,則産生中斷。此位隻能由軟體清0。對此位寫1是無效的。

0:無溢出;

1:32位可程式設計計數器溢出。

ALRF:鬧鐘标志

當32位可程式設計計數器達到RTC_ALR寄存器所設定的門限值,此位由硬體置1。如果RTC_CRH寄存器中ALRIE=1,則産生中斷。此位隻能由軟體清0。對此位寫1是無效的。

0:無鬧鐘;

1:有鬧鐘。

SECF:秒标志

當32位可程式設計預分頻器溢出時,此位由硬體置1,RTC計數器遞增。是以,此标志為分辨率可程式設計的RTC計數器提供一個周期性的信号(通常為1秒)。如果RTC_CRH寄存器中SECIE=1,則産生中斷。此位隻能由軟體清除。對此位寫“1”是無效的。

0:秒标志條件不成立;

1:秒标志條件成立。

RTC 計數器寄存器 (RTC_CNTH / RTC_CNTL)

RTC核有一個32位可程式設計的計數器,可通過兩個16位的寄存器通路。計數器以預分頻器産生的TR_CLK時間基準為參考進行計數。RTC_CNT寄存器用來存放計數器的計數值。他們被RTC_CR上的位RTOFF寫保護,并且如果RTOFF值是1的話,允許寫操作。在高或低寄存器(RTC_CNTH或RTC_CNTL)上的寫操作,能夠直接裝載到相應的可程式設計計數器,并且重新裝載RTC預分頻器。當進行讀操作時,直接傳回計數器内的計數值(系統時間)。

RTC 鬧鐘寄存器(RTC_ALRH/RTC_ALRL )

當可程式設計計數器的值與RTC_ALR中的32位值相等時,即觸發一個鬧鐘事件,并且産生RTC鬧鐘中斷。此寄存器被RTC_CR寄存器裡的RTOFF位寫保護,如果RTOFF值是1時,允許寫操作。

相關庫函數

STM32-(27):RTC實時時鐘
STM32-(27):RTC實時時鐘

代碼塊

main.c

/*Includes----------------------------------*/
#include"stm32f10x_lib.h"		//包含所用的頭檔案
#include<stdio.h>

//----------------外部函數的聲明------------------------------
extern void SMG_Init(void);
extern void SMG_Display(u32 data,u8 dot);  //數位管函數的聲明(包含SPI函數的聲明)
extern void RTC_Configuration(void);
//---------------------函數的聲明---------------------------
void Delay_Ms(u16 time);
void RCC_Configuration(void);
void NVIC_Configuration(void);

extern vu8 Count;

/* Private functions ---------------------------------------------------------*/ 
/*******************************************************************************
* Function Name  : main
* Description    : Main program.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
int main(void)
{
	#ifdef DEBUG
		debug();
	#endif
   RCC_Configuration();
   RTC_Configuration();
   SMG_Init();
   NVIC_Configuration();

   while(1)
   {
   		SMG_Display(Count,3);	
   }

}

/*******************************************************************************
* Function Name  : Delay_Ms
* Description    : delay 1 ms.
* Input          : time (ms)
* Output         : None
* Return         : None
*******************************************************************************/
void Delay_Ms(u16 time)  //延時函數
{ 
	u16 i,j;
	for(i=0;i<time;i++)
  		for(j=10000;j>0;j--);
}
 /*******************************************************************************
* Function Name  : RCC_Configuration
* Description    : Configures the different system clocks.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void RCC_Configuration(void)
{
	//-----------使用外部RC晶振-----------------
	RCC_DeInit();			//初始化為預設值狀态
	RCC_HSEConfig(RCC_HSE_ON);	
	while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);

	FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
	FLASH_SetLatency(FLASH_Latency_2);

	RCC_HCLKConfig(RCC_SYSCLK_Div1);
	RCC_PCLK2Config(RCC_HCLK_Div1);
	RCC_PCLK1Config(RCC_HCLK_Div2);

	RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);
	RCC_PLLCmd(ENABLE);
	while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

	RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
	while(RCC_GetSYSCLKSource()!=0x08);
}

void NVIC_Configuration(void)
{
	NVIC_InitTypeDef	NVIC_InitStructure;
	
#ifdef VECT_TAB_RAM
	NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);
#else
	NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);
#endif

	//Configure one bit for preemption priority
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQChannel;	//設定RTC中斷
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //設定先優先級為 1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //設定亞優先級為0
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;	   //中斷使能
	NVIC_Init(&NVIC_InitStructure);	 //初始化		
}
           

RTC.c

/********************************************************************
* 檔案 :RTC.c
* 描述 : 實時時鐘RTC子產品的配置
********************************************************************/
#include"stm32f10x_lib.h"
/*************************************************************************************
**名稱		;void RTC_Configuration(void)
**功能		;RTC實時時鐘的配置
**入口參數	;無
**出口參數	;無
*************************************************************************************/
void RTC_Configuration(void)
{
	/* Enable PWR and BKP clocks */   //使能APB1外設PWR and BKP 的時鐘  (打開電源與後備電源)
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE);
	
	/* Allow access to BKP Domain*/  //允許RTC 和後備寄存器的通路
	PWR_BackupAccessCmd(ENABLE);
	
	/* Reset Backup Domain*/		//将外設BKP的全部 寄存器重設為預設值
	BKP_DeInit();
	
	/* Enable LSE */				//設定外部低速時鐘
   	RCC_LSEConfig(RCC_LSE_ON);
	
	/* Wait till LSE is ready */		//等待外部低速時鐘準備好
	while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
	
	/* Select LSE as RTC Clock Source */	//設定LSE為RTC時鐘
	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
	
	/* Enable RTC Clock */				//使能RT時鐘
	RCC_RTCCLKCmd(ENABLE);

	/* Wait for RTC registers synchronization *///等待RTC寄存器(RTC_CNT,RTC_ALR and RTC_PRL)與RTC的APB時鐘同步
	RTC_WaitForSynchro();

	/* Wait untill last write operation on RTC register has finised *///等待最近一次對RTC的寫操作完成
	RTC_WaitForLastTask();

   /* Enable the RTC Second interrup */	//使能RTC的秒中斷
   RTC_ITConfig(RTC_IT_SEC,ENABLE);

   /* Wait untill last write operation on RTC register has finised *///等待最近一次對RTC的寫操作完成
	RTC_WaitForLastTask();

   /* Set RTC prescaler : set RTC period to 1 sec*/		//設定RTC預分頻的值 為32767,則計數頻率 = (32.768 KHz)/(32767+1) = 1Hz(~1s)
   RTC_SetPrescaler(32767);

    /* Wait untill last write operation on RTC register has finised *///等待最近一次對RTC的寫操作完成
	RTC_WaitForLastTask();
			
}

           
上一篇:STM32-(26):RCC内部結構與原理分析 下一篇:STM32-(28):ADC模數轉換(理論分析)

繼續閱讀