/** ******************************** STM32F10x ********************************* * @文件名 : rtc.c * @作者 : sun * @库版本 : V3.5.0 * @文件版本 : V1.0.0 * @日期 : 2018年02月04日 * @摘要 : RTC源文件 ******************************************************************************/ /*---------------------------------------------------------------------------- 更新日志: 2018-02-04 V1.0.0:初始版本 ----------------------------------------------------------------------------*/ /* 包含的头文件 --------------------------------------------------------------*/ #include "rtc.h" #include "systick.h" #include "delay.h" RTC_DateTimeTypeDef DeviceRTC={16,5,19,15,26,0}; // DeviceRTC.Year = 16; // DeviceRTC.Month = 5; // DeviceRTC.Date = 19; // DeviceRTC.Hour = 15; // DeviceRTC.Minute = 26; // DeviceRTC.Second = 0; /************************************************ 函数名称 : RTC_Configuration 功 能 : RTC配置 参 数 : 无 返 回 值 : 无 作 者 : sun *************************************************/ void RTC_Configuration(void) { BKP_DeInit(); //复位后备区域 RCC_LSEConfig(RCC_LSE_ON); //使能低速外部时钟(LSE) while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET); RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //选择LSE作为RTC时钟源 RCC_RTCCLKCmd(ENABLE); //使能RTC时钟 RTC_WaitForSynchro(); //等待同步 RTC_WaitForLastTask(); //等待操作完成 // RTC_ITConfig(RTC_IT_ALR, ENABLE); //使能闹钟中断 // RTC_WaitForLastTask(); //等待操作完成 RTC_SetPrescaler(32767); //分频值 RTC_WaitForLastTask(); //等待操作完成 } /************************************************ 函数名称 : RTC_Initializes 功 能 : RTC初始化 参 数 : 无 返 回 值 : 无 作 者 : sun *************************************************/ void RTC_Initializes(void) { RTC_DateTimeTypeDef RTC_DateTimeStructure; RTC_DateTimeStructure.Year = 16; RTC_DateTimeStructure.Month = 7; RTC_DateTimeStructure.Date = 18; RTC_DateTimeStructure.Hour = 18; RTC_DateTimeStructure.Minute = 0; RTC_DateTimeStructure.Second = 0; PWR_BackupAccessCmd(ENABLE); //允许操作后备区域 /* 判断是否首次操作RTC */ if(BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5) { RTC_Configuration(); //配置RTC RTC_SetDateTime(RTC_DateTimeStructure); //初始化日历(2016年7月18日 18:00:00) BKP_WriteBackupRegister(BKP_DR1, 0xA5A5); } else { if(RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET) { } else if(RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET) { } RTC_WaitForSynchro(); //等待RTC与RTC_APB时钟同步 } // RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能秒中断 RTC_WaitForLastTask(); //等待TRC最后一次操作完成 } static void RTC_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; //RTC全局中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级1位,从优先级3位 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //先占优先级0位,从优先级4位 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能该通道中断 NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 } //实时时钟配置 //初始化RTC时钟,同时检测时钟是否工作正常 //BKP->DR1用于保存是否第一次配置的设置 //返回0:正常 //其他:错误代码 uint8_t RTC_Init(void) { uint8_t 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),使用外设低速晶振 RCC_LSICmd(ENABLE);//开启内部低速晶振LSI,changed by scx while( RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == 0 && temp<11) //while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) //检查指定的RCC标志位设置与否,等待低速晶振就绪 { temp++; delay_ms(10); } if(temp>=10)return 1;//初始化时钟失败,晶振有问题 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); //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_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 RTC_SetPrescaler(39000);//分频后为1HZ //RTC_SetPrescaler(32767); //设置RTC预分频的值 RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 RTC_SetDateTime(DeviceRTC); //设置时间 RTC_ExitConfigMode(); //退出配置模式 BKP_WriteBackupRegister(BKP_DR1, 0X5050); //向指定的后备寄存器中写入用户程序数据 } else//系统继续计时 { /////////////////////(时钟配置部分)//////////////////////////// RCC_LSICmd(ENABLE);//开启内部低速晶振LSI while( RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == 0 && temp<11) //while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) //检查指定的RCC标志位设置与否,等待低速晶振就绪 { temp++; delay_ms(10); } if(temp>=10)return 1;//初始化时钟失败,晶振有问题 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); RCC_RTCCLKCmd(ENABLE);//选择使能RTC时钟 RTC_WaitForLastTask();//等待上一次写RTC任务完成(常用,只要涉及对RTC里值的修改,都需要在修改后加上此函数) RTC_WaitForSynchro();//等待与APB1的同步,才能读RTC寄存器 RTC_EnterConfigMode();//允许RTC配置 RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断 RTC_WaitForLastTask();//等待上一次写RTC任务完成(常用,只要涉及对RTC里值的修改,都需要在修改后加上此函数) RTC_SetPrescaler(39000);//分频后为1HZ RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 RTC_ExitConfigMode(); //等待最近一次对RTC寄存器的写操作完成 RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 } RTC_NVIC_Config();//RCT中断分组设置 RTC_GetDateTime(&DeviceRTC);//更新时间 return 0; //ok } /************************************************ 函数名称 : RTC_SetDateTime 功 能 : 设置RTC日期时间 参 数 : RTC_DateTimeStructure --- RTC日期时间结构体 返 回 值 : RTC_OK ------------------ 成功 RTC_OVERFLOW ------------ 失败(越界) 作 者 : sun *************************************************/ RTC_RESULT RTC_SetDateTime(RTC_DateTimeTypeDef RTC_DateTimeStructure) { uint32_t num_leapyear; //闰年天数 uint32_t conut_year; //计秒(年) uint32_t conut_month_day; //月日的秒计数 /*------------------------- 判断是否越界 --------------------------*/ //年、月、星期、时、分、秒 if((130 < RTC_DateTimeStructure.Year) || (12 < RTC_DateTimeStructure.Month) || (24 <= RTC_DateTimeStructure.Hour) || (60 <= RTC_DateTimeStructure.Minute) || (60 <= RTC_DateTimeStructure.Second)) { return RTC_OVERFLOW; } //日 if((RTC_DateTimeStructure.Month==1)|(RTC_DateTimeStructure.Month==3)|(RTC_DateTimeStructure.Month==5)|(RTC_DateTimeStructure.Month==7)|(RTC_DateTimeStructure.Month==8)|(RTC_DateTimeStructure.Month==10)|(RTC_DateTimeStructure.Month==12)) { if(RTC_DateTimeStructure.Date > 31) return RTC_OVERFLOW; } else if((RTC_DateTimeStructure.Month==4)|(RTC_DateTimeStructure.Month==6)|(RTC_DateTimeStructure.Month==9)|(RTC_DateTimeStructure.Month==11)) { if(RTC_DateTimeStructure.Date > 30) return RTC_OVERFLOW; } else if(RTC_DateTimeStructure.Month==2) { /* 如果是闰年 */ if(RTC_DateTimeStructure.Year%4 == 0) { if(RTC_DateTimeStructure.Date > 29) return RTC_OVERFLOW; } else if(RTC_DateTimeStructure.Date > 28) return RTC_OVERFLOW; } //--------------------------- 计算天数 ---------------------------- //闰年数 num_leapyear = RTC_DateTimeStructure.Year/4 + 1; //计秒(年) conut_year = RTC_DateTimeStructure.Year*SEC_YEAR + num_leapyear*SEC_DAY; switch(RTC_DateTimeStructure.Month) { case 1:/* 一月 */ conut_month_day = (RTC_DateTimeStructure.Date-1)*SEC_DAY; if(RTC_DateTimeStructure.Year%4 == 0) //假如是闰年,需要减去一天的计数 conut_month_day -= SEC_DAY; break; case 2:/* 二月 */ conut_month_day = (31 + RTC_DateTimeStructure.Date - 1)*SEC_DAY; if(RTC_DateTimeStructure.Year%4 == 0) //假如是闰年,需要减去一天的计数 conut_month_day -= SEC_DAY; break; case 3:/* 三月 */ conut_month_day = (59 + RTC_DateTimeStructure.Date - 1)*SEC_DAY; break; case 4:/* 四月 */ conut_month_day = (90 + RTC_DateTimeStructure.Date - 1)*SEC_DAY; break; case 5:/* 五月 */ conut_month_day = (120 + RTC_DateTimeStructure.Date - 1)*SEC_DAY; break; case 6:/* 六月 */ conut_month_day = (151 + RTC_DateTimeStructure.Date - 1)*SEC_DAY; break; case 7:/* 七月 */ conut_month_day = (181 + RTC_DateTimeStructure.Date - 1)*SEC_DAY; break; case 8:/* 八月 */ conut_month_day = (212 + RTC_DateTimeStructure.Date - 1)*SEC_DAY; break; case 9:/* 九月 */ conut_month_day = (243 + RTC_DateTimeStructure.Date - 1)*SEC_DAY; break; case 10:/* 十月 */ conut_month_day = (273 + RTC_DateTimeStructure.Date - 1)*SEC_DAY; break; case 11:/* 十一月 */ conut_month_day = (304 + RTC_DateTimeStructure.Date - 1)*SEC_DAY; break; case 12:/* 十二月 */ conut_month_day = (334 + RTC_DateTimeStructure.Date - 1)*SEC_DAY; break; } RTC_WaitForLastTask(); //设置计数值(更新RTC) RTC_SetCounter(conut_year + conut_month_day + RTC_DateTimeStructure.Hour*3600 + RTC_DateTimeStructure.Minute*60 + RTC_DateTimeStructure.Second); //等待TRC操作完成 RTC_WaitForLastTask(); return RTC_OK; } /************************************************ 函数名称 : RTC_GetDateTime 功 能 : 读取RTC时间(含日历、星期) 参 数 : RTC_DateTimeStructure --- RTC日期时间结构体 返 回 值 : 无 作 者 : sun *************************************************/ void RTC_GetDateTime(RTC_DateTimeTypeDef *RTC_DateTimeStructure) { uint32_t num_day; //计数的天数 uint32_t num_daytmp; //该年的天数 uint32_t num_leapyear; //闰年数 uint32_t count_value = RTC_GetCounter(); //读取RTC计数值 num_day = count_value/SEC_DAY; //从0开始计算天数 num_leapyear = num_day/(365*4+1) + 1; //闰年数 if(num_day%(365*4+1) == 0) //闰年的1月1日 RTC_DateTimeStructure->Year = (uint8_t)((num_day - num_leapyear + 1)/365); else RTC_DateTimeStructure->Year = (num_day - num_leapyear)/365; if(RTC_DateTimeStructure->Year%4 == 0) { /* 闰年一年内的天数 */ num_daytmp = num_day - RTC_DateTimeStructure->Year*365 - (num_leapyear-1); if(num_daytmp < 31) /* 一月 */ { RTC_DateTimeStructure->Month = 1; RTC_DateTimeStructure->Date = num_daytmp%31 + 1; } else if(num_daytmp < 60)/* 二月 */ { RTC_DateTimeStructure->Month = 2; RTC_DateTimeStructure->Date = (num_daytmp - 31)%29 + 1; } else if(num_daytmp < 91)/* 三月 */ { RTC_DateTimeStructure->Month = 3; RTC_DateTimeStructure->Date = (num_daytmp - 60)%31 + 1; } else if(num_daytmp < 121)/* 四月 */ { RTC_DateTimeStructure->Month = 4; RTC_DateTimeStructure->Date = (num_daytmp - 91)%30 + 1; } else if(num_daytmp < 152)/* 五月 */ { RTC_DateTimeStructure->Month = 5; RTC_DateTimeStructure->Date = (num_daytmp - 121)%31 + 1; } else if(num_daytmp < 182)/* 六月 */ { RTC_DateTimeStructure->Month = 6; RTC_DateTimeStructure->Date = (num_daytmp - 152)%30 + 1; } else if(num_daytmp < 213)/* 七月 */ { RTC_DateTimeStructure->Month = 7; RTC_DateTimeStructure->Date = (num_daytmp - 182)%31 + 1; } else if(num_daytmp < 244)/* 八月 */ { RTC_DateTimeStructure->Month = 8; RTC_DateTimeStructure->Date = (num_daytmp - 213)%31 + 1; } else if(num_daytmp < 274)/* 九月 */ { RTC_DateTimeStructure->Month = 9; RTC_DateTimeStructure->Date = (num_daytmp - 244)%30 + 1; } else if(num_daytmp < 305)/* 十月 */ { RTC_DateTimeStructure->Month = 10; RTC_DateTimeStructure->Date = (num_daytmp - 274)%31 + 1; } else if(num_daytmp < 335)/* 十一月 */ { RTC_DateTimeStructure->Month = 11; RTC_DateTimeStructure->Date = (num_daytmp - 305)%30 + 1; } else if(num_daytmp < 366)/* 十二月 */ { RTC_DateTimeStructure->Month = 12; RTC_DateTimeStructure->Date = (num_daytmp - 335)%31 + 1; } } else { /* 平年一年内的天数 */ num_daytmp = num_day - RTC_DateTimeStructure->Year*365 - num_leapyear ; if(num_daytmp < 31) { RTC_DateTimeStructure->Month = 1; RTC_DateTimeStructure->Date = num_daytmp%31 + 1; } else if(num_daytmp < 59) { RTC_DateTimeStructure->Month = 2; RTC_DateTimeStructure->Date = (num_daytmp - 31)%28 + 1; } else if(num_daytmp < 90) { RTC_DateTimeStructure->Month = 3; RTC_DateTimeStructure->Date = (num_daytmp - 59)%31 + 1; } else if(num_daytmp < 120) { RTC_DateTimeStructure->Month = 4; RTC_DateTimeStructure->Date = (num_daytmp - 90)%30 + 1; } else if(num_daytmp < 151) { RTC_DateTimeStructure->Month = 5; RTC_DateTimeStructure->Date = (num_daytmp - 120)%31 + 1; } else if(num_daytmp < 181) { RTC_DateTimeStructure->Month = 6; RTC_DateTimeStructure->Date = (num_daytmp - 151)%30 + 1; } else if(num_daytmp < 212) { RTC_DateTimeStructure->Month = 7; RTC_DateTimeStructure->Date = (num_daytmp - 181)%31 + 1; } else if(num_daytmp < 243) { RTC_DateTimeStructure->Month = 8; RTC_DateTimeStructure->Date = (num_daytmp - 212)%31 + 1; } else if(num_daytmp < 273) { RTC_DateTimeStructure->Month = 9; RTC_DateTimeStructure->Date = (num_daytmp - 243)%30 + 1; } else if(num_daytmp < 304) { RTC_DateTimeStructure->Month = 10; RTC_DateTimeStructure->Date = (num_daytmp - 273)%31 + 1; } else if(num_daytmp < 334) { RTC_DateTimeStructure->Month = 11; RTC_DateTimeStructure->Date = (num_daytmp - 304)%30 + 1; } else if(num_daytmp < 365) { RTC_DateTimeStructure->Month = 12; RTC_DateTimeStructure->Date = (num_daytmp - 334)%31 + 1; } } /* 星期 */ RTC_DateTimeStructure->Week = (num_day + 5)%7 + 1; /* 时 */ RTC_DateTimeStructure->Hour = (count_value / 3600) % 24; /* 分 */ RTC_DateTimeStructure->Minute = (count_value % 3600) / 60; /* 秒 */ RTC_DateTimeStructure->Second = count_value % 60; } /************************************************ 函数名称 : RTC_Initializes 功 能 : RTC初始化 参 数 : 无 返 回 值 : 无 作 者 : sun *************************************************/ void RTC_SetAlarmTime_S(uint32_t Time ) { uint32_t TimeNow = 0; RTC_ITConfig(RTC_IT_ALR, DISABLE); //使能闹钟中断 RTC_WaitForLastTask(); //等待操作完成 TimeNow = RTC_GetCounter(); TimeNow = TimeNow + Time -1; RTC_SetAlarm(TimeNow); //闹钟时间 RTC_WaitForLastTask(); //等待操作完成 RTC_ITConfig(RTC_IT_ALR, ENABLE); //使能闹钟中断 RTC_WaitForLastTask(); //等待操作完成 } /**** Copyright (C)2016 sun. All Rights Reserved **** END OF FILE ****/