RobotHardware-UESTC/Hardware/Firmware/Gebot_Firmware v1.0/STM32/BSPLIB/rtc.c

377 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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,dayGregorian 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