[活动] 【APM32F411V Tiny Board测评】5.SPI驱动LCD并显示RTC时间

[复制链接]
 楼主| yuyy1989 发表于 2024-5-12 17:58 | 显示全部楼层 |阅读模式
要驱动的屏幕是这个
微信截图_20240512174929.png 微信截图_20240512174944.png
选用PA5和PA7作为SCK 和MOSI,PA4 PA6 PA8分别作为CS RST A0
微信截图_20240512101918.png
初始化SPI,用只发送模式
  1. void spi_init()
  2. {
  3.     GPIO_Config_T GPIO_InitStructure;
  4.     SPI_Config_T  SPI1_InitStructure;
  5.     RCM_EnableAHB1PeriphClock (RCM_AHB1_PERIPH_GPIOA);
  6.     RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SPI1);
  7.    
  8.     GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_5, GPIO_AF_SPI1);
  9.     GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_7, GPIO_AF_SPI1);
  10.    
  11.     GPIO_ConfigStructInit(&GPIO_InitStructure);
  12.     GPIO_InitStructure.pin = GPIO_PIN_5 | GPIO_PIN_7;
  13.     GPIO_InitStructure.speed = GPIO_SPEED_100MHz;
  14.     GPIO_InitStructure.mode = GPIO_MODE_AF;
  15.     GPIO_InitStructure.otype = GPIO_OTYPE_PP;
  16.     GPIO_InitStructure.pupd = GPIO_PUPD_NOPULL;
  17.     GPIO_Config(GPIOA, &GPIO_InitStructure);
  18.    
  19.     SPI_ConfigStructInit(&SPI1_InitStructure);
  20.     SPI1_InitStructure.direction = SPI_DIRECTION_1LINE_TX;
  21.     SPI1_InitStructure.mode = SPI_MODE_MASTER;
  22.     SPI1_InitStructure.length = SPI_DATA_LENGTH_8B;
  23.     SPI1_InitStructure.polarity = SPI_CLKPOL_HIGH;
  24.     SPI1_InitStructure.phase = SPI_CLKPHA_2EDGE;
  25.     SPI1_InitStructure.nss = SPI_NSS_SOFT;
  26.     SPI1_InitStructure.baudrateDiv = SPI_BAUDRATE_DIV_8;
  27.     SPI1_InitStructure.firstBit = SPI_FIRSTBIT_MSB;
  28.     SPI1_InitStructure.crcPolynomial = 7;
  29.     SPI_Config(SPI1, &SPI1_InitStructure);
  30.     SPI_DisableCRC(SPI1);
  31.     SPI_DisableSSOutput(SPI1);
  32.     SPI_Enable(SPI1);
  33. }
  34. void lcd_spiwritebyte(SPI_T *spix,uint8_t byte)
  35. {
  36.     while (SPI_I2S_ReadStatusFlag(spix, SPI_FLAG_TXBE) == RESET);
  37.     SPI_I2S_TxData(spix, byte);
  38. }
