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("rnn 掉电重启事件....");}else if (RCC_GetFlagStatus(RCC_FLAG_PINRST)!=RESET){printf("rnn 外部复位事件....");}printf("rn 等待时间同步....");/*在备份寄存器中重新读出年月日*/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("nr请键入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("nn请输入月份:");Month=CalenderInput();printf("n您输入的月份是:%d",Month);printf("nn请输入日期:");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("rn==============时间设置=========================");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 请输入秒数:");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.2drn",THH, TMM, TSS);}///////////以上为应用层函数//////////////////////////////////////////////////////////////////**Function RTC_text(void)*Description 时间显示*Parameter void*Return void*Note *Log 时间* */void RTC_text(void){printf("nr");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());}}}
评论