forked from logzhan/RobotHardware-UESTC
377 lines
12 KiB
C
377 lines
12 KiB
C
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
#include "rtc.h"
|
||
#include "delay.h"
|
||
#include "usart.h"
|
||
|
||
//time structure
|
||
typedef struct
|
||
{
|
||
volatile unsigned char hour;
|
||
volatile unsigned char min;
|
||
volatile unsigned char sec;
|
||
//Gregorian calendar
|
||
volatile unsigned short int w_year;
|
||
volatile unsigned char w_month;
|
||
volatile unsigned char w_date;
|
||
volatile unsigned char week;
|
||
}CALENDAR;
|
||
|
||
CALENDAR calendar_r;//clock structure
|
||
|
||
//month data table
|
||
unsigned char const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //month correct data
|
||
//month data table of normal year
|
||
const unsigned char mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};
|
||
|
||
/***********************************************************************************************************************
|
||
* Function: static unsigned char Is_Leap_Year(unsigned short int year)
|
||
*
|
||
* Scope:
|
||
*
|
||
* Description: judge whether is leap year
|
||
* month 1 2 3 4 5 6 7 8 9 10 11 12
|
||
* leap year 31 29 31 30 31 30 31 31 30 31 30 31
|
||
* not leap year 31 28 31 30 31 30 31 31 30 31 30 31
|
||
* Input : Year
|
||
* Arguments:
|
||
*
|
||
* Return: 1,is leap year
|
||
* 0,not is leap year
|
||
* Cpu_Time:
|
||
*
|
||
* History:
|
||
************************************************************************************************************************/
|
||
static unsigned char Is_Leap_Year(unsigned short int year)
|
||
{
|
||
if(year%4==0) //must be divisible by 4
|
||
{
|
||
if(year%100==0)
|
||
{
|
||
if(year%400==0)return 1;//If end is 00, must be divisible by 400
|
||
else return 0;
|
||
}else return 1;
|
||
}else return 0;
|
||
}
|
||
|
||
/************************************************************************************************************************
|
||
* Function: unsigned char RTC_Get_Week(unsigned short int year,unsigned char month,unsigned char day)
|
||
*
|
||
* Scope:
|
||
*
|
||
* Description: Input date data to get week data
|
||
* legal input is 1901-2099
|
||
* year,month,day:Gregorian calendar date
|
||
*
|
||
* Arguments:
|
||
*
|
||
* Return: week data
|
||
*
|
||
* Cpu_Time:
|
||
*
|
||
* History:
|
||
*************************************************************************************************************************/
|
||
unsigned char RTC_Get_Week(unsigned short int year,unsigned char month,unsigned char day)
|
||
{
|
||
|
||
unsigned short int temp2;
|
||
unsigned char yearH,yearL;
|
||
|
||
yearH=year/100; yearL=year%100;
|
||
//if 21th century, year need add 100
|
||
if (yearH>19)yearL+=100;
|
||
//leap year only calculate after 1900
|
||
temp2=yearL+yearL/4;
|
||
temp2=temp2%7;
|
||
temp2=temp2+day+table_week[month-1];
|
||
if (yearL%4==0&&month<3)temp2--;
|
||
temp2%=7;
|
||
if(temp2==0)temp2=7;
|
||
return temp2;
|
||
|
||
}
|
||
|
||
/*************************************************************************************************************************
|
||
* Function: static unsigned char RTC_Get(void)
|
||
*
|
||
* Scope:
|
||
*
|
||
* Description: get current time
|
||
*
|
||
* Arguments:
|
||
*
|
||
* Return: 0-->succeeded others-->failed
|
||
*
|
||
* Cpu_Time:
|
||
*
|
||
* History:
|
||
**************************************************************************************************************************/
|
||
static unsigned char RTC_Get(void)
|
||
{
|
||
static unsigned short int daycnt=0;
|
||
unsigned int timecount=0;
|
||
unsigned int temp=0;
|
||
unsigned short int temp1=0;
|
||
timecount=RTC_GetCounter();
|
||
temp=timecount/86400; //get days(correspond the second)
|
||
if(daycnt!=temp)//over one day
|
||
{
|
||
daycnt=temp;
|
||
temp1=1970; //start at 1970
|
||
while(temp>=365)
|
||
{
|
||
if(Is_Leap_Year(temp1))//is leap year
|
||
{
|
||
if(temp>=366)temp-=366;//the seconds of leap year
|
||
else {temp1++;break;}
|
||
}
|
||
else temp-=365; //normal year
|
||
temp1++;
|
||
}
|
||
calendar_r.w_year=temp1;//get year
|
||
temp1=0;
|
||
while(temp>=28)//over one month
|
||
{
|
||
if(Is_Leap_Year(calendar_r.w_year)&&temp1==1)//judge if is leap month (February)
|
||
{
|
||
if(temp>=29)temp-=29;//the seconds of leap year
|
||
else break;
|
||
}
|
||
else
|
||
{
|
||
if(temp>=mon_table[temp1])temp-=mon_table[temp1];//normal year
|
||
else break;
|
||
}
|
||
temp1++;
|
||
}
|
||
calendar_r.w_month=temp1+1; //get month
|
||
calendar_r.w_date=temp+1; //get date
|
||
}
|
||
temp=timecount%86400; //get second
|
||
calendar_r.hour=temp/3600; //hour
|
||
calendar_r.min=(temp%3600)/60; //minute
|
||
calendar_r.sec=(temp%3600)%60; //second
|
||
calendar_r.week=RTC_Get_Week(calendar_r.w_year,calendar_r.w_month,calendar_r.w_date);//get week
|
||
return 0;
|
||
}
|
||
|
||
/*************************************************************************************************************************
|
||
* Function: RTC_NVIC_Config(void)
|
||
*
|
||
* Scope: private
|
||
*
|
||
* Description: RTC Configuration of Interruption
|
||
*
|
||
* Arguments:
|
||
*
|
||
* Return:
|
||
*
|
||
* Cpu_Time:
|
||
*
|
||
* History:
|
||
**************************************************************************************************************************/
|
||
static void RTC_NVIC_Config(void)
|
||
{
|
||
NVIC_InitTypeDef NVIC_InitStructure;
|
||
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; //RTC Global Interrupt
|
||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //PreemptionPriority
|
||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //SubPriority
|
||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //ENABLE the interrupt
|
||
NVIC_Init(&NVIC_InitStructure); //Initialize the NVIC register
|
||
}
|
||
|
||
/*************************************************************************************************************************
|
||
* Function: RTC_IRQHandler(void)
|
||
*
|
||
* Scope: private
|
||
*
|
||
* Description: RTC Interruptation update every second
|
||
*
|
||
* Arguments:
|
||
*
|
||
* Return:
|
||
*
|
||
* Cpu_Time:
|
||
*
|
||
* History:
|
||
**************************************************************************************************************************/
|
||
void RTC_IRQHandler(void)
|
||
{
|
||
if (RTC_GetITStatus(RTC_IT_SEC) != RESET)//RTC Interruptation
|
||
{
|
||
RTC_Get();//更新时间
|
||
}
|
||
if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)//alarm clock interrupt
|
||
{
|
||
|
||
RTC_ClearITPendingBit(RTC_IT_ALR); //clear clock interrupt
|
||
RTC_Get(); //update time
|
||
// printf("Alarm Time:%d-%d-%d %d:%d:%d\n",calendar_r.w_year,calendar_r.w_month,calendar_r.w_date,calendar_r.hour,calendar_r.min,calendar_r.sec);//输出闹铃时间
|
||
|
||
}
|
||
RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW); //clear alarm clock interrupt
|
||
RTC_WaitForLastTask();
|
||
}
|
||
|
||
unsigned char PB_RTC_Init(void)
|
||
{
|
||
|
||
//check if is first configuration of RTC
|
||
unsigned char temp=0;
|
||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //ENABLE clock of PWR and BKP
|
||
PWR_BackupAccessCmd(ENABLE); //enable access of backup register
|
||
if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050) //read data from backup register
|
||
{
|
||
BKP_DeInit(); //RESET backuo area
|
||
RCC_LSEConfig(RCC_LSE_ON); //set external LSE, and use LSE
|
||
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250) //check if set flag of RCC, and wait LSE is ready
|
||
{
|
||
temp++;
|
||
delay_ms(10);
|
||
}
|
||
if(temp>=250) return 1;//Initialize clock failed, the Crystal has error
|
||
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //set LSE to be the clock of RTC
|
||
RCC_RTCCLKCmd(ENABLE); //enable RTC
|
||
|
||
RTC_WaitForLastTask(); //wait finish writing RTC register
|
||
RTC_WaitForSynchro(); //wait RTC sync
|
||
RTC_ITConfig(RTC_IT_SEC, ENABLE); //ENABLE RTC Interrupt
|
||
RTC_WaitForLastTask(); //wait finish writing RTC register
|
||
RTC_EnterConfigMode();/// allow to configure
|
||
RTC_SetPrescaler(32767); //set Prescaler
|
||
RTC_WaitForLastTask(); //wait finish writing RTC register
|
||
RTC_Set(2015,1,14,17,42,55); //set time
|
||
RTC_ExitConfigMode(); //quit configuration mode
|
||
BKP_WriteBackupRegister(BKP_DR1, 0X5050); //write user program data to assign backup register
|
||
}
|
||
else//system continue counting time
|
||
{
|
||
RTC_WaitForSynchro(); //wait finish writing RTC register
|
||
RTC_ITConfig(RTC_IT_SEC, ENABLE); //enable RTC interrupt
|
||
RTC_WaitForLastTask(); //wait finish writing RTC register
|
||
}
|
||
RTC_NVIC_Config();//RTC interrupt NVIC configure
|
||
RTC_Get();//update time
|
||
return 0; //ok
|
||
|
||
}
|
||
|
||
/*************************************************************************************************************************
|
||
* Function: unsigned char RTC_Set(unsigned short int syear,unsigned char smon,unsigned char sday,unsigned char hour,unsigned char min,unsigned char sec)
|
||
*
|
||
* Scope: public
|
||
*
|
||
* Description: set clock
|
||
* transform the time data to seconds
|
||
* time base is 1,1,1970
|
||
* legal input is 1970~2099
|
||
*
|
||
* Arguments:
|
||
*
|
||
* Return: 0-->succeeded others-->failed
|
||
*
|
||
* Cpu_Time:
|
||
*
|
||
* History:
|
||
**************************************************************************************************************************/
|
||
unsigned char RTC_Set(unsigned short int syear,unsigned char smon,unsigned char sday,unsigned char hour,unsigned char min,unsigned char sec)
|
||
{
|
||
unsigned short int t;
|
||
unsigned int seccount=0;
|
||
if(syear<1970||syear>2099)return 1;
|
||
for(t=1970;t<syear;t++) //add all second data of year
|
||
{
|
||
if(Is_Leap_Year(t))seccount+=31622400;//seconds of leap year
|
||
else seccount+=31536000; //seconds of noramal year
|
||
}
|
||
smon-=1;
|
||
for(t=0;t<smon;t++) //add all second data of month
|
||
{
|
||
seccount+=(unsigned int)mon_table[t]*86400;//add second of every month
|
||
if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//if is leap year, add one more day time
|
||
}
|
||
seccount+=(unsigned int)(sday-1)*86400;//add all second before
|
||
seccount+=(unsigned int)hour*3600;//second of hour
|
||
seccount+=(unsigned int)min*60; //second of minute
|
||
seccount+=sec;//add second
|
||
|
||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //enable clock of PWR and BKP
|
||
PWR_BackupAccessCmd(ENABLE); // enable access to backup register
|
||
RTC_SetCounter(seccount); //set value of RTC counter
|
||
|
||
RTC_WaitForLastTask(); //wait finish writing RTC register
|
||
return 0;
|
||
}
|
||
|
||
/*************************************************************************************************************************
|
||
* Function: void RTC_Alarm_Set(unsigned short int syear,unsigned char smon,unsigned char sday,unsigned char hour,unsigned char min,unsigned char sec)
|
||
*
|
||
* Scope: public
|
||
*
|
||
* Description: Initialize clock
|
||
* transform the time data to seconds
|
||
* time base is 1,1,1970
|
||
* legal input is 1970~2099
|
||
*
|
||
* Arguments:
|
||
*
|
||
* Return: 0-->succeeded others-->failed
|
||
*
|
||
* Cpu_Time:
|
||
*
|
||
* History:
|
||
**************************************************************************************************************************/
|
||
void RTC_Alarm_Set(unsigned short int syear,unsigned char smon,unsigned char sday,unsigned char hour,unsigned char min,unsigned char sec)
|
||
{
|
||
unsigned short int t;
|
||
unsigned int seccount=0;
|
||
if(syear<1970||syear>2099)return ;
|
||
for(t=1970;t<syear;t++) //add all second data of year
|
||
{
|
||
if(Is_Leap_Year(t))seccount+=31622400;//seconds of leap year
|
||
else seccount+=31536000; //seconds of noramal year
|
||
}
|
||
smon-=1;
|
||
for(t=0;t<smon;t++) //add all second data of month
|
||
{
|
||
seccount+=(unsigned int)mon_table[t]*86400;//add second of every month
|
||
if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//if is leap year, add one more day time
|
||
}
|
||
seccount+=(unsigned int)(sday-1)*86400;//add all second before
|
||
seccount+=(unsigned int)hour*3600;//second of hour
|
||
seccount+=(unsigned int)min*60; //second of minute
|
||
seccount+=sec;//add second
|
||
//set clock
|
||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //enable clock of PWR and BKP
|
||
PWR_BackupAccessCmd(ENABLE); //enable access to backup register
|
||
//3 upside steps are necessary
|
||
|
||
RTC_SetAlarm(seccount);
|
||
|
||
RTC_WaitForLastTask(); //wait finish writing RTC register
|
||
|
||
return ;
|
||
}
|
||
|
||
void PB_Get_RTC_Time(uint8_t* year , uint8_t* month , uint8_t* date , uint8_t* week
|
||
,uint8_t* hour , uint8_t* min , uint8_t* sec , uint8_t* ampm)
|
||
{
|
||
RTC_Get();
|
||
*year = calendar_r.w_year;
|
||
*month = calendar_r.w_month;
|
||
*date = calendar_r.w_date;
|
||
*week = calendar_r.week;
|
||
*hour = calendar_r.hour;
|
||
*min = calendar_r.min;
|
||
*sec = calendar_r.sec;
|
||
*ampm = 0;
|
||
}
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|