#include "rtc.h" #include #include #include "stm32f10x_pwr.h" #include "stm32f10x_bkp.h" #include "stm32f10x_rtc.h" #include "stm32f10x_exti.h" /*********应用层外部调用文件**************/ #include "systick.h" #include "userport.h" /*****************************************/ Calendar_u uCalendar ; uint8_t const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表 const uint8_t mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31}; //平年的月份日期表 /************************************************************************************************** * 名 称: static void RTC_NVIC_Config(void) * 功能说明: RTC时钟中断和RTC闹钟中断优先级管理 *************************************************************************************************/ static void RTC_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure ; NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn ; //RTC中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = RTC_IRQn_PreemptionPriority ; //设置抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = RTC_IRQn_SubPriority ; //设置子优先级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE ; //使能该通道中断 NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 // NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn ; //RTCAlarm中断 // NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = RTCAlarm_IRQn_PreemptionPriority ; //设置抢占优先级 // NVIC_InitStructure.NVIC_IRQChannelSubPriority = RTCAlarm_IRQn_SubPriority ; //设置子优先级 // NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道 // NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 } /************************************************************************************************** * 名 称: RunResult RTC_Init(void) * 外部引用: ErrorLogPrintf * 功能说明: 初始化RTC功能块 * 出口参数: RunResult: 反映处理结果 * 说 明: 当LSE失效会启用LSI作为RTC时钟,LSI频率漂移大可能会导致走时不准的问题 *************************************************************************************************/ RunResult RTC_Init(void) { u8 temp=0; RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟 PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问 if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050) //从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎 { BKP_DeInit(); //复位备份区域 RCC_LSEConfig(RCC_LSE_ON); //设置外部低速晶振(LSE),使用外设低速晶振 while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250) //检查指定的RCC标志位设置与否,等待低速晶振就绪 { temp++; Delay_Ms(10); } if(temp>=250)return RunErr;//初始化时钟失败,晶振有问题 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟 RCC_RTCCLKCmd(ENABLE); //使能RTC时钟 RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 RTC_WaitForSynchro(); //等待RTC寄存器同步 RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断 RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 RTC_EnterConfigMode();/// 允许配置 RTC_SetPrescaler(32767); //设置RTC预分频的值 RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 Calendar_u uCalendar2 ; memcpy(uCalendar2.bytes, (const u8*)"2017-09-21 14:40:00", 19) ; RTC_Set(&uCalendar2) ; RTC_ExitConfigMode(); //退出配置模式 BKP_WriteBackupRegister(BKP_DR1, 0X5050); //向指定的后备寄存器中写入用户程序数据 } else//系统继续计时 { RTC_WaitForSynchro(); //等待最近一次对RTC寄存器的写操作完成 RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断 RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 } RTC_NVIC_Config();//RCT中断分组设置 //RTC_Get();//更新时间 return RunOK; //ok } /************************************************************************************************** * 名 称: void RTC_IRQHandler(void) * 功能说明: RTC时钟中断 * 说 明: 每秒触发一次中断 *************************************************************************************************/ void RTC_IRQHandler(void) { if ( RTC_GetITStatus(RTC_IT_SEC) != RESET )//秒钟中断 { RTC_ClearITPendingBit(RTC_IT_SEC); //清秒中断 RTC_Get(&uCalendar); //更新时间 } if( RTC_GetITStatus(RTC_IT_ALR)!= RESET ) //闹钟中断 { RTC_ClearITPendingBit(RTC_IT_ALR); //清闹钟中断 EXTI_ClearITPendingBit(EXTI_Line17); } RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW|RTC_IT_SEC); //清中断 RTC_WaitForLastTask() ; } /************************************************************************************************** * 名 称: void RTCAlarm_IRQHandler(void) * 功能说明: RTC闹钟中断 * 说 明: RTC计数器到达RTC->ALR值时发生中断。 注意:RTC闹钟中断挂载在EXTI_Line17中断线上的,注意需要清标志位 *************************************************************************************************/ //void RTCAlarm_IRQHandler(void) //{ // if( RTC_GetITStatus(RTC_IT_ALR)!= RESET ) //闹钟中断 // { // EXTI_ClearITPendingBit(EXTI_Line17); // RTC_ClearITPendingBit(RTC_IT_ALR); //清闹钟中断 // printf("\r\n*闹钟中断" ) ; // } ///* Clear the EXTIL line 17 */ //} /************************************************************************************************** * 名 称: uint8_t CheckLeepYear(uint16_t year) * 功能说明: 检查year是否为闰年 * 入口参数: * @param uint16_t year:年份数值 * 出口参数: * @param uint8_t:检查结果 @arg 1: year为闰年 * @arg 0: year为平年 * 说 明: * 月份 1 2 3 4 5 6 7 8 9 10 11 12 * 闰年 31 29 31 30 31 30 31 31 30 31 30 31 * 非闰年 31 28 31 30 31 30 31 31 30 31 30 31 *************************************************************************************************/ uint8_t CheckLeepYear(uint16_t year) { if( year%4 == 0 ) //必须能被4整除 { if( year%100 == 0 ) { if( year%400 == 0 ) return 1 ; //如果以00结尾,还要能被400整除 else return 0 ; } else return 1 ; } else return 0 ; } /************************************************************************************************** * 名 称: uint8_t RTC_Set(Calendar_u *setCalendar) * 功能说明: 设置RTC当前时间 * 入口参数: * @param *setCalendar:Calendar_u类型共用体指针 * 出口参数: * @param uint8_t:返回值:0,成功;其他:错误代码. * 说 明: *************************************************************************************************/ RunResult RTC_Set(Calendar_u *setCalendar) // { uint16_t t ; u32 seccount = 0 ; //存储setCalendar日期计算出来的总秒钟数 初始化RTC计数器 uint16_t syear = (setCalendar->bytes[0]-'0')*1000+(setCalendar->bytes[1]-'0')*100+(setCalendar->bytes[2]-'0')*10+(setCalendar->bytes[3]-'0') ; uint8_t smon = (setCalendar->bytes[5]-'0')*10 +(setCalendar->bytes[6]-'0') ; uint8_t sday = (setCalendar->bytes[8]-'0')*10 +(setCalendar->bytes[9]-'0') ; uint8_t hour = (setCalendar->bytes[11]-'0')*10 +(setCalendar->bytes[12]-'0') ; uint8_t min = (setCalendar->bytes[14]-'0')*10 +(setCalendar->bytes[15]-'0') ; uint8_t sec = (setCalendar->bytes[17]-'0')*10 +(setCalendar->bytes[18]-'0'); if( syear<1970 || syear>2099 ) return (RunErr); for( t = 1970; t < syear; t++ ) //把所有年份的秒钟相加 { if(CheckLeepYear(t)) seccount += 31622400; //闰年的秒钟数 else seccount += 31536000; //平年的秒钟数 } smon -= 1; for( t=0; t2099 ) return (RunErr) ; for( t=1970; t= 365 ) { if( CheckLeepYear(temp1) ) //是闰年 { if( temp >= 366 ) temp -= 366 ; //闰年的秒钟数 else { temp1++ ; break ; } } else temp -= 365 ; //平年 temp1++ ; } w_year = temp1 ; //得到年份 getCalendar->calendar.w_year[0] = w_year/1000+'0' ; getCalendar->calendar.w_year[1] = (w_year%1000)/100+'0' ; getCalendar->calendar.w_year[2] = ((w_year%1000)%100)/10 + '0' ; getCalendar->calendar.w_year[3] = w_year%10 + '0' ; temp1 = 0 ; while( temp >= 28 ) //超过了一个月 { if( CheckLeepYear(w_year)&&temp1==1 )//当年是不是闰年/2月份 { if( temp >= 29 ) temp -= 29 ; //闰年的秒钟数 else break ; } else { if( temp >= mon_table[temp1] ) temp -= mon_table[temp1] ;//平年 else break ; } temp1++ ; } w_month = temp1+1 ; //得到月份 w_date = temp+1 ; //得到日期 getCalendar->calendar.w_month[0] = w_month/10+'0' ; getCalendar->calendar.w_month[1] = w_month%10+'0' ; getCalendar->calendar.w_date[0] = w_date/10+'0' ; getCalendar->calendar.w_date[1] = w_date%10+'0' ; } temp = timecount%86400 ; //得到秒钟数 hour = temp/3600 ; //小时 min = (temp%3600)/60 ; //分钟 sec = (temp%3600)%60 ; //秒钟 getCalendar->calendar.hour[0] = hour/10+'0' ; getCalendar->calendar.hour[1] = hour%10+'0' ; getCalendar->calendar.min[0] = min/10+'0' ; getCalendar->calendar.min[1] = min%10+'0' ; getCalendar->calendar.sec[0] = sec/10+'0' ; getCalendar->calendar.sec[1] = sec%10+'0' ; // if(( hour == 0x15 )&& ( min == 0x00 )&&( sec == 0x00) ) //凌晨21:00:00设定闹钟 // { // appConfigUnion.appFlashStruct.VolumeRank = 0x34 ; // RTC_WaitForLastTask(); // randCount = rand()%1000+rand()%100+rand()%10 ; // timecount = timecount+4*3600+randCount ; // RTC_SetAlarm(timecount) ; //设置下次闹钟值 // RTC_ITConfig( RTC_IT_ALR, ENABLE ) ; //开闹钟中断 // } // if(( hour == 0x07 )&& ( min == 0x00 )&&( sec == 0x00) ) //早上07:00:00恢复音量 // { // Read_From_Flash(APP_FLASH_CONFIG_ADDR, appConfigUnion.appFlashBuffer, APPFLASHCONFIGLEN ) ; //恢复音量等级 // if( !IS_VolumeRank_ALL_PERIPH(appConfigUnion.appFlashStruct.VolumeRank)) //音量等级不合法的话直接设置为7级 // { // appConfigUnion.appFlashStruct.VolumeRank = 0x37 ; // Save_to_Flash(APP_FLASH_CONFIG_ADDR, appConfigUnion.appFlashBuffer, APPFLASHCONFIGLEN ) ; // } // } week = RTC_Get_Week( w_year,w_month,w_date ) ;//获取星期 return (RunOK) ; } /************************************************************************************************** * 名 称: Ruint8_t RTC_Get_Week(uint16_t year, uint8_t month, uint8_t day) * 功能说明: 获取现在是星期几 * 入口参数: * @param1 year: 年分 * @param2 mon: 月份 * @param3 day: 日 * 出口参数: * @param1 uint8_t: 星期几? * @param RunResult:返回值,返回函数运行结果. * 说 明: 输入公历日期得到星期(只允许1901-2099年) *************************************************************************************************/ uint8_t RTC_Get_Week(uint16_t year, uint8_t month, uint8_t day) { uint16_t temp2 ; uint8_t yearH, yearL ; yearH = year/100 ; yearL = year%100 ; if ( yearH>19 ) // 如果为21世纪,年份数加100 yearL+=100; // 所过闰年数只算1900年之后的 temp2 = yearL+yearL/4 ; temp2 = temp2%7 ; temp2 = temp2+day+table_week[month-1] ; if ( yearL%4==0&&month<3 ) temp2--; return(temp2%7) ; }