LCD驱动代码
  1. void YUYY_HS12864G18B_writebyte(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t dat)
  2. {
  3.     uint8_t i = 0;
  4.     if(hs12864_dev->spix)
  5.         hs12864_dev->spi_sendbyte_func(hs12864_dev->spix, dat);
  6.     else
  7.     {
  8.         while(i<8)
  9.         {
  10.             hs12864_dev->sck_setlev_func(&(hs12864_dev->sck),YUYY_GPIO_LEV0);
  11.             if(dat & 0x80)
  12.                 hs12864_dev->mo_setlev_func(&(hs12864_dev->mo),YUYY_GPIO_LEV1);
  13.             else
  14.                 hs12864_dev->mo_setlev_func(&(hs12864_dev->mo),YUYY_GPIO_LEV0);
  15.             hs12864_dev->sck_setlev_func(&(hs12864_dev->sck),YUYY_GPIO_LEV1);
  16.             dat <<= 1;
  17.             i += 1;
  18.         }
  19.     }
  20. }

  21. void YUYY_HS12864G18B_cs(YUYY_HS12864G18B_DEV_Type *hs12864_dev,YUYY_GPIO_LEV_TYPE lev)
  22. {
  23.     hs12864_dev->delayus_func(5);
  24.     hs12864_dev->cs_setlev_func(&(hs12864_dev->cs),lev);
  25.     hs12864_dev->delayus_func(5);
  26. }
  27. void YUYY_HS12864G18B_rst(YUYY_HS12864G18B_DEV_Type *hs12864_dev,YUYY_GPIO_LEV_TYPE lev)
  28. {
  29.     hs12864_dev->rst_setlev_func(&(hs12864_dev->rst),lev);
  30. }
  31. void YUYY_HS12864G18B_a0(YUYY_HS12864G18B_DEV_Type *hs12864_dev,YUYY_GPIO_LEV_TYPE lev)
  32. {
  33.     hs12864_dev->a0_setlev_func(&(hs12864_dev->a0),lev);
  34. }


  35. /*
  36. * com 0指令 1数据
  37. */
  38. void YUYY_HS12864G18B_writedata(YUYY_HS12864G18B_DEV_Type *hs12864_dev,YUYY_GPIO_LEV_TYPE com,uint8_t dat)
  39. {
  40.     YUYY_HS12864G18B_cs(hs12864_dev,YUYY_GPIO_LEV0);
  41.     YUYY_HS12864G18B_a0(hs12864_dev,com);
  42.     YUYY_HS12864G18B_writebyte(hs12864_dev,dat);
  43. }

  44. void YUYY_HS12864G18B_Init(YUYY_HS12864G18B_DEV_Type *hs12864_dev)
  45. {
  46.     if(!hs12864_dev->a0_setlev_func)
  47.         hs12864_dev->a0_setlev_func = YUYY_GPIO_SetLev;
  48.     if(!hs12864_dev->cs_setlev_func)
  49.         hs12864_dev->cs_setlev_func = YUYY_GPIO_SetLev;
  50.     if(!hs12864_dev->mo_setlev_func)
  51.         hs12864_dev->mo_setlev_func = YUYY_GPIO_SetLev;
  52.     if(!hs12864_dev->rst_setlev_func)
  53.         hs12864_dev->rst_setlev_func = YUYY_GPIO_SetLev;
  54.     if(!hs12864_dev->sck_setlev_func)
  55.         hs12864_dev->sck_setlev_func = YUYY_GPIO_SetLev;
  56.     if(!hs12864_dev->delayus_func)
  57.         hs12864_dev->delayus_func = (YUYY_DELAY_Func_Type)YUYY_DelayUs;
  58.         
  59.     YUYY_HS12864G18B_cs(hs12864_dev,YUYY_GPIO_LEV0);
  60.     YUYY_HS12864G18B_rst(hs12864_dev,YUYY_GPIO_LEV0);/*低电平复位*/
  61.     hs12864_dev->delayus_func(20);
  62.     YUYY_HS12864G18B_rst(hs12864_dev,YUYY_GPIO_LEV1);/*复位完毕*/
  63.     YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0xE2);/*软复位*/
  64.     hs12864_dev->delayus_func(50);
  65.     YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0x2C); /*升压步聚 1*/
  66.     hs12864_dev->delayus_func(50);
  67.     YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0x2E); /*升压步聚 2*/
  68.     hs12864_dev->delayus_func(50);
  69.     YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0x2F); /*升压步聚 3*/
  70.     hs12864_dev->delayus_func(50);
  71.     YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0x24); /*0x24粗调对比度,可设置范围0x20~0x27*/
  72.     YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0x81); /*微调对比度*/
  73.     YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0x08); /*0x28,微调对比度的值,可设置范围0x00~0x3f  1f*/
  74.     YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0xA2); /*1/9偏压比(bias)*/
  75.     YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0xC8); /*行扫描顺序:从上到下*/
  76.     YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0xA0); /*列扫描顺序:从左到右*/
  77.     YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0x40); /*起始行:第一行开始*/
  78.     YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0xAF); /*开显示*/
  79.     YUYY_HS12864G18B_cs(hs12864_dev,YUYY_GPIO_LEV1);
  80. }

  81. void YUYY_HS12864G18B_address(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t page,uint8_t column)
  82. {
  83.     YUYY_HS12864G18B_cs(hs12864_dev,YUYY_GPIO_LEV0);
  84.     YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0xB0+page); //设置页地址。每页是 8行。一个画面的 64行被分成 8个页*/
  85.     YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,((column>>4)&0x0F)+0x10); //设置列地址的高4位
  86.     YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,column&0x0F); //设置列地址的低4位
  87. }

  88. /*全屏清屏*/
  89. void YUYY_HS12864G18B_ClearScreen(YUYY_HS12864G18B_DEV_Type *hs12864_dev)
  90. {
  91.     uint8_t i,j;
  92.     for(i=0;i<8;i+=1)
  93.     {
  94.         YUYY_HS12864G18B_address(hs12864_dev,i,0);
  95.         for(j=0;j<132;j+=1)
  96.         {
  97.             YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV1,0x00);
  98.         }
  99.     }
  100. }

  101. //===显示测试画面:例如全显示,隔行显示,隔列显示,雪花显示=====
  102. void YUYY_HS12864G18B_TestDisplay(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t data1,uint8_t data2)
  103. {
  104.     uint8_t i,j;
  105.     for(j=0;j<8;j+=1)
  106.     {
  107.         YUYY_HS12864G18B_address(hs12864_dev,j,0);
  108.         for(i=0;i<64;i+=1)
  109.         {
  110.             YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV1,data1);
  111.             YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV1,data2);
  112.         }
  113.     }
  114. }


  115. void YUYY_HS12864G18B_DisplayDatas(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t option,uint8_t page,uint8_t column,uint8_t *dp,uint8_t width,uint8_t height)
  116. {
  117.     uint8_t rev,i=0,j=0,k=0,hp=height/8;
  118.     rev = option&YUYY_FONT_DATAS_REVERSE;
  119.     if((option&YUYY_FONT_DATAS_COL_COL) == 0)
  120.     {
  121.         while (i<hp)
  122.         {
  123.             YUYY_HS12864G18B_address(hs12864_dev,page+i,column);
  124.             j=0;
  125.             while (j<width)
  126.             {
  127.                 if(rev == 0)
  128.                     YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV1,*dp);
  129.                 else
  130.                     YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV1,~*dp);
  131.                 dp+=1;
  132.                 j+=1;
  133.             }
  134.             
  135.             i+=1;
  136.         }
  137.     }
  138.     else
  139.     {
  140.         while (i<hp)
  141.         {
  142.             YUYY_HS12864G18B_address(hs12864_dev,page+i,column);
  143.             k=i;
  144.             j=0;
  145.             while (j<width)
  146.             {
  147.                 if(rev == 0)
  148.                     YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV1,dp[k]);
  149.                 else
  150.                     YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV1,~dp[k]);
  151.                 j+=1;
  152.                 k+=hp;
  153.             }
  154.             i+=1;
  155.         }
  156.     }
  157. }

  158. /*显示 128x64点阵图像*/
  159. void YUYY_HS12864G18B_GisplayGraphic128x64(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t option,uint8_t page,uint8_t column,uint8_t *dp)
  160. {
  161.     YUYY_HS12864G18B_DisplayDatas(hs12864_dev,option,page,column,dp,128,64);
  162. }

  163. /*显示 32x32点阵图像、汉字、生僻字或 32x32点阵的其他图标*/  
  164. void YUYY_HS12864G18B_GisplayGraphic32x32(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t option,uint8_t page,uint8_t column,uint8_t *dp)
  165. {
  166.     YUYY_HS12864G18B_DisplayDatas(hs12864_dev,option,page,column,dp,32,32);
  167. }
  168. /*显示 16x16点阵图像、汉字、生僻字或 16x16点阵的其他图标*/
  169. void YUYY_HS12864G18B_GisplayGraphic16x16(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t option,uint8_t page,uint8_t column,uint8_t *dp)
  170. {
  171.     YUYY_HS12864G18B_DisplayDatas(hs12864_dev,option,page,column,dp,16,16);
  172. }
  173. /*显示8x16点阵图像、ASCII, 或8x16点阵的自造字符、其他图标*/
  174. void YUYY_HS12864G18B_GisplayGraphic8x16(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t option,uint8_t page,uint8_t column,uint8_t *dp)
  175. {
  176.     YUYY_HS12864G18B_DisplayDatas(hs12864_dev,option,page,column,dp,8,16);
  177. }
  178. /*显示8x16ASCII字符串*/
  179. void YUYY_HS12864G18B_DisplayString8x16(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t option,uint8_t page,uint8_t column,char *text)
  180. {
  181.     uint8_t i=0,j;
  182.     option &= 0x01;
  183.     while(text[i]>0x00)
  184.     {
  185.         if((text[i] > 0x1F)&&(text[i] < 0x7F))
  186.         {
  187.             j=text[i]-0x20;
  188.             YUYY_HS12864G18B_DisplayDatas(hs12864_dev,option,page,column,(uint8_t *)(YUYY_FONT_ASCII_TABLE_8x16+j),8,16);
  189.             column+=8;
  190.         }
  191.         i+=1;
  192.     }
  193. }
  194. /*显示6x8ASCII字符串*/
  195. void YUYY_HS12864G18B_DisplayString6x8(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t option,uint8_t page,uint8_t column,char *text)
  196. {
  197.     uint8_t i=0,j;
  198.     option &= 0x01;
  199.     while(text[i]>0x00)
  200.     {
  201.         if((text[i]>0x1F)&&(text[i]<0x7F))
  202.         {
  203.             j=text[i]-0x20;
  204.             YUYY_HS12864G18B_DisplayDatas(hs12864_dev,option,page,column,(uint8_t *)(YUYY_FONT_ASCII_TABLE_6x8+j),6,8);
  205.             column+=6;
  206.         }
  207.         i+=1;
  208.     }
  209. }


  210. void YUYY_HS12864G18B_DisplayFinish(YUYY_HS12864G18B_DEV_Type *hs12864_dev)
  211. {
  212.     YUYY_HS12864G18B_cs(hs12864_dev,YUYY_GPIO_LEV1);
  213. }
