[MM32软件] 【灵动微电子MM32F5330测评】6.SPI驱动LCD屏幕+RTC时钟测试

[复制链接]
 楼主| yuyy1989 发表于 2024-7-1 22:28 | 显示全部楼层 |阅读模式
<
SPI是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线(CS、SCK、MOSI、MISO),根据实际使用情况可以只用其中的2根或3根。
MISO:主设备输入、从设备输出引脚。传输方向为从设备发送到主设备。
MOSI:主设备输出、从设备输入引脚。传输方向为主设备发送到从设备。
SCK:串口时钟,由主设备产生并提供给从设备。
NSS:从设备选择。
微信截图_20240701222747.png
开发板上集成了一颗W25Q80,这是一颗容量为 8M-bit的串行 Flash 存储器
微信截图_20240701194704.png
例程里有读写代码这里就不重复实现了,换用SPI驱动LCD显示屏。
驱动这块屏幕需要用到5个IO:CS、RST、A0、SCK、MOSI
微信截图_20240701202739.png
初始化SPI,只用发送模式就行,手动控制CS、RST、A0

  1. void APP_SpiInit(void)
  2. {
  3.     GPIO_InitTypeDef GPIO_InitStruct;
  4.     SPI_InitTypeDef  SPI_InitStruct;

  5.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
  6.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);

  7.     SPI_StructInit(&SPI_InitStruct);
  8.     SPI_InitStruct.SPI_Mode      = SPI_Mode_Master;
  9.     SPI_InitStruct.SPI_DataSize  = SPI_DataSize_8b;
  10.     SPI_InitStruct.SPI_DataWidth = 8;
  11.     SPI_InitStruct.SPI_CPOL      = SPI_CPOL_High;
  12.     SPI_InitStruct.SPI_CPHA      = SPI_CPHA_2Edge;
  13.     SPI_InitStruct.SPI_NSS       = SPI_NSS_Soft;
  14.     SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
  15.     SPI_InitStruct.SPI_FirstBit  = SPI_FirstBit_MSB;
  16.     SPI_Init(SPI1, &SPI_InitStruct);

  17.     SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Tx);

  18.     GPIO_PinAFConfig(GPIOB, GPIO_PinSource3,  GPIO_AF_5);
  19.     GPIO_PinAFConfig(GPIOB, GPIO_PinSource5,  GPIO_AF_5);

  20.     GPIO_StructInit(&GPIO_InitStruct);
  21.     GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_3 | GPIO_Pin_5;
  22.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
  23.     GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF_PP;
  24.     GPIO_Init(GPIOB, &GPIO_InitStruct);

  25.     SPI_Cmd(SPI1, ENABLE);
  26. }

  27. void APP_SpiWriteByte(SPI_TypeDef *spix,uint8_t dat)
  28. {
  29.     SPI_SendData(spix, dat);
  30.     while (RESET == SPI_GetFlagStatus(spix, SPI_FLAG_TXEPT));
  31. }

  32. YUYY_HS12864G18B_DEV_Type lcd_dev;
  33. YUYY_GPIO_DEV_Type gpio_cs;
  34. YUYY_GPIO_DEV_Type gpio_rst;
  35. YUYY_GPIO_DEV_Type gpio_a0;
  36. void APP_LcdInit(void)
  37. {
  38.     GPIO_InitTypeDef GPIO_InitStruct;
  39.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
  40.     GPIO_StructInit(&GPIO_InitStruct);
  41.     GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_4 | GPIO_Pin_6 | GPIO_Pin_7;
  42.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
  43.     GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_Out_PP;
  44.     GPIO_Init(GPIOB, &GPIO_InitStruct);
  45.    
  46.     gpio_cs.gpio = GPIOB;
  47.     gpio_cs.pin = GPIO_Pin_6;
  48.     gpio_a0.gpio = GPIOB;
  49.     gpio_a0.pin = GPIO_Pin_4;
  50.     gpio_rst.gpio = GPIOB;
  51.     gpio_rst.pin = GPIO_Pin_7;
  52.    
  53.     lcd_dev.cs_pin = &gpio_cs;
  54.     lcd_dev.a0_pin = &gpio_a0;
  55.     lcd_dev.rst_pin = &gpio_rst;
  56.     lcd_dev.spix = SPI1;
  57.     lcd_dev.spi_sendbyte_func = (YUYY_HS12864G18B_SpiWriteByteFunc_Type)APP_SpiWriteByte;
  58.     lcd_dev.gpio_setlev_func = (YUYY_HS12864G18B_GPIO_SetLevFunc_Type)YUYY_GPIO_SetLev;
  59.     lcd_dev.delayus_func = (YUYY_HS12864G18B_DelayUsFunc_Type)YUYY_DelayUs;
  60.    
  61.     YUYY_HS12864G18B_Init(&lcd_dev);
  62.     YUYY_HS12864G18B_ClearScreen(&lcd_dev);
  63.     YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,0,0," MM32F5330 TEST");
  64.     YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,2,0,"   LCD use SPI");
  65.     YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,4,0,"  bbs.21ic.com");
  66.     YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,6,0,"Code by yuyy1989");
  67.     YUYY_HS12864G18B_DisplayFinish(&lcd_dev);
  68. }
