新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > stm32 利用備份寄存器保存實時時鐘數(shù)據(jù)

stm32 利用備份寄存器保存實時時鐘數(shù)據(jù)

作者: 時間:2016-11-09 來源:網(wǎng)絡(luò) 收藏
在實際應(yīng)用中,會出現(xiàn)許多復(fù)位或者掉電的情況,下面提供了一種方法使即使是在掉電和復(fù)位事件發(fā)生時,仍舊可以利用低功耗模式繼續(xù)對于實時時鐘進(jìn)行供電,保證時鐘的正常運(yùn)行!


本文引用地址:http://butianyuan.cn/article/201611/317634.htm

//bsp_rtc.h#ifndef _BSP_RTC_H#define _BSP_RTC_H#include "misc.h"/*全局變量*/	   uint8_t RTCInterruptFlag=0;	 //RTC 中斷標(biāo)志uint32_t RTC_TimeNum=0;			  // 設(shè)置時間變量uint16_t Year;uint8_t Month;uint8_t Day;/* RTC hardware init*/void RTC_NVIconfigration(void);void RTC_configration(void);void RTC_Init(void);/*日歷及時間輸入*/uint8_t RTC_InputTime(uint32_t border);uint32_t RTC_TimeCollate(void);void RTC_RxIntHandler(void); /*獲得年月日*/uint16_t GetYear();uint8_t GetMonth();uint8_t GetDay();void CalenderSet(void);void  CalenderCount(void);static uint8_t Choice_MonthDay(uint16_t temp_year,uint8_t temp_month);/*顯示*/void RTC_TimeDisplay(uint32_t TimeVar);/*測試*/void Text_RTC(void); #endif/*_BSP_RTC_H*/

bsp_rtc.c

#include "bsp_rtc.h"#define RTCClockSource_LSEuint32_t TimeDisplay=0;	// 用于顯示測試 每次進(jìn)入中斷改變  /**Function      RTC_NVIconfigration()*Description   設(shè)置RTC中斷優(yōu)先級*Parameter     void*Return        void*Note          *Log          	2014年7月24日*/void RTC_NVIconfigration(void){NVIC_InitTypeDef NVIC_InitStructure;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);	  //已經(jīng)在bsp_usart.c進(jìn)行了設(shè)置/* Enable the RTC Interrupt */NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;					//配置外部中斷源(秒中斷)NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);}/**Function      RTC_configration(void)*Description   RTC配置函數(shù)*Parameter     void*Return        void*Note          *Log          	2014年7月24日*/void RTC_configration(void){/* 使能 PWR 和 BKP 的時鐘 */RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);PWR_DeInit();/* 允許訪問BKP區(qū)域 */PWR_BackupAccessCmd(ENABLE);/* 復(fù)位BKP */BKP_DeInit();#ifdef RTCClockSource_LSI/* 使能內(nèi)部RTC時鐘 */RCC_LSICmd(ENABLE);/* 等待RTC內(nèi)部時鐘就緒 */while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET){}/* 選擇RTC內(nèi)部時鐘為RTC時鐘 */RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);#elif defined	RTCClockSource_LSE/* 使能RTC外部時鐘 */RCC_LSEConfig(RCC_LSE_ON);/* 等待RTC外部時鐘就緒 */while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET){}/* 選擇RTC外部時鐘為RTC時鐘 */RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);#endif/* 使能RTC時鐘 */RCC_RTCCLKCmd(ENABLE);#ifdef RTCClockOutput_Enable/* Disable the Tamper Pin */BKP_TamperPinCmd(DISABLE); /* To output RTCCLK/64 on Tamper pin, the tamperfunctionality must be disabled *//* 使能在TAMPER腳輸出RTC時鐘 */BKP_RTCCalibrationClockOutputCmd(ENABLE);#endif/* 等待RTC寄存器同步 */RTC_WaitForSynchro();/* 等待寫RTC寄存器完成 */RTC_WaitForLastTask();/* 使能RTC秒中斷 */RTC_ITConfig(RTC_IT_SEC, ENABLE);/* 等待寫RTC寄存器完成 */RTC_WaitForLastTask();/* 設(shè)置RTC預(yù)分頻 */#ifdef RTCClockSource_LSIRTC_SetPrescaler(31999);            /* RTC period = RTCCLK/RTC_PR = (32.000 KHz)/(31999+1) */#elif defined	RTCClockSource_LSERTC_SetPrescaler(32767);            /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */#endif/* 等待寫RTC寄存器完成 */RTC_WaitForLastTask();}/**Function      RTC_Init(void)*Description   RTC初始化*Parameter     void*Return        void*Note          *Log          	2014年7月24日*/void RTC_Init(void){if (BKP_ReadBackupRegister(BKP_DR1)!=0x0229){//printf("n RTC not yet configured....");RTC_configration();printf("n RTC實時時鐘設(shè)置...");/*日歷設(shè)置操作*/CalenderSet();BKP_WriteBackupRegister(BKP_DR2,GetYear());BKP_WriteBackupRegister(BKP_DR3,GetMonth());  BKP_WriteBackupRegister(BKP_DR4,GetDay());/*實時時鐘設(shè)置操作:*/RTC_WaitForLastTask();RTC_SetCounter(RTC_TimeCollate());	// 進(jìn)行設(shè)置RTC_WaitForLastTask();BKP_WriteBackupRegister(BKP_DR1,0x0229);}else{if (RCC_GetFlagStatus(RCC_FLAG_PORRST)!=RESET){printf("rnn 掉電重啟事件....");}else  if (RCC_GetFlagStatus(RCC_FLAG_PINRST)!=RESET){printf("rnn 外部復(fù)位事件....");}printf("rn 等待時間同步....");/*在備份寄存器中重新讀出年月日*/Year=BKP_ReadBackupRegister(BKP_DR2);Month=BKP_ReadBackupRegister(BKP_DR3);Day=BKP_ReadBackupRegister(BKP_DR4);/*在讀取RTC寄存器時,RTC的APB1接口曾經(jīng)處于禁止?fàn)顟B(tài),則軟件首先必須等待RTC_CRL寄存器中的RSF 位(寄存器同步標(biāo)志)被硬件置’1’ 。注:    RTC的 APB1 接口不受WFI和WFE等低功耗模式的影響。 */RTC_WaitForSynchro(); //  同步RTC_WaitForLastTask();RTC_ITConfig(RTC_IT_SEC,ENABLE);// 使能秒中斷RTC_WaitForLastTask();}RCC_ClearFlag();}/////////硬件初始化/////////////////////////////////////////////////////////////////**Function      GetYear()*Description   獲得年數(shù)*Parameter     void*Return        uint16_t Year*Note          *Log          2014年7月5日*     */uint16_t GetYear(){return Year;}/**Function      GetMonth()*Description   獲得月數(shù)*Parameter     void*Return        uint8_t Month*Note          *Log          2014年7月5日*     */uint8_t GetMonth(){return Month;}/**Function      GetDay()*Description   獲得月數(shù)*Parameter     void*Return        uint8_t Day*Note          *Log          2014年7月5日*     */uint8_t GetDay(){  return Day; }/**Function      Choice_MonthDay(uint16_t temp_year,uint8_t temp_month)*Description   選擇月份天數(shù)*Parameter     uint16_t temp_year  *Parameter     uint8_t temp_month*Return        Month_day*Note          *Log          2014年7月5日*     */static uint8_t Choice_MonthDay(uint16_t temp_year,uint8_t temp_month){uint8_t	Month_day=0;switch(temp_month){case 1:case 3:case 5:case 7:case 8:	case 10:case 12:Month_day=31;break;case 4:	case 6:	case 9:	case 11:Month_day=30;break;case 2:if(temp_year%4==0&&temp_year%100!=0||temp_year%400==0)Month_day=29;elseMonth_day=28;default:break;		 	}return Month_day;}/**Function      CalenderCount()*Description   日歷計數(shù)函數(shù)*Parameter     void*Return        void*Note          *Log          2014年7月5日*     */void  CalenderCount(void){if(Day>0&&Day12){Month=1;Year++;}Day=1;	} }/**Function      CalenderInput()*Description   用戶日歷校對輸入函數(shù)*Parameter     void*Return        void*Note          *Log          2014年7月5日*     */uint8_t CalenderInput(){RTCInterruptFlag=0;RTC_TimeNum=0;RTC_ITConfig(RTC_IT_SEC,DISABLE);   // 失能能秒中斷/* 防止第一個字符無法發(fā)出,關(guān)閉發(fā)送中斷  */if (USART_GetITStatus(USART2,USART_IT_TXE)!=RESET){USART_ITConfig(USART2,USART_IT_TXE,DISABLE);}/*等待用戶輸入數(shù)據(jù)*/while (!RTCInterruptFlag){printf("");	}   RTC_ITConfig(RTC_IT_SEC,ENABLE);// 失能能秒中斷	return RTC_TimeNum;}		   /**Function      RTC_InputTime(uint32_t border)*Description   用戶時間校時輸入函數(shù)*Parameter     uint32_t border	   邊界大小*Return        uint8_t*Note          *Log          	2014年7月24日*/uint8_t RTC_InputTime(uint32_t border){RTCInterruptFlag=0;RTC_TimeNum=0;RTC_ITConfig(RTC_IT_SEC,DISABLE);   // 失能能秒中斷/* 防止第一個字符無法發(fā)出,關(guān)閉發(fā)送中斷  */if (USART_GetITStatus(USART2,USART_IT_TXE)!=RESET){USART_ITConfig(USART2,USART_IT_TXE,DISABLE);}/*等待用戶輸入數(shù)據(jù)*/while (!RTCInterruptFlag){printf("");	// 個人理解,因為RTC時間設(shè)置和數(shù)據(jù)輸入都是用的USAET2 這樣做是為了防止優(yōu)先級被占用,不加的話while將不起作用}  printf("n您鍵入的數(shù)值是:");   if (RTC_TimeNum > border){printf("nr請鍵入0到%d之間的數(shù)字", border);return 0xFF;}RTC_ITConfig(RTC_IT_SEC,ENABLE);// 失能能秒中斷	return RTC_TimeNum;}/**Function      void RTC_RxIntHandler()*Description   RTC中斷處理函數(shù)*Parameter     void*Return        void*Note          *Log          	2014年7月24日*               放在中斷處理中*/void RTC_RxIntHandler(void){uint32_t temp_data;RTCInterruptFlag=1;if (USART_GetFlagStatus(USART2,USART_IT_RXNE)!=RESET){temp_data=(USART_ReceiveData(USART2));RTC_TimeNum=(temp_data>>4)*10+(temp_data&0x0F);	// 設(shè)置時間變量//  printf("當(dāng)前的temp_data %d",RTC_Num);}					   if (USART_GetITStatus(USART2,USART_IT_TXE)!=RESET){USART_ITConfig(USART2,USART_IT_TXE,DISABLE);}			   }///////////以上為底層函數(shù)///////////////////////////////////////////////////////////////////////////////////////////**Function      CalenderSet(void)*Description   日歷設(shè)置函數(shù)*Parameter     void*Return        void*Note         用于串口輸入 *Log          2014年7月5日*     */void CalenderSet(void){printf("n=========設(shè)置年月日=================:");printf("n請輸入年份:");Year=(uint16_t)CalenderInput()*100;Year=Year+CalenderInput();printf("n您輸入的年份是:%d",Year);printf("nn請輸入月份:");Month=CalenderInput();printf("n您輸入的月份是:%d",Month);printf("nn請輸入日期:");Day=CalenderInput();printf("n您輸入的日期是:%d",Day);}/* 名    稱:uint32_t RTC_TimeCollate(void)* 功    能:時間校正函數(shù)* 入口參數(shù):無* 出口參數(shù):uint32_t* 說    明:用于串口輸入* 調(diào)用方法:/uint32_t RTC_TimeCollate(void){uint32_t Tmp_HH = 0xFF, Tmp_MM = 0xFF, Tmp_SS = 0xFF; printf("rn==============時間設(shè)置=========================");printf("rn  請輸入小時:");  while (Tmp_HH == 0xFF){Tmp_HH = RTC_InputTime(23);}printf(":  %d", Tmp_HH);printf("rn  請輸入分鐘:");while (Tmp_MM == 0xFF){Tmp_MM = RTC_InputTime(59);}printf(":  %d", Tmp_MM);printf("rn  請輸入秒數(shù):");while (Tmp_SS == 0xFF){Tmp_SS = RTC_InputTime(59);}printf(":  %d", Tmp_SS);		  /* 返回保存在RTC計數(shù)寄存器里的值 */return((Tmp_HH*3600 + Tmp_MM*60 + Tmp_SS));}	  /* 名    稱:void RTC_TimeDisplay(uint32_t TimeVar)* 功    能:顯示當(dāng)前時間* 入口參數(shù):無* 出口參數(shù):無* 說    明:* 調(diào)用方法:/void RTC_TimeDisplay(uint32_t TimeVar){uint32_t THH = 0, TMM = 0, TSS = 0;/* 計算小時 */THH = TimeVar/3600;/* 計算分鐘 */TMM = (TimeVar % 3600)/60;/* 計算秒 */TSS = (TimeVar % 3600)% 60;printf("n%d年 %d月 %d日  ",Year,Month,Day);printf("Time: %0.2d:%0.2d:%0.2drn",THH, TMM, TSS);}///////////以上為應(yīng)用層函數(shù)//////////////////////////////////////////////////////////////////**Function      RTC_text(void)*Description   時間顯示*Parameter     void*Return        void*Note          *Log          	時間*              */void RTC_text(void){printf("nr");while (1){/* 秒更新發(fā)生 */if(TimeDisplay == 1){/* 顯示當(dāng)前時間 */RTC_TimeDisplay(RTC_GetCounter());TimeDisplay = 0;}}}


