- // 初始化Rtc,设置RTC超时时间为1s
- void Rtc_UserInit(void)
- {
- uint32_t tmpMod = 159999; /*!设置RTC模值 */
- uint32_t tmpPrescalerValue = 99; /*!设置分频比 */
- RTC_ConfigType RTCConfig; /*! (99+1)*(159999+1)/16000000 = 1s, timeout = (pre+1)*(mod+1)/clk */
-
- memset(&RTCConfig,0,sizeof(RTCConfig));
- RTCConfig.clockSource = RTC_CLOCK_APB; /*! 时钟源选择:RTC_CLOCK_APB,默认为16M */
- RTCConfig.periodValue = tmpMod; /*! 模值赋给RTCConfig结构体 */
- RTCConfig.psrInterruptEn = DISABLE; /*! 关闭实时预分频器中断 */
- RTCConfig.rtcInterruptEn = ENABLE; /*! RTC中断使能 */
- RTCConfig.psrValue = tmpPrescalerValue; /*! 预分频比赋值给RTCConfig结构体 */
- RTCConfig.rtcOutEn = DISABLE; /*! 禁能RTC输出 */
- RTCConfig.callBack = Rtc_CallbackFunc; /*! RTC回调函数配置 */
-
- RTC_Init(&RTCConfig); /*! RTC初始化函数生效 */
- Rtc_UserSetDateTime();
- }
2.3 时间累计函数
由于AC7802X没有提供硬件上的日期时间的自动累计,所以需要以来软件来实现。
> 硬件上没有实现日期时间的累计功能,RTC计时器就显得比较鸡肋,因为定时器可以实现同样的功能。
- Rtc_IsLeapYear函数用于判断指定年份是否为闰年
- Rtc_FindWeekDay为泰勒公式的软件实现,用于根据年月日计算星期。就算不设置星期,也可以自动计算出来。
- Rtc_DateTimeIncrease为日期时间累计函数,当初试时间设置之后,该函数会自动累计时间。该函数需要放在回调函数中,每一秒钟调用一次。
2.4 全部代码
下面是全部代码,包括了RTC初始化,时间设置,打印等。
每一秒中打印一次当前时间,日期,星期。
设定的初始时间为2023年12月31日23点59分50秒,为了测试时间累计函数是否成功。
- /*
- @hehung
- 2023-6-11
- email: 1398660197@qq.com
- wechat: hehung95
- reproduced and please indicate the source @hehung
- */
- #include <stdbool.h>
- #include <string.h>
- #include <stdio.h>
- #include "ac780x_gpio.h"
- #include "ac780x_rtc.h"
- #include "ac7802x.h"
- #include "app_rtc.h"
- static rtc_time_t current_dt = {0, 0, 0, 0, 0, 0, 0};
- static uint8_t month_day_num[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
- static void Rtc_CallbackFunc(void *device, uint32_t wpara, uint32_t lpara);
- static uint8_t Rtc_IsLeapYear(uint8_t year);
- static void Rtc_DateTimeIncrease(void);
- // Rtc 回调函数
- static void Rtc_CallbackFunc(void *device, uint32_t wpara, uint32_t lpara)
- {
- if (wpara & RTC_SC_RTIF_Msk) /*! RTC溢出中断 */
- {
- Rtc_DateTimeIncrease();
- Rtc_ShowTime();
- }
- }
- // 判断某一年是否为闰年
- static uint8_t Rtc_IsLeapYear(uint8_t year)
- {
- uint16_t full_year = 2000 + year;
- if (((full_year % 4 == 0 ) && (full_year % 100 != 0)) ||
- (year % 400 == 0))
- {
- return 1; // 闰年
- }
- else
- {
- return 0; // 非闰年
- }
- }
- // 泰勒公式求星期
- static uint8_t Rtc_FindWeekDay(void)
- {
- int m = current_dt.mon;
- int d = current_dt.mday;
- int year = current_dt.year + 2000;
- // 根据月份对年份和月份进行调整
- if(m <= 2)
- {
- year -= 1;
- m += 12;
- }
- int c = year / 100; // 取得年份前两位
- int y = year % 100; // 取得年份后两位
-
- // 根据泰勒公式计算星期
- int w = (int)(c/4) - 2*c + y + (int)(y/4)
- + (int)(13*(m+1)/5) + d - 1;
-
-
- return w%7; // 返回星期
- }
- // 日期时间累计函数,硬件没有实现,需要软件实现
- static void Rtc_DateTimeIncrease(void)
- {
- // seconds increase
- if (current_dt.sec >= 59U)
- {
- current_dt.sec = 0U;
-
- if (current_dt.min >= 59U)
- {
- current_dt.min = 0;
-
- if (current_dt.hour >= 23)
- {
- current_dt.hour = 0U;
-
- if (current_dt.mday >= month_day_num[current_dt.mon-1])
- {
- current_dt.mday = 1;
- if (current_dt.mon >= 12)
- {
- current_dt.mon = 1;
- current_dt.year++;
- // 年变化时,求2月天数
- month_day_num[1] = (Rtc_IsLeapYear(current_dt.year) == 1) ? (29U) : (28U);
- }
- else
- {
- current_dt.mon++;
- }
- }
- else
- {
- current_dt.mday++;
- }
-
- if (current_dt.weekday >= 7U)
- {
- current_dt.weekday = 0U;
- }
- else
- {
- current_dt.weekday++;
- }
- }
- else
- {
- current_dt.hour++;
- }
- }
- else
- {
- current_dt.min++;
- }
- }
- else
- {
- current_dt.sec++;
- }
- }
- // 设置当前时间
- void Rtc_DateTimeInit(rtc_time_t dt)
- {
- current_dt.year = dt.year;
- current_dt.mon = dt.mon;
- current_dt.mday = dt.mday;
- current_dt.weekday = dt.weekday;
- current_dt.hour = dt.hour;
- current_dt.min = dt.min;
- current_dt.sec = dt.sec;
- // 2月天数
- month_day_num[1] = (Rtc_IsLeapYear(current_dt.year) == 1) ? (29U) : (28U);
- // 根据泰勒公式计算真实星期
- current_dt.weekday = Rtc_FindWeekDay();
- }
- void Rtc_GetDateTime(rtc_time_t *date_time)
- {
- *date_time = current_dt;
- }
- void Rtc_ShowTime(void)
- {
- static const char *week[7] = {"Sun.", "Mon.", "Tue.", "Wed.", "Thu.", "Fri.", "Sat."};
- rtc_time_t date_time;
- Rtc_GetDateTime(&date_time);
- printf ("DateTime:20%02d-%02d-%02d(%s) %02d:%02d:%02d\r\n", date_time.year,
- date_time.mon,
- date_time.mday,
- week[(uint8_t)date_time.weekday],
- date_time.hour,
- date_time.min,
- date_time.sec);
- }
- // 初始化Rtc,设置RTC超时时间为1s
- void Rtc_UserInit(void)
- {
- uint32_t tmpMod = 159999; /*!设置RTC模值 */
- uint32_t tmpPrescalerValue = 99; /*!设置分频比 */
- RTC_ConfigType RTCConfig; /*! (99+1)*(159999+1)/16000000 = 1s, timeout = (pre+1)*(mod+1)/clk */
-
- memset(&RTCConfig,0,sizeof(RTCConfig));
- RTCConfig.clockSource = RTC_CLOCK_APB; /*! 时钟源选择:RTC_CLOCK_APB,默认为16M */
- RTCConfig.periodValue = tmpMod; /*! 模值赋给RTCConfig结构体 */
- RTCConfig.psrInterruptEn = DISABLE; /*! 关闭实时预分频器中断 */
- RTCConfig.rtcInterruptEn = ENABLE; /*! RTC中断使能 */
- RTCConfig.psrValue = tmpPrescalerValue; /*! 预分频比赋值给RTCConfig结构体 */
- RTCConfig.rtcOutEn = DISABLE; /*! 禁能RTC输出 */
- RTCConfig.callBack = Rtc_CallbackFunc; /*! RTC回调函数配置 */
-
- RTC_Init(&RTCConfig); /*! RTC初始化函数生效 */
- Rtc_UserSetDateTime();
- }
- void Rtc_UserSetDateTime(void)
- {
- rtc_time_t dt;
- dt.year = 23;
- dt.mon = 12;
- dt.mday = 31;
- dt.hour = 23;
- dt.min = 59;
- dt.sec = 50;
- Rtc_DateTimeInit(dt);
- }
- ```
- 2.5 主函数
- 主函数中只需要调用Rtc_UserInit即可。
- ```cpp
- int main(void)
- {
- InitDelay();
-
- UART_Cfg_Init(); /*! 串口1初始化 */
- Rtc_UserInit();
- while(1)
- {
- }
- }
3 实验效果
下面展示了实现效果。
初始时间为2023年12月31日23点59分50秒,目的是测试时间累计功能是否成功。
不用设置星期参数,就算设置了也不会识别,因为星期参数会通过泰勒公式自动计算出来,实验验证无误。
2023年12月31的日历如下: