【沁恒微CH32V307评估板试用体验】U8g2电子时钟 - RISC-V MCU技术社区 - 电子技术william hill官网 - 广受欢迎的专业电子william hill官网 - 威廉希尔官方网站
分享 收藏 返回

[文章]

【沁恒微CH32V307评估板试用体验】U8g2电子时钟

【前言】昨天用u8g2驱动了OLED,CH32V307的RTC得用起来,这里向大家展一款基本的电子时钟。
1、先学习一下RTC的例程,然后自己新建一个rtc.c及rtc.h这样的话其他的工程就可以重复使用了。
新建rtc文件.png
2、先编写rtc.c,rtc初始化函数:
  1. /*********************************************************************
  2. * @fn      RTC_Init
  3. *
  4. * [url=home.php?mod=space&uid=2666770]@Brief[/url]   Initializes RTC collection.
  5. *
  6. * [url=home.php?mod=space&uid=1141835]@Return[/url]  1 - Init Fail
  7. *          0 - Init Success
  8. */
  9. uint8_t RTC_Init(void)
  10. {
  11.     u8 temp = 0;
  12.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
  13.         PWR_BackupAccessCmd(ENABLE);

  14.         /* Is it the first configuration */
  15.         if(BKP_ReadBackupRegister(BKP_DR1) != 0xA1A1)
  16.         {
  17.             BKP_DeInit();
  18.             RCC_LSEConfig(RCC_LSE_ON);
  19.             while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET && temp < 250)
  20.             {
  21.                 temp++;
  22.                 Delay_Ms(20);
  23.             }
  24.             if(temp >= 250)
  25.                 return 1;
  26.             RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
  27.             RCC_RTCCLKCmd(ENABLE);
  28.             RTC_WaitForLastTask();
  29.             RTC_WaitForSynchro();
  30.             //      RTC_ITConfig(RTC_IT_ALR, ENABLE);
  31.             RTC_ITConfig(RTC_IT_SEC, ENABLE);
  32.             RTC_WaitForLastTask();
  33.             RTC_EnterConfigMode();
  34.             RTC_SetPrescaler(32767);
  35.             RTC_WaitForLastTask();
  36.             RTC_Set(2022, 5, 23, 12, 0, 0); /* Setup Time */
  37.             RTC_ExitConfigMode();
  38.             BKP_WriteBackupRegister(BKP_DR1, 0XA1A1);
  39.         }
  40.         else
  41.         {
  42.             RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
  43.             PWR_WakeUpPinCmd(DISABLE);
  44.             RTC_WaitForSynchro();
  45.             //      RTC_ITConfig(RTC_IT_ALR, ENABLE);
  46.             RTC_ITConfig(RTC_IT_SEC, ENABLE);
  47.             RTC_WaitForLastTask();
  48.         }
  49.         RTC_Get();
  50.         RTC_NVIC_Config();

  51.         return 0;
  52. }
3、为了自动获取时间,设置了RTC中断函数,定时更新结构数据
  1. /*********************************************************************
  2. * @fn      RTC_NVIC_Config
  3. *
  4. * @brief   Initializes RTC Int.
  5. *
  6. * @return  none
  7. */
  8. static void RTC_NVIC_Config(void)
  9. {
  10.     NVIC_InitTypeDef NVIC_InitStructure = {0};
  11.     NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
  12.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  13.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  14.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  15.     NVIC_Init(&NVIC_InitStructure);
  16. }
4、然后大家不要忘了去ch32v30x_it.c去书写中断函数:
  1. void RTC_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
  2. /*********************************************************************
  3. * @fn      RTC_IRQHandler
  4. *
  5. * @brief   This function handles RTC Handler.
  6. *
  7. * @return  none
  8. */
  9. void RTC_IRQHandler(void)
  10. {
  11.     if(RTC_GetITStatus(RTC_IT_SEC) != RESET) /* Seconds interrupt */
  12.     {
  13.         RTC_Get();
  14.     }
  15.     if(RTC_GetITStatus(RTC_IT_ALR) != RESET) /* Alarm clock interrupt */
  16.     {
  17.         RTC_ClearITPendingBit(RTC_IT_ALR);
  18.         RTC_Get();
  19.     }

  20.     RTC_ClearITPendingBit(RTC_IT_SEC | RTC_IT_OW);
  21.     RTC_WaitForLastTask();
  22. }
5、定义时间的结构体以及用于星期、月份大小的数组,如果大家用不到星期等可以不用定义:
  1. typedef struct
  2. {
  3.     vu8 hour;
  4.     vu8 min;
  5.     vu8 sec;

  6.     vu16 w_year;
  7.     vu8  w_month;
  8.     vu8  w_date;
  9.     vu8  week;
  10. } _calendar_obj;
  11. _calendar_obj calendar;

  12. u8 const table_week[12] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
  13. const u8 mon_table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
6、判断是不是闰年:
  1. /*********************************************************************
  2. * @fn      Is_Leap_Year
  3. *
  4. * @brief   Judging whether it is a leap year.
  5. *
  6. * [url=home.php?mod=space&uid=3142012]@param[/url]   year
  7. *
  8. * @return  1 - Yes
  9. *          0 - No
  10. */
  11. u8 Is_Leap_Year(u16 year)
  12. {
  13.     if(year % 4 == 0)
  14.     {
  15.         if(year % 100 == 0)
  16.         {
  17.             if(year % 400 == 0)
  18.                 return 1;
  19.             else
  20.                 return 0;
  21.         }
  22.         else
  23.             return 1;
  24.     }
  25.     else
  26.         return 0;
  27. }