stm32f10x_it.c
/** Function Name  : RTC_IRQHandler* Description    : This function handles RTC global interrupt request.* Input          : None* Output         : None* Return         : None*/void RTC_IRQHandler(void){if(RTC_GetITStatus(RTC_IT_SEC) != RESET)				 //讀取秒中斷狀態(tài){RTC_ClearITPendingBit(RTC_IT_SEC);					 //清除秒中斷標(biāo)志			    /* 時鐘更新標(biāo)志置位 */TimeDisplay = 1;	  RTC_WaitForLastTask();							     //等待上一次對RTC寄存器的寫操作是否已經(jīng)完成    if(RTC_GetCounter() == 0x0001517F)				     //當(dāng)前時間是23:59:59時 復(fù)位為0:0:0 	    {RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);PWR->CR|=1<<8;                  					 //取消備份區(qū)寫保護(hù)RTC_EnterConfigMode();						     //允許配置 	  				RTC_WaitForLastTask();                             //等待上一次對RTC寄存器的寫操作是否已經(jīng)完成 RTC_SetCounter(0x0);								 //寫入復(fù)位值RTC_WaitForLastTask();							 //等待上一次對RTC寄存器的寫操作是否已經(jīng)完成 CalenderCount();BKP_WriteBackupRegister(BKP_DR2,GetYear());BKP_WriteBackupRegister(BKP_DR3,GetMonth());  BKP_WriteBackupRegister(BKP_DR4,GetDay());}else if(RTC_GetCounter() > 0x0001517F)				 //當(dāng)再次上電后計數(shù)值超過0x00015180, 復(fù)位為當(dāng)前值取模0x00015180。	    {RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);PWR->CR|=1<<8;                                     //取消備份區(qū)寫保護(hù)RTC_EnterConfigMode();			                 //允許配置 RTC_WaitForLastTask();                             //等待上一次對RTC寄存器的寫操作是否已經(jīng)完成    RTC_SetCounter(RTC_GetCounter()%0x0001517F);		 //寫入復(fù)位值RTC_WaitForLastTask();							 //等待上一次對RTC寄存器的寫操作是否已經(jīng)完成 CalenderCount();BKP_WriteBackupRegister(BKP_DR2,GetYear());BKP_WriteBackupRegister(BKP_DR3,GetMonth());  BKP_WriteBackupRegister(BKP_DR4,GetDay());}}}


評論


技術(shù)專區(qū)

關(guān)閉