[MM32硬件] 【灵动微电子MM32F0121测评】4、RTC实时时钟

[复制链接]
 楼主| 发表于 2025-6-13 16:07 | 显示全部楼层 |阅读模式
本文实现RTC实时时钟,以点阵屏形式显示。

关于RTC实时时钟,SDK中有完整的例子,可以不用修改就直接使用:
LibSamples_MM32F0120_V1.13.4\Samples\LibSamples\RTC\RTC_Calendar

在此基础上加上显示部分就可以完成本实验。


1、RTC配置
RTC_Configure完成:
RTC模块的初始化配置(使用LSE作为时钟源)
通过备份寄存器判断是否需要重新配置RTC
配置RTC秒中断
设置中断优先级和使能
加载默认RTC值

  1. void RTC_Configure(void)
  2. {
  3.     NVIC_InitTypeDef NVIC_InitStruct;

  4.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_RTC | RCC_APB1Periph_BKP, ENABLE);

  5.     PWR_BackupAccessCmd(ENABLE);

  6.     BKP_DeInit();

  7.     if (BKP_ReadBackupRegister(BKP_DR1) != 0x5B5B)
  8.     {
  9.         RCC_LSEConfig(RCC_LSE_ON);

  10.         while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
  11.         {
  12.         }

  13.         RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);

  14.         RCC_RTCCLKCmd(ENABLE);

  15.         RTC_WaitForSynchro();
  16.         RTC_WaitForLastTask();

  17.         RTC_ITConfig(RTC_IT_SEC, ENABLE);
  18.         RTC_WaitForLastTask();

  19.         RTC_SetPrescaler(32767);
  20.         RTC_WaitForLastTask();

  21.         printf("\r\n%s", __FUNCTION__);

  22.         BKP_WriteBackupRegister(BKP_DR1, 0x5B5B);
  23.     }
  24.     else
  25.     {
  26.         printf("\r\nNeed't to configure RTC.");

  27.         RTC_WaitForSynchro();

  28.         RTC_ITConfig(RTC_IT_SEC, ENABLE);
  29.         RTC_WaitForLastTask();
  30.     }

  31.     NVIC_InitStruct.NVIC_IRQChannel = RTC_BKP_IRQn;
  32.     NVIC_InitStruct.NVIC_IRQChannelPriority = 0;
  33.     NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  34.     NVIC_Init(&NVIC_InitStruct);

  35.     RTC_LoadDefault();
  36. }



2、RTC_BKP_IRQHandler中断处理
RTC(实时时钟)和 BKP(备份寄存器)共用的中断源
实际上包含多个可能的中断事件,主要分:
秒中断(RTC_IT_SEC)
闹钟中断(RTC_IT_ALR)
溢出中断(RTC_IT_OW)

本例中,用于更新时间显示RTC_UpdateCalendar
打印时间RTC_PrintDateTime
  1. void RTC_BKP_IRQHandler(void)
  2. {
  3.     if (RESET != RTC_GetITStatus(RTC_IT_SEC))
  4.     {
  5.         RTC_UpdateCalendar();
  6.         RTC_PrintDateTime();

  7.         RTC_ClearITPendingBit(RTC_IT_SEC);
  8.         RTC_WaitForLastTask();
  9.     }
  10. }
3、RTC_UpdateCalendar()更新时间
  1. void RTC_UpdateCalendar(void)
  2. {
  3.     static uint32_t PreTotalDay = 0;
  4.     uint32_t TotalSecond = 0;
  5.     uint32_t TotalDay    = 0;
  6.     uint16_t Year  = 1970;
  7.     uint8_t  Month = 0;

  8.     TotalSecond = RTC_GetCounter();
  9.     TotalDay    = TotalSecond / 86400;

  10.     if (PreTotalDay != TotalDay)
  11.     {
  12.         PreTotalDay = TotalDay;

  13.         while (TotalDay >= 365)
  14.         {
  15.             if (RTC_LeapYear(Year) == 1)
  16.             {
  17.                 if (TotalDay >= 366)
  18.                 {
  19.                     TotalDay -= 366;
  20.                 }
  21.                 else
  22.                 {
  23.                     break;
  24.                 }
  25.             }
  26.             else
  27.             {
  28.                 TotalDay -= 365;
  29.             }

  30.             Year++;
  31.         }

  32.         RTC_Calendar.year = Year;

  33.         while (TotalDay >= 28)
  34.         {
  35.             if ((Month == 1) && (RTC_LeapYear(RTC_Calendar.year) == 1))
  36.             {
  37.                 if (TotalDay >= 29)
  38.                 {
  39.                     TotalDay -= 29;
  40.                 }
  41.                 else
  42.                 {
  43.                     break;
  44.                 }
  45.             }
  46.             else
  47.             {
  48.                 if (TotalDay >= RTC_DayOfMonth[Month])
  49.                 {
  50.                     TotalDay -= RTC_DayOfMonth[Month];
  51.                 }
  52.                 else
  53.                 {
  54.                     break;
  55.                 }
  56.             }

  57.             Month++;
  58.         }

  59.         RTC_Calendar.month = Month + 1;
  60.         RTC_Calendar.day   = TotalDay + 1;

  61.         RTC_Calendar.week  = RTC_GetWeek(RTC_Calendar.year, RTC_Calendar.month, RTC_Calendar.day);
  62.     }

  63.     RTC_Calendar.hour   = (TotalSecond % 86400) / 3600;
  64.     RTC_Calendar.minute = ((TotalSecond % 86400) % 3600) / 60;
  65.     RTC_Calendar.second = ((TotalSecond % 86400) % 3600) % 60;
  66. }


