Use TIMER to simulate RTC clock
Borrow two functions in RTC.c in STM32F103 to realize RTC clock.
Advantages: strong portability and accurate timing.
Disadvantages: Need to adjust the time after each power on.
Applicable occasions: no external RTC crystal oscillator, time calibration.
Instructions for use:
1: First determine the time base: that is, what time is the starting point for calculation. We start at 0:00:00:00 on January 1, 2020, and the relevant definitions are as follows:
#define START_YEAR 2000//default 2000, Jan.1, 00:00:00
#define SEC_IN_DAY 86400//1 day includes 86400 seconds
typedef struct
{
/* date and time components */
int16_t sec; //senconds after the minute, 0 to 59
int16_t min; //minutes after the hour, 0 to 59
int16_t hour; //hours since midnight, 0 to 23
int16_t mday; //day of the month, 1 to 31
int16_t month; //months of the year, 1 to 12
int16_t year; //years, START_YEAR to START_YEAR+135
int16_t wday; //days since Sunday, 0 to 6
int16_t yday; //days of the year, 1 to 366
}Calendar_TypeDef;
2: MyMakeTime() calculates the time (year, month, day, hour, minute, and second) obtained through time calibration as the number of seconds from START_YEAR. The MyMakeTime function is only called once when obtaining the time calibration time issued by the host computer.
Put the number of seconds returned by the MyMakeTime function in the TIMER timer interrupt and accumulate once per second. Used to simulate the RTC clock.
3: The MyLocalTime() function converts the accumulated seconds of the TIMER timer into the current time: year, month, day, hour, minute, and second. When you need to get the time, just call this function.
/*******************************************************************************
* Function Name : MyMakeTime
* Description : Form a 32 bit second counting value from calendar.
* Input : pointer to a calendar struct
* Return : 32 bit second counting value
*******************************************************************************/
uint32_t MyMakeTime(Calendar_TypeDef *pCalendar)
{
uint32_t TotalSeconds = pCalendar->sec;
int16_t nYear = pCalendar->year;
int16_t DaysInYear = 365;
int16_t nMonth = pCalendar->month;
int16_t DaysInMonth = 30;
if((nYear < START_YEAR) || (nYear > (START_YEAR + 135)))
return 0;//out of year range
TotalSeconds += (uint32_t)pCalendar->min * 60;//contribution of minutes
TotalSeconds += (uint32_t)pCalendar->hour * 3600;//contribution of hours
//contribution of mdays
TotalSeconds += (uint32_t)(pCalendar->mday - 1) * SEC_IN_DAY;
while(nMonth > 1)//contribution of months
{
nMonth --;
if(nMonth == 1||nMonth == 3||nMonth == 5||nMonth == 7
||nMonth == 8||nMonth == 10||nMonth == 12)
DaysInMonth = 31;
else if(nMonth == 2)
{
if(IsLeapYear(nYear)) DaysInMonth = 29;
else DaysInMonth = 28;
}
else DaysInMonth = 30;
TotalSeconds += (uint32_t)DaysInMonth * SEC_IN_DAY;
}
while(nYear > START_YEAR)//contribution of years
{
nYear --;
if(IsLeapYear(nYear)) DaysInYear = 366;
else DaysInYear = 365;
TotalSeconds += (uint32_t)DaysInYear * SEC_IN_DAY;
}
return TotalSeconds;
}
//end function MyMakeTime
/*******************************************************************************
* Function Name : MyLocalTime
* Description : Form a calendar from 32 bit second counting.
* Input : pointer to a 32 bit second value
* Return : Calendar structure
*******************************************************************************/
Calendar_TypeDef MyLocalTime(const uint32_t *pTotalSeconds)
{
Calendar_TypeDef Calendar;
uint32_t TotalDays, RemainSeconds;
int16_t DaysInYear=365;
int16_t DaysInMonth=30;
Calendar.year = START_YEAR;
Calendar.month = 1; Calendar.mday = 1;
Calendar.yday = 1;
Calendar.wday = Ymd2Wday(START_YEAR, 1, 1);
TotalDays = *pTotalSeconds / SEC_IN_DAY;
RemainSeconds = *pTotalSeconds % SEC_IN_DAY;
Calendar.hour = (int16_t)(RemainSeconds / 3600);//calculate hour
Calendar.min = (int16_t)((RemainSeconds / 60) % 60);//calculate minute
Calendar.sec = (int16_t)(RemainSeconds % 60);//calculate second
Calendar.wday = (int16_t)((TotalDays + Calendar.wday) % 7);//calculate wday
while(1)//calculate year
{
if(IsLeapYear(Calendar.year)) DaysInYear = 366;
else DaysInYear = 365;
if(TotalDays >= DaysInYear)
{
TotalDays -= DaysInYear;
Calendar.year ++;
}//continue while
else
break;//forced to end while
}//finish year calculation
Calendar.yday += TotalDays;//calculate yday
while(1)//calculate month
{
if(Calendar.month == 1||Calendar.month == 3||Calendar.month == 5
||Calendar.month == 7||Calendar.month == 8
||Calendar.month == 10||Calendar.month == 12)
DaysInMonth = 31;
else if(Calendar.month == 2)
{
if(IsLeapYear(Calendar.year)) DaysInMonth = 29;
else DaysInMonth = 28;
}
else DaysInMonth = 30;
if(TotalDays >= DaysInMonth)
{
TotalDays -= DaysInMonth;
Calendar.month ++;
}//continue while
else
break;//forced to end while
}//finish month calculation
Calendar.mday += (int16_t)TotalDays;//calculate mday
return Calendar;
}
//end function MyLocalTime
/*******************************************************************************
* Function Name : Ymd2Wday
* Description : Calculate days in week from year, month, mday.
* Input : year, month, mday
* Return : 0--6, Suanday--Saturday
*******************************************************************************/
static int16_t Ymd2Wday(int16_t nYear, int16_t nMonth, int16_t nMday)
{
uint8_t i;
const uint8_t DaysInMonth[] = {
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30 };
for(i = 0; i < nMonth; i++) nMday += DaysInMonth[i];
if(nMonth > 2)
{
if(IsLeapYear(nYear)) nMday++;
}
nYear--;
return (nYear + nYear/4 - nYear/100 + nYear/400 + nMday)%7;
}
//end function Ymd2Wday
/***********************************************************************
* Function Name : IsLeapYear
* Description : Check whether the past year is leap or not.
* Input : 4 digits year number
* Return : 1: leap year. 0: not leap year
***********************************************************************/
static uint8_t IsLeapYear(int16_t nYear)
{
if(nYear % 4 != 0) return 0;
if(nYear % 100 != 0) return 1;
return (uint8_t)(nYear % 400 == 0);
}
//end function IsLeapYear
Summary:
1: Use this method to time the time accurately, which is more accurate than the internal low-speed clock LSI as the RTC clock source.
2: Portability is strong, only need to open a timer to accumulate the number of seconds.
3: It is suitable for the application environment where the time can be adjusted.