LCD初始化
  1. YUYY_HS12864G18B_DEV_Type lcd_dev;
  2. void lcd_init()
  3. {
  4.     GPIO_Config_T gpioConfigStruct;
  5.     RCM_EnableAHB1PeriphClock (RCM_AHB1_PERIPH_GPIOA);
  6.     GPIO_ConfigStructInit(&gpioConfigStruct);
  7.     gpioConfigStruct.mode = GPIO_MODE_OUT;
  8.     gpioConfigStruct.speed = GPIO_SPEED_100MHz;
  9.     gpioConfigStruct.pin = GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_8;
  10.     gpioConfigStruct.otype = GPIO_OTYPE_PP;
  11.     gpioConfigStruct.pupd = GPIO_PUPD_NOPULL;
  12.     GPIO_Config(GPIOA, &gpioConfigStruct);
  13.    
  14.     lcd_dev.cs.gpio = GPIOA;
  15.     lcd_dev.cs.pin = GPIO_PIN_4;
  16.     lcd_dev.rst.gpio = GPIOA;
  17.     lcd_dev.rst.pin = GPIO_PIN_6;
  18.     lcd_dev.a0.gpio = GPIOA;
  19.     lcd_dev.a0.pin = GPIO_PIN_8;
  20.     lcd_dev.spix = SPI1;
  21.     lcd_dev.spi_sendbyte_func = (YUYY_HS12864G18B_SpiWriteByteFunc_Type)lcd_spiwritebyte;
  22.    
  23.     YUYY_HS12864G18B_Init(&lcd_dev);
  24.     YUYY_HS12864G18B_ClearScreen(&lcd_dev);
  25.     YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,0,0," APM32F411 TEST");
  26.     YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,2,0,"  LCD use SPI");
  27.     YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,4,0,"  bbs.21ic.com");
  28.     YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,6,0,"Code by yuyy1989");
  29.     YUYY_HS12864G18B_DisplayFinish(&lcd_dev);
  30. }