4、RTC_PrintDateTime打印时间
  1. void RTC_PrintDateTime(void)
  2. {
  3.     printf("\r\n%04d-%02d-%02d", RTC_Calendar.year, RTC_Calendar.month, RTC_Calendar.day);

  4.     switch (RTC_Calendar.week)
  5.     {
  6.         case 0:
  7.             printf(" SUN ");
  8.             break;

  9.         case 1:
  10.             printf(" MON ");
  11.             break;

  12.         case 2:
  13.             printf(" TUE ");
  14.             break;

  15.         case 3:
  16.             printf(" WED ");
  17.             break;

  18.         case 4:
  19.             printf(" THU ");
  20.             break;

  21.         case 5:
  22.             printf(" FRI ");
  23.             break;

  24.         case 6:
  25.             printf(" SAT ");
  26.             break;

  27.         default:
  28.             break;
  29.     }

  30.     printf("%02d:%02d:%02d\r\n", RTC_Calendar.hour, RTC_Calendar.minute, RTC_Calendar.second);
  31.                
  32.                
  33.        
  34. }


5、增加自己的时间显示
因为用到74hc595驱动点阵屏,74hc595没有输出锁定功能,需要将相关的点阵屏驱动放在while(1)中不断刷新。
  1. void RTC_Calendar_Sample(void)
  2. {
  3.     printf("\r\nTest %s", __FUNCTION__);

  4.                 //初始化LED点阵屏
  5.                 config_led_matrix_gpio();
  6.        
  7.                 //配置RTC
  8.     RTC_Configure();

  9.     while (1)
  10.     {
  11.         //PLATFORM_LED_Toggle(LED1);
  12.         //PLATFORM_DelayMS(100);
  13.                        
  14.                                 //在LED点阵屏上显示
  15.                         clear_screen();
  16.                         vs_clear_screen();
  17.                        
  18.                         //填充小时
  19.                         fill_num_to_buffer(0,0,RTC_Calendar.hour/10);
  20.                         fill_num_to_buffer(4,0,RTC_Calendar.hour%10);
  21.                         //填充:
  22.                         fill_num_to_buffer(8,0,10);
  23.                         //填充小时
  24.                         fill_num_to_buffer(12,0,RTC_Calendar.minute/10);
  25.                         fill_num_to_buffer(16,0,RTC_Calendar.minute%10);
  26.                         //填充:
  27.                         fill_num_to_buffer(20,0,10);
  28.                         //填充秒钟
  29.                         fill_num_to_buffer(24,0,RTC_Calendar.second/10);
  30.                         fill_num_to_buffer(28,0,RTC_Calendar.second%10);
  31.                        
  32.                         vs_render_screen();
  33.                         render_screen_to_matrix8x24();
  34.     }
  35. }