7、获取星期:
  1. /*********************************************************************
  2. * @fn      RTC_Get_Week
  3. *
  4. * @brief   Get the current day of the week.
  5. *
  6. * @param   year/month/day
  7. *
  8. * @return  week
  9. */
  10. u8 RTC_Get_Week(u16 year, u8 month, u8 day)
  11. {
  12.     u16 temp2;
  13.     u8  yearH, yearL;

  14.     yearH = year / 100;
  15.     yearL = year % 100;
  16.     if(yearH > 19)
  17.         yearL += 100;
  18.     temp2 = yearL + yearL / 4;
  19.     temp2 = temp2 % 7;
  20.     temp2 = temp2 + day + table_week[month - 1];
  21.     if(yearL % 4 == 0 && month < 3)
  22.         temp2--;
  23.     return (temp2 % 7);
  24. }
8、时间设置:
  1. /*********************************************************************
  2. * @fn      RTC_Set
  3. *
  4. * @brief   Set Time.
  5. *
  6. * @param   Struct of _calendar_obj
  7. *
  8. * @return  1 - error
  9. *          0 - success
  10. */
  11. u8 RTC_Set(u16 syear, u8 smon, u8 sday, u8 hour, u8 min, u8 sec)
  12. {
  13.     u16 t;
  14.     u32 seccount = 0;
  15.     if(syear < 1970 || syear > 2099)
  16.         return 1;
  17.     for(t = 1970; t < syear; t++)
  18.     {
  19.         if(Is_Leap_Year(t))
  20.             seccount += 31622400;
  21.         else
  22.             seccount += 31536000;
  23.     }
  24.     smon -= 1;
  25.     for(t = 0; t < smon; t++)
  26.     {
  27.         seccount += (u32)mon_table[t] * 86400;
  28.         if(Is_Leap_Year(syear) && t == 1)
  29.             seccount += 86400;
  30.     }
  31.     seccount += (u32)(sday - 1) * 86400;
  32.     seccount += (u32)hour * 3600;
  33.     seccount += (u32)min * 60;
  34.     seccount += sec;

  35.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
  36.     PWR_BackupAccessCmd(ENABLE);
  37.     RTC_SetCounter(seccount);
  38.     RTC_WaitForLastTask();
  39.     return 0;
  40. }
9、获取时间:这里的时间直接存入到全局结构体calendar中,如果哪里需要,直接读取这个结构的内空就行了,因为中断函数定时执行了RTC_Get函数。
  1. /*********************************************************************
  2. * @fn      RTC_Get
  3. *
  4. * @brief   Get current time.
  5. *
  6. * @return  1 - error
  7. *          0 - success
  8. */
  9. u8 RTC_Get(void)
  10. {
  11.     static u16 daycnt = 0;
  12.     u32        timecount = 0;
  13.     u32        temp = 0;
  14.     u16        temp1 = 0;
  15.     timecount = RTC_GetCounter();
  16.     temp = timecount / 86400;
  17.     if(daycnt != temp)
  18.     {
  19.         daycnt = temp;
  20.         temp1 = 1970;
  21.         while(temp >= 365)
  22.         {
  23.             if(Is_Leap_Year(temp1))
  24.             {
  25.                 if(temp >= 366)
  26.                     temp -= 366;
  27.                 else
  28.                 {
  29.                     temp1++;
  30.                     break;
  31.                 }
  32.             }
  33.             else
  34.                 temp -= 365;
  35.             temp1++;
  36.         }
  37.         calendar.w_year = temp1;
  38.         temp1 = 0;
  39.         while(temp >= 28)
  40.         {
  41.             if(Is_Leap_Year(calendar.w_year) && temp1 == 1)
  42.             {
  43.                 if(temp >= 29)
  44.                     temp -= 29;
  45.                 else
  46.                     break;
  47.             }
  48.             else
  49.             {
  50.                 if(temp >= mon_table[temp1])
  51.                     temp -= mon_table[temp1];
  52.                 else
  53.                     break;
  54.             }
  55.             temp1++;
  56.         }
  57.         calendar.w_month = temp1 + 1;
  58.         calendar.w_date = temp + 1;
  59.     }
  60.     temp = timecount % 86400;
  61.     calendar.hour = temp / 3600;
  62.     calendar.min = (temp % 3600) / 60;
  63.     calendar.sec = (temp % 3600) % 60;
  64.     calendar.week = RTC_Get_Week(calendar.w_year, calendar.w_month, calendar.w_date);
  65.     return 0;
  66. }
10、把需要用的函数在rtc.h中声明,基本的驱动就OK了。当然还有闹钟,我这里就没有写了。
11、在主函数中调引用rtc.h初始化RTC,然后书写一个显示时钟的函数,在main中定期调用就OK了。
  1. void show_rtc(void)
  2. {

  3.     u8g2_ClearBuffer(&u8g2);
  4.     sprintf(str_rtc_date,"%04d-%02d-%02d",calendar.w_year,calendar.w_month,calendar.w_date);
  5.     sprintf(str_time,"%02d:%02d:%02d", calendar.hour,calendar.min,calendar.sec);
  6.     u8g2_SetFont(&u8g2,u8g2_font_t0_22b_tr);
  7.     u8g2_DrawStr(&u8g2, 10, 20, str_rtc_date);
  8.     //u8g2_SendBuffer(&u8g2);
  9.     u8g2_SetFont(&u8g2,u8g2_font_profont29_tf);
  10.     u8g2_DrawStr(&u8g2, 0, 60, str_time);
  11.     u8g2_SendBuffer(&u8g2);
  12. }
【总结】这个例程学习的如何初始化RTC,以及设设置RTC中断。


RTC

更多回帖

×
发帖