运行效果
微信截图_20240701222536.png
实时时钟(RTC)是嵌入式系统中的一种重要组件,它提供了精确的时间跟踪功能,即使在系统关机时也能保持准确。RTC通常由一个专用的硬件模块组成,用于跟踪当前的年、月、日、时、分、秒以及星期等时间信息。MM32F5330的RTC模块内部包含一组连续计数的计数器。它作为一个独立的定时器,在相应软件配置下,可提供时钟功能。修改计数器的值可以重新设置系统当前的时间。MM32F5330的RTC提供的是一个32位的计数器,需要自行实现秒到日期时间的转换
  1. enum
  2. {
  3.     YUYY_TIME_WEEK_SUNDAY = 0,
  4.     YUYY_TIME_WEEK_MONDAY,
  5.     YUYY_TIME_WEEK_TUESDAY,
  6.     YUYY_TIME_WEEK_WEDNESDAY,
  7.     YUYY_TIME_WEEK_THURSDAY,
  8.     YUYY_TIME_WEEK_FRIDAY,
  9.     YUYY_TIME_WEEK_SATURDAY,
  10. };
  11. typedef struct
  12. {
  13.     uint8_t month;
  14.     uint8_t day;
  15.     uint8_t week;
  16.     uint8_t hour;
  17.     uint8_t minutes;
  18.     uint8_t seconds;
  19.     uint16_t year;
  20. } YUYY_DateTimeType;
  21. const uint8_t kMonthDays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  22. bool YUYY_TIME_IsLeapYear(uint16_t year)
  23. {
  24.     if(year%100!=0)
  25.     {
  26.         return (year%4==0);
  27.     }
  28.     else
  29.     {
  30.         return (year%400==0);
  31.     }
  32. }
  33. uint32_t YUYY_TIME_GetSecondFromDateTime(YUYY_DateTimeType *datetime,uint16_t since_year)
  34. {
  35.     uint16_t i = 0,leap_count = 0;
  36.     uint32_t alldays = 0;
  37.     if(datetime->year < since_year)
  38.         return 0;
  39.     i = since_year;
  40.     while (i < datetime->year)
  41.     {
  42.         if(YUYY_TIME_IsLeapYear(i))
  43.             leap_count += 1;
  44.         i+=1;
  45.     }
  46.     alldays = (datetime->year - since_year)*365+leap_count;
  47.     printf("%d \n",leap_count);
  48.     i = 1;
  49.     while (i < datetime->month)
  50.     {
  51.         if(i == 2 && YUYY_TIME_IsLeapYear(datetime->year))
  52.             alldays += 29;
  53.         else
  54.             alldays += kMonthDays[i-1];
  55.         i+=1;
  56.     }
  57.     alldays += datetime->day - 1;
  58.     return alldays*24*3600 + datetime->hour*3600 + datetime->minutes*60 + datetime->seconds;
  59. }
  60. void YUYY_TIME_GetDateTimeFromSecond(uint32_t sec,YUYY_DateTimeType *datetime,uint16_t since_year,uint8_t since_week)
  61. {
  62.     uint16_t i = 0,leap_count = 0;
  63.     uint32_t alldays = 0;
  64.     datetime->seconds = sec%60;
  65.     sec /= 60;
  66.     datetime->minutes = sec%60;
  67.     sec /= 60;
  68.     datetime->hour = sec%24;
  69.     alldays = sec/24;
  70.     i = since_year;
  71.     datetime->week = ((alldays%7)+since_week)%7;
  72.     while (alldays > 365)
  73.     {
  74.         alldays -= 365;
  75.         if(YUYY_TIME_IsLeapYear(i))
  76.         {
  77.             if(alldays>0)
  78.                 alldays -= 1;
  79.             else
  80.                 break;
  81.         }
  82.         i+=1;
  83.     }
  84.     datetime->year = i;
  85.     i = 0;
  86.     while (alldays >= kMonthDays[i])
  87.     {
  88.         alldays -= kMonthDays[i];
  89.         if(i == 1 && YUYY_TIME_IsLeapYear(datetime->year))
  90.         {
  91.             if(alldays > 0)
  92.                 alldays -= 1;
  93.             else
  94.                 break;
  95.         }
  96.         i+=1;
  97.     }
  98.     datetime->month = i+1;
  99.     datetime->day = alldays+1;
  100. }