运行效果
微信截图_20240512175336.png
接下来用RTC实现时间显示功能,初始化RTC,使用外部低速晶振作为时钟源

  1. void rtc_init()
  2. {
  3.     RTC_Config_T Struct;
  4.     RTC_TimeConfig_T timeConfig;
  5.     RTC_DateConfig_T dateConfig;

  6.     RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_PMU);
  7.     PMU_EnableBackupAccess();
  8.     RCM_ConfigLSE(RCM_LSE_OPEN);
  9.     while(RCM_ReadStatusFlag(RCM_FLAG_LSERDY) == RESET)
  10.     {
  11.     }

  12.     RCM_ConfigRTCCLK(RCM_RTCCLK_LSE);

  13.     RCM_EnableRTCCLK();
  14.     RTC_WaitForSynchro();
  15.     RTC_ConfigStructInit(&Struct);
  16.     Struct.format = RTC_HOURFORMAT_24;
  17.     RTC_Config(&Struct);
  18.    
  19.     RTC_DisableWriteProtection();
  20.     timeConfig.hours = 8;
  21.     timeConfig.minutes = 20;
  22.     timeConfig.seconds = 30;
  23.     RTC_ConfigTime(RTC_FORMAT_BIN,&timeConfig);
  24.     dateConfig.year = 24;
  25.     dateConfig.month = RTC_MONTH_MAY;
  26.     dateConfig.date = 12;
  27.     dateConfig.weekday = RTC_WEEKDAY_SUNDAY;
  28.     RTC_ConfigDate(RTC_FORMAT_BIN,&dateConfig);
  29.     RTC_EnableWriteProtection();
  30. }
