|
|
#include "system.h"
|
|
|
#include "rtc.h"
|
|
|
#include "Systick.h"
|
|
|
#include "USART.h"
|
|
|
|
|
|
_calendar_obj calendar;//时钟结构体
|
|
|
extern u8 RS485_RX_BUF[64];
|
|
|
extern u8 buf[51];
|
|
|
u8 a,b;
|
|
|
void static RTC_NVIC_Config(void)
|
|
|
{
|
|
|
NVIC_InitTypeDef NVIC_InitStructure;
|
|
|
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; //RTC全局中断
|
|
|
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占优先级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:正常
|
|
|
//其他:错误代码
|
|
|
|
|
|
//void RCC_Configuration(void)
|
|
|
//{
|
|
|
// // 错误处理函数
|
|
|
// ErrorStatus HSEStartUpStatus;
|
|
|
|
|
|
// // 重置RCC配置为默认值
|
|
|
// RCC_DeInit();
|
|
|
|
|
|
// // 打开HSE
|
|
|
// RCC_HSEConfig(RCC_HSE_ON);
|
|
|
|
|
|
// // 等待HSE启动
|
|
|
// HSEStartUpStatus = RCC_WaitForHSEStartUp();
|
|
|
|
|
|
// if(HSEStartUpStatus == SUCCESS)
|
|
|
// {
|
|
|
// // 使能预取指
|
|
|
// FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
|
|
|
|
|
|
// // 设置FLASH等待状态
|
|
|
// FLASH_SetLatency(FLASH_Latency_2);
|
|
|
|
|
|
// // HCLK = SYSCLK
|
|
|
// RCC_HCLKConfig(RCC_SYSCLK_Div1);
|
|
|
|
|
|
// // PCLK2 = HCLK
|
|
|
// RCC_PCLK2Config(RCC_HCLK_Div1);
|
|
|
|
|
|
// // PCLK1 = HCLK/2
|
|
|
// RCC_PCLK1Config(RCC_HCLK_Div2);
|
|
|
|
|
|
// // PLLCLK = 8MHz * 9 = 72 MHz
|
|
|
// RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
|
|
|
|
|
|
// // 使能PLL
|
|
|
// RCC_PLLCmd(ENABLE);
|
|
|
|
|
|
// // 等待PLL准备就绪
|
|
|
// while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
|
|
|
// {
|
|
|
// }
|
|
|
|
|
|
// // 选择PLL作为系统时钟源
|
|
|
// RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
|
|
|
|
|
|
// // 等待PLL成为系统时钟源
|
|
|
// while(RCC_GetSYSCLKSource() != 0x08)
|
|
|
// {
|
|
|
// }
|
|
|
// }
|
|
|
//}
|
|
|
|
|
|
|
|
|
u8 RTC_Init(void)
|
|
|
{
|
|
|
//检查是不是第一次配置时钟
|
|
|
printf("rtc_init start\r\n");
|
|
|
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_HSEConfig(RCC_HSE_ON);
|
|
|
|
|
|
while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET&&temp<250) //检查指定的RCC标志位设置与否,等待低速晶振就绪
|
|
|
{
|
|
|
temp++;
|
|
|
delay_ms(10);
|
|
|
}
|
|
|
if(temp>=250)return 1;//初始化时钟失败,晶振有问题
|
|
|
printf("rtc_init \r\n");
|
|
|
RCC_RTCCLKConfig(RCC_RTCCLKSource_HSE_Div128);
|
|
|
//设置RTC时钟(RTCCLK),选择LSE作为RTC时钟
|
|
|
printf("HSE is timesource\r\n");
|
|
|
RCC_RTCCLKCmd(ENABLE); //使能RTC时钟
|
|
|
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
|
|
RTC_WaitForSynchro(); //等待RTC寄存器同步
|
|
|
RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断
|
|
|
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
|
|
RTC_EnterConfigMode();/// 允许配置
|
|
|
RTC_SetPrescaler(62500); //设置RTC预分频的值
|
|
|
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
|
|
RTC_Set(2023,9,1,0,00,00); //设置时间
|
|
|
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(&a,&b);//更新时间
|
|
|
return 0; //ok
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//void RTC_Init(void)
|
|
|
//{
|
|
|
// // 配置系统时钟
|
|
|
// RCC_Configuration();
|
|
|
|
|
|
// // 配置RTC
|
|
|
// RTC_Configuration();
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
u8 RTC_synchronization_ins(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)//时钟同步
|
|
|
{
|
|
|
|
|
|
//u16 year=buf[3]+2000;
|
|
|
|
|
|
//检查是不是第一次配置时钟
|
|
|
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_LSICmd(ENABLE);
|
|
|
RCC_HSEConfig(RCC_HSE_ON); //设置外RCC_FLAG_LSIRDY部低速晶振(LSE),使用外设低速晶振
|
|
|
while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET&&temp<250) //检查指定的RCC标志位设置与否,等待低速晶振就绪
|
|
|
{
|
|
|
temp++;
|
|
|
delay_ms(10);
|
|
|
}
|
|
|
if(temp>=250)return 1;//初始化时钟失败,晶振有问题
|
|
|
RCC_RTCCLKConfig(RCC_RTCCLKSource_HSE_Div128); //设置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(62500); //设置RTC预分频的值
|
|
|
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
|
|
//RTC_Set(2017,4,30,20,17,00); //设置时间
|
|
|
RTC_Set( syear, smon, sday, hour, min, sec); //设置时间
|
|
|
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(&a,&b);//更新时间
|
|
|
return 0;
|
|
|
}
|
|
|
//RTC时钟中断
|
|
|
//每秒触发一次
|
|
|
//extern u16 tcnt;
|
|
|
void RTC_IRQHandler(void)
|
|
|
{
|
|
|
if (RTC_GetITStatus(RTC_IT_SEC) != RESET)//秒钟中断
|
|
|
{
|
|
|
RTC_Get(&a,&b);//更新时间
|
|
|
printf("RTC Time:%d-%d-%d %d:%d:%d\r\n",calendar.w_year,calendar.w_month,calendar.w_date,calendar.hour,calendar.min,calendar.sec);
|
|
|
}
|
|
|
if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)//闹钟中断
|
|
|
{
|
|
|
RTC_ClearITPendingBit(RTC_IT_ALR); //清闹钟中断
|
|
|
RTC_Get(&a,&b); //更新时间
|
|
|
printf("Alarm Time:%d-%d-%d %d:%d:%d\n",calendar.w_year,calendar.w_month,calendar.w_date,calendar.hour,calendar.min,calendar.sec);//输出闹铃时间
|
|
|
|
|
|
}
|
|
|
RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW); //清闹钟中断
|
|
|
RTC_WaitForLastTask();
|
|
|
}
|
|
|
//判断是否是闰年函数
|
|
|
//月份 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
|
|
|
//输入:年份
|
|
|
//输出:该年份是不是闰年.1,是.0,不是
|
|
|
u8 Is_Leap_Year(u16 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;
|
|
|
}
|
|
|
//设置时钟
|
|
|
//把输入的时钟转换为秒钟
|
|
|
//以1970年1月1日为基准
|
|
|
//1970~2099年为合法年份
|
|
|
//返回值:0,成功;其他:错误代码.
|
|
|
//月份数据表
|
|
|
u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表
|
|
|
//平年的月份日期表
|
|
|
const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};
|
|
|
u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
|
|
|
{
|
|
|
u16 t;
|
|
|
u32 seccount=0;
|
|
|
if(syear<1970||syear>2099)return 1;
|
|
|
for(t=1970;t<syear;t++) //把所有年份的秒钟相加
|
|
|
{
|
|
|
if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
|
|
|
else seccount+=31536000; //平年的秒钟数
|
|
|
}
|
|
|
smon-=1;
|
|
|
for(t=0;t<smon;t++) //把前面月份的秒钟数相加
|
|
|
{
|
|
|
seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
|
|
|
if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数
|
|
|
}
|
|
|
seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加
|
|
|
seccount+=(u32)hour*3600;//小时秒钟数
|
|
|
seccount+=(u32)min*60; //分钟秒钟数
|
|
|
seccount+=sec;//最后的秒钟加上去
|
|
|
|
|
|
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟
|
|
|
PWR_BackupAccessCmd(ENABLE); //使能RTC和后备寄存器访问
|
|
|
RTC_SetCounter(seccount); //设置RTC计数器的值
|
|
|
|
|
|
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
//初始化闹钟
|
|
|
//以1970年1月1日为基准
|
|
|
//1970~2099年为合法年份
|
|
|
//syear,smon,sday,hour,min,sec:闹钟的年月日时分秒
|
|
|
//返回值:0,成功;其他:错误代码.
|
|
|
u8 RTC_Alarm_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
|
|
|
{
|
|
|
u16 t;
|
|
|
u32 seccount=0;
|
|
|
if(syear<1970||syear>2099)return 1;
|
|
|
for(t=1970;t<syear;t++) //把所有年份的秒钟相加
|
|
|
{
|
|
|
if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
|
|
|
else seccount+=31536000; //平年的秒钟数
|
|
|
}
|
|
|
smon-=1;
|
|
|
for(t=0;t<smon;t++) //把前面月份的秒钟数相加
|
|
|
{
|
|
|
seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
|
|
|
if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数
|
|
|
}
|
|
|
seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加
|
|
|
seccount+=(u32)hour*3600;//小时秒钟数
|
|
|
seccount+=(u32)min*60; //分钟秒钟数
|
|
|
seccount+=sec;//最后的秒钟加上去
|
|
|
//设置时钟
|
|
|
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟
|
|
|
PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问
|
|
|
//上面三步是必须的!
|
|
|
|
|
|
RTC_SetAlarm(seccount);
|
|
|
|
|
|
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
//得到当前的时间
|
|
|
//返回值:0,成功;其他:错误代码.
|
|
|
u8 RTC_Get(u8 *hour,u8 *minute)
|
|
|
{
|
|
|
static u16 daycnt=0;
|
|
|
u32 timecount=0;
|
|
|
u32 temp=0;
|
|
|
u16 temp1=0;
|
|
|
timecount=RTC_GetCounter();
|
|
|
temp=timecount/86400; //得到天数(秒钟数对应的)
|
|
|
if(daycnt!=temp)//超过一天了
|
|
|
{
|
|
|
daycnt=temp;
|
|
|
temp1=1970; //从1970年开始
|
|
|
while(temp>=365)
|
|
|
{
|
|
|
if(Is_Leap_Year(temp1))//是闰年
|
|
|
{
|
|
|
if(temp>=366)temp-=366;//闰年的秒钟数
|
|
|
else {temp1++;break;}
|
|
|
}
|
|
|
else temp-=365; //平年
|
|
|
temp1++;
|
|
|
}
|
|
|
calendar.w_year=temp1;//得到年份
|
|
|
temp1=0;
|
|
|
while(temp>=28)//超过了一个月
|
|
|
{
|
|
|
if(Is_Leap_Year(calendar.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++;
|
|
|
}
|
|
|
calendar.w_month=temp1+1; //得到月份
|
|
|
calendar.w_date=temp+1; //得到日期
|
|
|
}
|
|
|
temp=timecount%86400; //得到秒钟数
|
|
|
calendar.hour=temp/3600; //小时
|
|
|
calendar.min=(temp%3600)/60; //分钟
|
|
|
calendar.sec=(temp%3600)%60; //秒钟
|
|
|
calendar.week=RTC_Get_Week(calendar.w_year,calendar.w_month,calendar.w_date);//获取星期
|
|
|
*hour=calendar.hour;
|
|
|
*minute=calendar.min;
|
|
|
return 0;
|
|
|
//return calendar.hour;
|
|
|
}
|
|
|
//获得现在是星期几
|
|
|
//功能描述:输入公历日期得到星期(只允许1901-2099年)
|
|
|
//输入参数:公历年月日
|
|
|
//返回值:星期号
|
|
|
u8 RTC_Get_Week(u16 year,u8 month,u8 day)
|
|
|
{
|
|
|
u16 temp2;
|
|
|
u8 yearH,yearL;
|
|
|
|
|
|
yearH=year/100; yearL=year%100;
|
|
|
// 如果为21世纪,年份数加100
|
|
|
if (yearH>19)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);
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|