初始化RTC
  1. void APP_RTCInit(void)
  2. {

  3.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWRDBG | RCC_APB1Periph_BKP, ENABLE);
  4.     PWR_BackupAccessCmd(ENABLE);
  5.     BKP_DeInit();
  6.     if (BKP_ReadBackupRegister(BKP_DR1) != 0x5B5B)
  7.     {
  8.         RCC_LSEConfig(RCC_LSE_ON);

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

  12.         RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
  13.         RCC_RTCCLKCmd(ENABLE);
  14.         RTC_WaitForSynchro();
  15.         RTC_WaitForLastTask();
  16.         RTC_WaitForLastTask();
  17.         RTC_SetPrescaler(32767);
  18.         RTC_WaitForLastTask();
  19.         RTC_SetCounter(0);
  20.         RTC_WaitForLastTask();
  21.         BKP_WriteBackupRegister(BKP_DR1, 0x5B5B);
  22.     }
  23.     else
  24.     {
  25.         RTC_WaitForSynchro();
  26.         RTC_WaitForLastTask();
  27.     }
  28. }

按下按键后修改为指定的时间
  1. #define RTC_START_YEAR 2024
  2. #define RTC_START_WEEK YUYY_TIME_WEEK_MONDAY
  3. char *WeekdayStr[7]= {"SUN","MON","TUE","WED","THU","FRI","SAT"};
  4. void APP_SetTestRTC(void)
  5. {
  6.     YUYY_DateTimeType datetime;
  7.     datetime.year = 2024;
  8.     datetime.month = 6;
  9.     datetime.day = 30;
  10.     datetime.hour = 20;
  11.     datetime.minutes = 30;
  12.     datetime.seconds = 30;
  13.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWRDBG | RCC_APB1Periph_BKP, ENABLE);
  14.     PWR_BackupAccessCmd(ENABLE);
  15.     RTC_SetCounter(YUYY_TIME_GetSecondFromDateTime(&datetime,RTC_START_YEAR));
  16.     RTC_WaitForLastTask();
  17. }

打印时间到LCD屏幕
  1. int main(void)
  2. {
  3.     char out[20];
  4.     YUYY_DateTimeType datetime;
  5.     uart_init();
  6.     led_init();
  7.     keys_init();
  8.     exit_init();
  9.     APP_SpiInit();
  10.     APP_LcdInit();
  11.     APP_RTCInit();
  12.     while (1)
  13.     {
  14.         YUYY_DelayMs(1000);
  15.         led_toggle(LED_NO_1);
  16.         YUYY_TIME_GetDateTimeFromSecond(RTC_GetCounter(),&datetime,RTC_START_YEAR,RTC_START_WEEK);
  17.         sprintf(out," %04d-%02d-%02d %s ",datetime.year, datetime.month, datetime.day,WeekdayStr[datetime.week]);
  18.         YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,2,0,out);
  19.         sprintf(out,"    %02d:%02d:%02d    ",datetime.hour, datetime.minutes, datetime.seconds);
  20.         YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,4,0,out);
  21.     }
  22. }

运行效果
WeChat_20240701222542 00_00_00-00_00_30.gif

地瓜patch 发表于 2024-7-30 22:36 | 显示全部楼层
用片内rtc么
suncat0504 发表于 2024-7-31 19:30 | 显示全部楼层
帖子排版很舒服,楼主用心了。谢谢分享!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:同飞软件研发工程师
简介:制冷系统单片机软件开发,使用PID控制温度

161

主题

815

帖子

10

粉丝
快速回复 在线客服 返回列表 返回顶部
认证:同飞软件研发工程师
简介:制冷系统单片机软件开发,使用PID控制温度

161

主题

815

帖子

10

粉丝
快速回复 在线客服 返回列表 返回顶部