您的位置 首页 电源

stm32 使用备份寄存器保存实时时钟数据

在实际应用中,会出现许多复位或者掉电的情况,下面提供了一种方法使即使是在掉电和复位事件发生时,仍旧可以利用低功耗模式继续对于实时时…

在实践使用中,会呈现许多复位或许掉电的状况,下面供给了一种办法使即使是在掉电和复位事情产生时,依旧能够使用低功耗形式持续关于实时时钟进行供电,确保时钟的正常运转!

//bsp_rtc.h#ifndef _BSP_RTC_H#define _BSP_RTC_H#include "misc.h"/*全局变量*/	   uint8_t RTCInterruptFlag=0;	 //RTC 中止标志uint32_t RTC_TimeNum=0;			  // 设置时刻变量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;	// 用于显现测验 每次进入中止改动  /**\Function      RTC_NVIconfigration()*\Description   设置RTC中止优先级*\Parameter     void*\Return        void*\Note          *\Log          	2014年7月24日*/void RTC_NVIconfigration(void){NVIC_InitTypeDef NVIC_InitStructure;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);	  //现已在bsp_usart.c进行了设置/* 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装备函数*\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区域 */PWR_BackupAccessCmd(ENABLE);/* 复位BKP */BKP_DeInit();#ifdef RTCClockSource_LSI/* 使能内部RTC时钟 */RCC_LSICmd(ENABLE);/* 等候RTC内部时钟安排妥当 */while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET){}/* 挑选RTC内部时钟为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();/* 设置RTC预分频 */#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实时时钟设置...");/*日历设置操作*/CalenderSet();BKP_WriteBackupRegister(BKP_DR2,GetYear());BKP_WriteBackupRegister(BKP_DR3,GetMonth());  BKP_WriteBackupRegister(BKP_DR4,GetDay());/*实时时钟设置操作:*/RTC_WaitForLastTask();RTC_SetCounter(RTC_TimeCollate());	// 进行设置RTC_WaitForLastTask();BKP_WriteBackupRegister(BKP_DR1,0x0229);}else{if (RCC_GetFlagStatus(RCC_FLAG_PORRST)!=RESET){printf("\r\n\n 掉电重启事情....");}else  if (RCC_GetFlagStatus(RCC_FLAG_PINRST)!=RESET){printf("\r\n\n 外部复位事情....");}printf("\r\n 等候时刻同步....");/*在备份寄存器中从头读出年月日*/Year=BKP_ReadBackupRegister(BKP_DR2);Month=BKP_ReadBackupRegister(BKP_DR3);Day=BKP_ReadBackupRegister(BKP_DR4);/*在读取RTC寄存器时,RTC的APB1接口从前处于禁止状况,则软件首要有必要等候RTC_CRL寄存器中的RSF 位(寄存器同步标志)被硬件置’1’ 。注:    RTC的 APB1 接口不受WFI和WFE等低功耗形式的影响。 */RTC_WaitForSynchro(); //  同步RTC_WaitForLastTask();RTC_ITConfig(RTC_IT_SEC,ENABLE);// 使能秒中止RTC_WaitForLastTask();}RCC_ClearFlag();}/////////硬件初始化/////////////////////////////////////////////////////////////////**\Function      GetYear()*\Description   取得年数*\Parameter     void*\Return        uint16_t Year*\Note          *\Log          2014年7月5日*     */uint16_t GetYear(){return Year;}/**\Function      GetMonth()*\Description   取得月数*\Parameter     void*\Return        uint8_t Month*\Note          *\Log          2014年7月5日*     */uint8_t GetMonth(){return Month;}/**\Function      GetDay()*\Description   取得月数*\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   挑选月份天数*\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   日历计数函数*\Parameter     void*\Return        void*\Note          *\Log          2014年7月5日*     */void  CalenderCount(void){if(Day>0&&Day12){Month=1;Year++;}Day=1;	} }/**\Function      CalenderInput()*\Description   用户日历校对输入函数*\Parameter     void*\Return        void*\Note          *\Log          2014年7月5日*     */uint8_t CalenderInput(){RTCInterruptFlag=0;RTC_TimeNum=0;RTC_ITConfig(RTC_IT_SEC,DISABLE);   // 失能能秒中止/* 避免榜首个字符无法宣布,封闭发送中止  */if (USART_GetITStatus(USART2,USART_IT_TXE)!=RESET){USART_ITConfig(USART2,USART_IT_TXE,DISABLE);}/*等候用户输入数据*/while (!RTCInterruptFlag){printf("");	}   RTC_ITConfig(RTC_IT_SEC,ENABLE);// 失能能秒中止	return RTC_TimeNum;}		   /**\Function      RTC_InputTime(uint32_t border)*\Description   用户时刻校时输入函数*\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);   // 失能能秒中止/* 避免榜首个字符无法宣布,封闭发送中止  */if (USART_GetITStatus(USART2,USART_IT_TXE)!=RESET){USART_ITConfig(USART2,USART_IT_TXE,DISABLE);}/*等候用户输入数据*/while (!RTCInterruptFlag){printf("");	// 个人了解,由于RTC时刻设置和数据输入都是用的USAET2 这样做是为了避免优先级被占用,不加的话while将不起作用}  printf("\n您键入的数值是:");   if (RTC_TimeNum > border){printf("\n\r请键入0到%d之间的数字", border);return 0xFF;}RTC_ITConfig(RTC_IT_SEC,ENABLE);// 失能能秒中止	return RTC_TimeNum;}/**\Function      void RTC_RxIntHandler()*\Description   RTC中止处理函数*\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);	// 设置时刻变量//  printf("当时的temp_data %d",RTC_Num);}					   if (USART_GetITStatus(USART2,USART_IT_TXE)!=RESET){USART_ITConfig(USART2,USART_IT_TXE,DISABLE);}			   }///////////以上为底层函数///////////////////////////////////////////////////////////////////////////////////////////**\Function      CalenderSet(void)*\Description   日历设置函数*\Parameter     void*\Return        void*\Note         用于串口输入 *\Log          2014年7月5日*     */void CalenderSet(void){printf("\n=========设置年月日=================:");printf("\n请输入年份:");Year=(uint16_t)CalenderInput()*100;Year=Year+CalenderInput();printf("\n您输入的年份是:%d",Year);printf("\n\n请输入月份:");Month=CalenderInput();printf("\n您输入的月份是:%d",Month);printf("\n\n请输入日期:");Day=CalenderInput();printf("\n您输入的日期是:%d",Day);}/* 名    称:uint32_t RTC_TimeCollate(void)* 功    能:时刻校对函数* 进口参数:无* 出口参数:uint32_t* 说    明:用于串口输入* 调用办法:/uint32_t RTC_TimeCollate(void){uint32_t Tmp_HH = 0xFF, Tmp_MM = 0xFF, Tmp_SS = 0xFF; printf("\r\n==============时刻设置=========================");printf("\r\n  请输入小时:");  while (Tmp_HH == 0xFF){Tmp_HH = RTC_InputTime(23);}printf(":  %d", Tmp_HH);printf("\r\n  请输入分钟:");while (Tmp_MM == 0xFF){Tmp_MM = RTC_InputTime(59);}printf(":  %d", Tmp_MM);printf("\r\n  请输入秒数:");while (Tmp_SS == 0xFF){Tmp_SS = RTC_InputTime(59);}printf(":  %d", Tmp_SS);		  /* 回来保存在RTC计数寄存器里的值 */return((Tmp_HH*3600 + Tmp_MM*60 + Tmp_SS));}	  /* 名    称:void RTC_TimeDisplay(uint32_t TimeVar)* 功    能:显现当时时刻* 进口参数:无* 出口参数:无* 说    明:* 调用办法:/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.2d\r\n",THH, TMM, TSS);}///////////以上为使用层函数//////////////////////////////////////////////////////////////////**\Function      RTC_text(void)*\Description   时刻显现*\Parameter     void*\Return        void*\Note          *\Log          	时刻*              */void RTC_text(void){printf("\n\r");while (1){/* 秒更新产生 */if(TimeDisplay == 1){/* 显现当时时刻 */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)				 //读取秒中止状况{RTC_ClearITPendingBit(RTC_IT_SEC);					 //铲除秒中止标志			    /* 时钟更新标志置位 */TimeDisplay = 1;	  RTC_WaitForLastTask();							     //等候上一次对RTC寄存器的写操作是否现已完结    if(RTC_GetCounter() == 0x0001517F)				     //当时时刻是23:59:59时 复位为0:0:0 	    {RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);PWR->CR|=1<<8;                  					 //撤销备份区写保护RTC_EnterConfigMode();						     //答应装备 	  				RTC_WaitForLastTask();                             //等候上一次对RTC寄存器的写操作是否现已完结 RTC_SetCounter(0x0);								 //写入复位值RTC_WaitForLastTask();							 //等候上一次对RTC寄存器的写操作是否现已完结 CalenderCount();BKP_WriteBackupRegister(BKP_DR2,GetYear());BKP_WriteBackupRegister(BKP_DR3,GetMonth());  BKP_WriteBackupRegister(BKP_DR4,GetDay());}else if(RTC_GetCounter() > 0x0001517F)				 //当再次上电后计数值超越0x00015180, 复位为当时值取模0x00015180。	    {RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);PWR->CR|=1<<8;                                     //撤销备份区写保护RTC_EnterConfigMode();			                 //答应装备 RTC_WaitForLastTask();                             //等候上一次对RTC寄存器的写操作是否现已完结    RTC_SetCounter(RTC_GetCounter()%0x0001517F);		 //写入复位值RTC_WaitForLastTask();							 //等候上一次对RTC寄存器的写操作是否现已完结 CalenderCount();BKP_WriteBackupRegister(BKP_DR2,GetYear());BKP_WriteBackupRegister(BKP_DR3,GetMonth());  BKP_WriteBackupRegister(BKP_DR4,GetDay());}}}

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/dianyuan/276599.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部