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

377 lines
12 KiB
C
Raw Normal View History

2024-01-18 02:06:22 +08:00
#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