APM32E103VET6S微控制器带有一个RTC实时时钟单元,它可以应用在我们需要显示日期或者时间的应用场合,通过内部或者外部的时钟源实现精确走时,相比于定时器实现的RTC要准确得多。本方通过RTC的秒中断功能,再结合软件处理实现日期和时间的打印输出,具体步骤如下:
typedef struct
{
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t week;
uint8_t hour;
uint8_t minute;
uint8_t second;
} CALENDAR_TypeDef;
const uint8_t RTC_DayOfMonth[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
CALENDAR_TypeDef RTC_Calendar;
/*******************************************************************************
* [url=home.php?mod=space&uid=159083]@brief[/url] * @param
* @retval
* [url=home.php?mod=space&uid=1020061]@attention[/url] *******************************************************************************/
uint8_t RTC_LeapYear(uint16_t Year)
{
if(
(((Year % 400) == 0) ) || /* Century Leap Year */
(((Year % 100) != 0) && ((Year % 4) == 0)) /* Normal Leay Year */
)
{
return 1;
}
else
{
return 0;
}
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
uint8_t RTC_GetWeek(uint16_t Year, uint8_t Month, uint8_t Day)
{
int w, c, y;
/* Month 1 Or 2 of This Year Must Be As Last Month 13 Or 14 */
if((Month == 1) || (Month == 2))
{
Month += 12;
Year -= 1;
}
w = 0; /* Weekday */
c = Year / 100; /* Century */
y = Year % 100; /* Year */
w = y + (y / 4) + (c / 4) - (2 * c) + (26 * (Month + 1) / 10) + Day - 1;
while(w < 0) w += 7;
w %= 7;
return w;
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void RTC_UpdateCalendar(void)
{
static uint32_t PreTotalDay = 0;
uint32_t TotalSecond = 0;
uint32_t TotalDay = 0;
uint16_t Year = 1970;
uint8_t Month = 0;
/* Get The RTC Counter Value */
TotalSecond = RTC_ReadCounter();
TotalDay = TotalSecond / 86400;
if(PreTotalDay != TotalDay)
{
PreTotalDay = TotalDay;
while(TotalDay >= 365)
{
if(RTC_LeapYear(Year) == 1)
{
if(TotalDay >= 366)
{
TotalDay -= 366;
}
else
{
break;
}
}
else
{
TotalDay -= 365;
}
Year++;
}
RTC_Calendar.year = Year;
while(TotalDay >= 28)
{
if((Month == 1) && (RTC_LeapYear(RTC_Calendar.year) == 1))
{
if(TotalDay >= 29)
{
TotalDay -= 29;
}
else
{
break;
}
}
else
{
if(TotalDay >= RTC_DayOfMonth[Month])
{
TotalDay -= RTC_DayOfMonth[Month];
}
else
{
break;
}
}
Month++;
}
RTC_Calendar.month = Month + 1;
RTC_Calendar.day = TotalDay + 1;
RTC_Calendar.week = RTC_GetWeek(RTC_Calendar.year, RTC_Calendar.month, RTC_Calendar.day);
}
RTC_Calendar.hour = (TotalSecond % 86400) / 3600;
RTC_Calendar.minute = ((TotalSecond % 86400) % 3600) / 60;
RTC_Calendar.second = ((TotalSecond % 86400) % 3600) % 60;
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void RTC_SetDateTime(uint16_t Year, uint8_t Month, uint8_t Day,
uint8_t Hour, uint8_t Min, uint8_t Sec)
{
uint32_t TotalSecond = 0;
uint16_t y = 0;
uint8_t m = 0;
if((Year >= 1970) && (Year <= 2099))
{
for(y = 1970; y < Year; y++)
{
if(RTC_LeapYear(y) == 1)
{
TotalSecond += 31622400; /* Total Seconds Of Leap Year */
}
else
{
TotalSecond += 31536000; /* Total Seconds Of Normal Year */
}
}
for(m = 0; m < (Month - 1); m++)
{
TotalSecond += RTC_DayOfMonth[m] * 86400; /* Total Seconds Of Month */
if((RTC_LeapYear(Year) == 1) && (m == 1))
{
TotalSecond += 86400;
}
}
TotalSecond += (uint32_t)(Day - 1) * 86400; /* Total Seconds Of Day */
TotalSecond += (uint32_t)Hour * 3600; /* Total Seconds Of Hour */
TotalSecond += (uint32_t)Min * 60; /* Total Seconds Of Minute */
TotalSecond += Sec;
RTC_ConfigCounter(TotalSecond);
RTC_WaitForLastTask();
}
else
{
printf("\r\nError Date & Time!!!\r\n");
}
}
/******************************************************************************
* @brief
* @param
* @retval
* @attention
******************************************************************************/
void RTC_PrintDateTime(void)
{
printf("\r\n%04d-%02d-%02d", RTC_Calendar.year, RTC_Calendar.month, RTC_Calendar.day);
switch(RTC_Calendar.week)
{
case 0 : printf(" SUN "); break;
case 1 : printf(" MON "); break;
case 2 : printf(" TUE "); break;
case 3 : printf(" WED "); break;
case 4 : printf(" THU "); break;
case 5 : printf(" FRI "); break;
case 6 : printf(" SAT "); break;
default: break;
}
printf("%02d:%02d:%02d\r\n", RTC_Calendar.hour, RTC_Calendar.minute, RTC_Calendar.second);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void RTC_LoadDefault(void)
{
char date[20], time[20];
char text[6][5];
uint8_t index = 0, month = 0;
memset(date, 0, sizeof(date));
memset(time, 0, sizeof(time));
memset(text, 0, sizeof(text));
memcpy(date, __DATE__, sizeof(__DATE__));
memcpy(time, __TIME__, sizeof(__TIME__));
char *str;
str = strtok(date, " ");
while(str != NULL)
{
memcpy(text[index], str, strlen(str));
index++;
str = strtok(NULL, " ");
}
str = strtok(time, ":");
while(str != NULL)
{
memcpy(text[index], str, strlen(str));
index++;
str = strtok(NULL, ":");
}
#if 0
for(uint8_t i = 0; i < index; i++)
{
printf("\r\n->%s", text[i]);
}
#endif
char *strMonth[12] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
};
for(uint8_t i = 0; i < 12; i++)
{
if(strcmp(text[0], strMonth[i]) == 0)
{
month = i + 1;
}
}
RTC_Calendar.day = atoi(text[1]);
RTC_Calendar.month = month;
RTC_Calendar.year = atoi(text[2]);
RTC_Calendar.week = RTC_GetWeek(RTC_Calendar.year,
RTC_Calendar.month,
RTC_Calendar.day);
RTC_Calendar.hour = atoi(text[3]);
RTC_Calendar.minute = atoi(text[4]);
RTC_Calendar.second = atoi(text[5]);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void RTC_Init(void)
{
RCM_EnableAPB1PeriphClock((RCM_APB1_PERIPH_T)RCM_APB1_PERIPH_PMU);
PMU_EnableBackupAccess();
RCM_EnableLSI();
while(RCM_ReadStatusFlag(RCM_FLAG_LSIRDY) == RESET);
RCM_ConfigRTCCLK(RCM_RTCCLK_LSI);
RCM_EnableRTCCLK();
RTC_WaitForSynchro();
RTC_WaitForLastTask();
RTC_EnableInterrupt(RTC_INT_SEC);
RTC_WaitForLastTask();
RTC_ConfigPrescaler(32767);
RTC_WaitForLastTask();
RTC_LoadDefault();
RTC_SetDateTime(RTC_Calendar.year, RTC_Calendar.month, RTC_Calendar.day,
RTC_Calendar.hour, RTC_Calendar.minute, RTC_Calendar.second);
RTC_WaitForLastTask();
NVIC_EnableIRQRequest(RTC_IRQn, 0, 0);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void RTC_IRQHandler(void)
{
if(RTC_ReadIntFlag(RTC_INT_SEC) != RESET)
{
RTC_UpdateCalendar();
RTC_PrintDateTime();
}
RTC_ClearIntFlag(RTC_INT_SEC | RTC_INT_OVR);
RTC_WaitForLastTask();
}
运行结果:
软件工程源代码:
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void RTC_Init(void)
{
#if 0
RCM_EnableAPB1PeriphClock((RCM_APB1_PERIPH_T)RCM_APB1_PERIPH_PMU);
PMU_EnableBackupAccess();
RCM_EnableLSI();
while(RCM_ReadStatusFlag(RCM_FLAG_LSIRDY) == RESET);
RCM_ConfigRTCCLK(RCM_RTCCLK_LSI);
RCM_EnableRTCCLK();
#else
RCM_EnableAPB1PeriphClock((RCM_APB1_PERIPH_T)(RCM_APB1_PERIPH_PMU | RCM_APB1_PERIPH_BAKR));
PMU_EnableBackupAccess();
BAKPR_Reset();
RCM_ConfigLSE(RCM_LSE_OPEN);
while(RCM_ReadStatusFlag(RCM_FLAG_LSERDY) == RESET);
RCM_ConfigRTCCLK(RCM_RTCCLK_LSE);
RCM_EnableRTCCLK();
#endif
RTC_WaitForSynchro();
RTC_WaitForLastTask();
RTC_EnableInterrupt(RTC_INT_SEC);
RTC_WaitForLastTask();
RTC_ConfigPrescaler(32767);
RTC_WaitForLastTask();
RTC_LoadDefault();
RTC_SetDateTime(RTC_Calendar.year, RTC_Calendar.month, RTC_Calendar.day,
RTC_Calendar.hour, RTC_Calendar.minute, RTC_Calendar.second);
RTC_WaitForLastTask();
NVIC_EnableIRQRequest(RTC_IRQn, 0, 0);
}
本帖最后由 xld0932 于 2022-9-28 09:00 编辑
楼主的RTC示例写得非常清晰明了,感分享!