6、点阵屏的驱动

  1. #include "hc595.h"
  2. #include "hal_conf.h"

  3. //位置,595扫描的行/列
  4. //COM
  5. const uint8_t pos[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
  6. //显示缓存 7*11*4=7*44,使用8*48缓存
  7. //SEG,实际屏幕,节约空间
  8. uint8_t matrix3[48]={0x00};

  9. // 虚拟屏幕
  10. uint8_t virtual_screen[SCREEN_WIDTH][SCREEN_HEIGHT]={0};

  11. unsigned char bigNUM[]=
  12. {
  13. /* 3*7数字字模,上下顶到头,空左边一列*/
  14. 0x07,0x05,0x05,0x05,0x05,0x05,0x07, /*0*/
  15. 0x02,0x02,0x02,0x02,0x02,0x02,0x02, /*1*/
  16. 0x07,0x01,0x01,0x07,0x04,0x04,0x07, /*2*/
  17. 0x07,0x01,0x01,0x07,0x01,0x01,0x07, /*3*/
  18. 0x05,0x05,0x05,0x07,0x01,0x01,0x01, /*4*/
  19. 0x07,0x04,0x04,0x07,0x01,0x01,0x07, /*5*/
  20. 0x07,0x04,0x04,0x07,0x05,0x05,0x07, /*6*/
  21. 0x07,0x01,0x01,0x01,0x01,0x01,0x01, /*7*/
  22. 0x07,0x05,0x05,0x07,0x05,0x05,0x07, /*8*/
  23. 0x07,0x05,0x05,0x07,0x01,0x01,0x07, /*9*/
  24. 0x00,0x02,0x00,0x00,0x00,0x02,0x00, /*:*/
  25. 0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*空,补位*/
  26. };

  27. unsigned char smallNUM[]=
  28. {
  29. /* 4*7数字字模,上下各空一行,空左边一列*/
  30. 0x00,0x07,0x05,0x05,0x05,0x07,0x00, /*0*/
  31. 0x00,0x02,0x02,0x02,0x02,0x02,0x00, /*1*/
  32. 0x00,0x07,0x01,0x07,0x04,0x07,0x00, /*2*/
  33. 0x00,0x07,0x01,0x07,0x01,0x07,0x00, /*3*/
  34. 0x00,0x05,0x05,0x07,0x01,0x01,0x00, /*4*/
  35. 0x00,0x07,0x04,0x07,0x01,0x07,0x00, /*5*/
  36. 0x00,0x07,0x04,0x07,0x05,0x07,0x00, /*6*/
  37. 0x00,0x07,0x01,0x01,0x01,0x01,0x00, /*7*/
  38. 0x00,0x07,0x05,0x07,0x05,0x07,0x00, /*8*/
  39. 0x00,0x07,0x05,0x07,0x01,0x07,0x00, /*9*/
  40. 0x00,0x00,0x02,0x00,0x02,0x00,0x00, /*:*/
  41. 0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*空,补位*/
  42. };



  43. void config_led_matrix_gpio(void)
  44. {
  45.     GPIO_InitTypeDef GPIO_InitStruct;

  46.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
  47.                 RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOD, ENABLE);

  48.     GPIO_StructInit(&GPIO_InitStruct);
  49.     GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_9 | GPIO_Pin_11 | GPIO_Pin_15;
  50.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
  51.     GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_Out_PP;
  52.     GPIO_Init(GPIOA, &GPIO_InitStruct);
  53.        

  54.     GPIO_StructInit(&GPIO_InitStruct);
  55.     GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_3;
  56.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
  57.     GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_Out_PP;
  58.     GPIO_Init(GPIOD, &GPIO_InitStruct);       
  59.        
  60.                 LED_OE_CLR;
  61. }
  62. /*
  63. *  PN:反显
  64. * */
  65. void HC595(uint8_t c,uint8_t PN)
  66. {
  67.     uint8_t i;
  68.     for(i=0;i<8;i++){

  69.         if(PN==0){                       //正常显示
  70.             if((c>>i) & 0x01) LED_SER_SET;
  71.             else LED_SER_CLR;
  72.         }
  73.         else{                                //反显
  74.             if((c>>i) & 0x01) LED_SER_CLR;
  75.             else LED_SER_SET;
  76.         }

  77.         LED_SRCK_CLR;
  78.         LED_SRCK_SET;     // 上升沿进行一次数据移入
  79.     }
  80. }

  81. void clear_screen(void)
  82. {
  83.         uint8_t i;
  84.     for ( i = 0; i < 48; i++) {
  85.         matrix3[i]=0x00;
  86.     }
  87. }

  88. //紧凑缓存画点
  89. void draw_pixel(uint8_t x,uint8_t y)
  90. {
  91.     uint8_t mx,my;

  92.     if (x>21) x=x+2;

  93.     mx=5-x/8;
  94.     my=y+1;

  95.     matrix3[mx*8+my]|=1<<(7-x%8);
  96. }




  97. //控制闪烁的措施,如果点灯少就多循环显示,否则少循环显示
  98. uint8_t count_ones(uint8_t i) {
  99.     uint8_t count = 0;
  100.     while (i != 0) {
  101.         i &= (i - 1); // 清除最低位的1
  102.         count++;
  103.     }
  104.     return count;
  105. }

  106. //将紧凑缓存内容显示在LED矩阵上,没有虚拟屏直接显示的函数
  107. //pBuff通常是matrix3,
  108. void render_screen_to_matrix8x24(void)
  109. {
  110.                 uint8_t *pBuff=matrix3;
  111.     uint8_t k;
  112.     uint16_t m,n;

  113.      for(m=0;m<32*2;m++)    //为移动预留
  114.      {

  115.          for(k=0;k<7;k++)   //行扫描
  116.          {
  117.              for(n=0;n<(count_ones(pBuff[k])+count_ones(pBuff[k+8])+count_ones(pBuff[k+16])+count_ones(pBuff[k+24])
  118.              +count_ones(pBuff[k+32])+count_ones(pBuff[k+40]))*2;n++)//控制显示速度,防止闪烁
  119.                                                
  120.              {

  121.                  HC595(~pos[k],0);
  122.                  HC595(pBuff[k],0);
  123.                  HC595(pBuff[k+8],0);
  124.                  HC595(pBuff[k+16],0);

  125.                  HC595(~pos[k],0);
  126.                  HC595(pBuff[k+24],0);
  127.                  HC595(pBuff[k+32],0);
  128.                  HC595(pBuff[k+40],0);
  129.                  LED_RCK_CLR;
  130.                  LED_RCK_SET;    //并行输出
  131.                                                                 __nop();__nop();
  132.                  
  133.              }


  134.           }
  135.      }
  136.     //传COM -

  137.     //传SEG +
  138. }



  139. //虚拟屏清屏
  140. void vs_clear_screen(void)
  141. {
  142.         uint8_t x,y;
  143.     for ( y = 0; y < SCREEN_HEIGHT; y++) {
  144.         for ( x = 0; x < SCREEN_WIDTH; x++) {
  145.             virtual_screen[x][y] = 0;
  146.         }
  147.     }
  148. }

  149. //虚拟屏画点
  150. void vs_drawpixel(uint8_t x,uint8_t y)
  151. {
  152.     virtual_screen[x][y]=1;
  153. }

  154. void vs_clearpixel(uint8_t x,uint8_t y)
  155. {
  156.         virtual_screen[x][y]=0;
  157. }

  158. //虚拟屏复制到紧凑缓存
  159. void vs_render_screen(void)
  160. {
  161.         uint8_t x,y;
  162.     //clear_screen();
  163.     for ( y = 0; y < SCREEN_HEIGHT; y++) {
  164.         for ( x = 0; x < SCREEN_WIDTH; x++) {
  165.             if (virtual_screen[x][y]) {
  166.                 draw_pixel(x, y); // 画点
  167.             } else {
  168.                 // 如果需要清除点,可以调用清屏函数或设置背景色
  169.             }
  170.         }
  171.     }
  172. }

  173. /*
  174. * 填充数字到屏幕位置,写物理和虚拟缓存
  175. * (x,y)是显示位置坐标;NUM是要显示的数字
  176. */
  177. void fill_num_to_buffer(uint8_t x,uint8_t y,uint8_t num)
  178. {
  179.     uint8_t i,j;

  180.     for(i=0;i<7;i++)
  181.     {
  182.         for(j=0;j<4;j++)
  183.         {
  184.             if(((smallNUM[num*7+i]>>j)&0x01)==0x01)
  185.             {
  186.                 //draw_pixel(x+4-j, y+i);
  187.                 vs_drawpixel(x+4-j, y+i);
  188.             }
  189.                                                 else
  190.                                                 {
  191.                                                         vs_clearpixel(x+4-j, y+i);
  192.                                                 }
  193.         }
  194.     }
  195. }


  196. void hc595_test(void)
  197. {
  198.                 config_led_matrix_gpio();
  199.        

  200.        
  201.                 while(1)
  202.                 {
  203.                                         vs_clear_screen();
  204.     fill_num_to_buffer(0,0,0);
  205.     fill_num_to_buffer(4,0,1);
  206.     fill_num_to_buffer(8,0,2);
  207.     fill_num_to_buffer(12,0,3);
  208.     fill_num_to_buffer(16,0,4);
  209.     fill_num_to_buffer(20,0,5);
  210.     fill_num_to_buffer(24,0,6);
  211.     fill_num_to_buffer(28,0,7);
  212.     fill_num_to_buffer(32,0,8);
  213.     fill_num_to_buffer(36,0,9);
  214.        
  215.     vs_render_screen();
  216.                         render_screen_to_matrix8x24();
  217.                 }
  218. }
6、效果

1.jpg

tutieshi_640x362_4s.gif


您需要登录后才可以回帖 登录 | 注册

本版积分规则

84

主题

147

帖子

3

粉丝
快速回复 返回顶部 返回列表