Utilice TIMER para simular el reloj RTC
Tome prestadas dos funciones en RTC.c en STM32F103 para realizar el reloj RTC.
Ventajas: portabilidad fuerte y sincronización precisa.
Desventajas: es necesario ajustar el tiempo después de cada encendido.
Ocasiones aplicables: sin oscilador de cristal RTC externo, calibración de tiempo.
Instrucciones de uso:
1: Primero determine la base de tiempo: es decir, qué hora es el punto de partida para el cálculo. Comenzamos a las 0: 00: 00: 00 el 1 de enero de 2020, y las definiciones relevantes son las siguientes:
#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 () calcula el tiempo (año, mes, día, hora, minuto y segundo) obtenido a través de la calibración de tiempo como el número de segundos de START_YEAR. La función MyMakeTime solo se llama una vez cuando se obtiene la hora de calibración de hora emitida por la computadora host.
Ponga el número de segundos devueltos por la función MyMakeTime en la interrupción del temporizador TIMER y acumule una vez por segundo. Se utiliza para simular el reloj RTC.
3: La función MyLocalTime () convierte los segundos acumulados del temporizador TIMER en la hora actual: año, mes, día, hora, minuto y segundo. Cuando necesite obtener la hora, simplemente llame a esta función.
/*******************************************************************************
* 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
Resumen:
1: Utilice este método para medir el tiempo con precisión, que es más preciso que el LSI del reloj interno de baja velocidad como fuente de reloj RTC.
2: La portabilidad es fuerte, solo es necesario abrir un temporizador para acumular la cantidad de segundos.
3: Es adecuado para el entorno de aplicación donde se puede ajustar el tiempo.