swzswz

极海 APM32 + RTC示例并写日历

0
阅读(1467)

APM32内置一个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;
  • 闰年判断函数:

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; } }
  • 通过蔡勒公式获取当前日期对应的是星期几:

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; }
  • 通过读取当前RTC计数器的累加值,将其转换为对应的日期和时间信息

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; }
  • 通过日期和时间信息将其转换为RTC的计数值,并将计数值设置到RTC中:

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"); } }
  • 打印日期和时间信息:

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); }
  • 自动加载并提取当前工程编译生成时的日期和时间信息,用于后面初始化日期和时间用:

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]); }
  • RTC初始化及中断处理实现:

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(); }



Baidu
map