实现LCD显示RTC时间
  1. char *WeekdayStr[7]= {"SUN","MON","TUE","WED","THU","FRI","SAT"};
  2. uint8_t ertc_int_flag = 0;
  3. void showrtc()
  4. {
  5.     RTC_TimeConfig_T time;
  6.     RTC_DateConfig_T date;
  7.     char out[20];
  8.     RTC_ReadDate(RTC_FORMAT_BIN,&date);
  9.     sprintf(out," 20%02d-%02d-%02d %s ",date.year, date.month, date.date,WeekdayStr[date.weekday%7]);
  10.     YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,0,0,out);
  11.     RTC_ReadTime(RTC_FORMAT_BIN,&time);
  12.     sprintf(out,"    %02d:%02d:%02d    ",time.hours, time.minutes, time.seconds);
  13.     YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,2,0,out);
  14. }
运行效果
WeChat_20240512175624 00_00_00-00_00_30.gif


szt1993 发表于 2024-5-23 18:06 | 显示全部楼层
SPI显示屏驱动速率应该比较稳定
逢dududu必shu 发表于 2024-8-17 01:12 | 显示全部楼层
在极海MCU APM32F103上使用SPI驱动LCD并显示RTC时间的过程涉及硬件初始化、SPI通信、RTC设置和时间获取、以及LCD显示更新。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

161

主题

815

帖子

10

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