[方案相关] HC32F4A0开发板的LCD屏显示驱动

[复制链接]
 楼主| jinglixixi 发表于 2023-3-6 22:43 | 显示全部楼层 |阅读模式
本帖最后由 jinglixixi 于 2023-3-6 22:48 编辑

#申请原创#
HC32F4A0开发板上,为了满足显示的需要配备有一个LCD屏接口,见图1所示。
由图中的注释可知,它是用来支持一款分辨率为800*480像素点的4.3寸屏,其驱动方式应该是以并行的方式,共有34个引脚。
无奈的是手中并没有与之相匹配的显示屏,只有一款34引脚的SPI接口LCD屏,其引脚排列如图2所示。
虽然在尺寸上略有不足,但终归是彩屏可以用来显示图像呀。
1.jpg
1  LCD接口

2.jpg
2  MDM_2802显示模组引脚排列


在利用LCD接口的情况下,经编程处理其使用效果如图3所示。

3.jpg
3 使用效果
那它的驱动是怎样实现的呢?
其实本来应该很简单,那就是以GPIO口来模拟SPI的工作方式来驱动它。

但在具体实施时却发现一个问题,那就是该LCD接口所连接的引脚并非全是GPIO口,而是部分引脚经芯片扩展而获得,如引脚LCD_RST就属于这种类型,见图4所示。
4.jpg

4  I2C扩展I/O
也就是说,本来以模拟方式就可解决的问题现在又增添了I2C扩展I/O口的问题。
在查清引脚连接关系的情况下,MDM_2802显示模组与开发板的连接关系为:
CS  ----PG12
RS  ----PG2
SCLK----PC0
RD  ----PF11
RST ----TCA9539(LCD_RST)
BKL ---- PI0
VDD --- 3.3V
GND--- GND
SDO ----PE3
SDI ----PF10/PE5(以J17进行切换)

为实现高低电平的模拟输出所作的定义为:
#defineCLR_CLK()    GPIO_ResetPins(GPIO_PORT_C, GPIO_PIN_00)
#defineSET_CLK()   GPIO_SetPins(GPIO_PORT_C,GPIO_PIN_00)   //CLK

#defineCLR_SDA()    GPIO_ResetPins(GPIO_PORT_E,GPIO_PIN_05)
#defineSET_SDA()   GPIO_SetPins(GPIO_PORT_E,GPIO_PIN_05)   //DIN

#defineSET_REST()   GPIO_SetPins(GPIO_PORT_E,GPIO_PIN_13)
#defineCLR_REST()   GPIO_ResetPins(GPIO_PORT_E,GPIO_PIN_13)  //RES

#defineCLR_CS()     GPIO_ResetPins(GPIO_PORT_G,GPIO_PIN_12)
#defineSET_CS()    GPIO_SetPins(GPIO_PORT_G,GPIO_PIN_12)    //CS


对所用引脚的初始化配置函数为:
  1. void LCD_Init(void)
  2. {
  3.     stc_gpio_init_t stcGpioInit;
  4.     (void)GPIO_StructInit(&stcGpioInit);
  5.     stcGpioInit.u16PinState = PIN_STAT_RST;
  6.     stcGpioInit.u16PinDir = PIN_DIR_OUT;
  7.         (void)GPIO_Init(GPIO_PORT_E, GPIO_PIN_13, &stcGpioInit);
  8.     (void)GPIO_Init(GPIO_PORT_F, GPIO_PIN_11, &stcGpioInit);
  9.         (void)GPIO_Init(GPIO_PORT_G, GPIO_PIN_12, &stcGpioInit);
  10.     (void)GPIO_Init(GPIO_PORT_G, GPIO_PIN_02, &stcGpioInit);
  11.         (void)GPIO_Init(GPIO_PORT_E, GPIO_PIN_05, &stcGpioInit);
  12.         (void)GPIO_Init(GPIO_PORT_C, GPIO_PIN_00, &stcGpioInit);
  13. }

I/O口模拟SPI方式字节数据的函数为:
  1. void send_byte(uint8_t data)
  2. {
  3.     uint8_t count;
  4.     for(count = 0; count < 8; count++)
  5.     {
  6.         CLR_CLK();
  7.         if(data & 0x80)
  8.         {
  9.             SET_SDA();
  10.         }
  11.         else
  12.         {
  13.             CLR_SDA();
  14.         }
  15.         data <<= 1;
  16.             SET_CLK();
  17.     }
  18. }

配置的写寄存器和数据的函数如下:
  1. void write_register(uint8_t cmd)         
  2. {
  3.         CLR_CS();
  4.         CLR_CLK();
  5.         CLR_SDA();
  6.         SET_CLK();
  7.         send_byte(cmd);
  8.         SET_CS();
  9. }

  10. void write_data(uint8_t data)
  11. {
  12.      CLR_CS();
  13.          CLR_CLK();
  14.          SET_SDA();
  15.          SET_CLK();
  16.          send_byte(data);
  17.          SET_CS();
  18. }

显示屏的初始化函数为:
  1. void ili9341_init(void)
  2. {
  3.         write_register(0xCF);
  4.     write_data(0x00);
  5.     write_data(0xC1);
  6.     write_data(0X30);
  7.     write_register(0xED);
  8.     write_data(0x64);
  9.     write_data(0x03);
  10.     write_data(0X12);
  11.     write_data(0X81);
  12.     write_register(0xE8);
  13.     write_data(0x85);
  14.     write_data(0x10);
  15.     write_data(0x7A);
  16.     write_register(0xCB);
  17.     write_data(0x39);
  18.     write_data(0x2C);
  19.     write_data(0x00);
  20.     write_data(0x34);
  21.     write_data(0x02);
  22.     write_register(0xF7);
  23.     write_data(0x20);
  24.     write_register(0xEA);
  25.     write_data(0x00);
  26.     write_data(0x00);
  27.     write_register(0xC0);
  28.     write_data(0x1B);
  29.     write_register(0xC1);
  30.     write_data(0x01);
  31.     write_register(0xC5);
  32.     write_data(0x30);
  33.     write_data(0x30);
  34.     write_register(0xC7);
  35.     write_data(0XB7);
  36.     write_register(0x36);
  37.     write_data(0x08);
  38.     write_register(0x3A);
  39.     write_data(0x55);
  40.     write_register(0xB1);
  41.     write_data(0x00);
  42.     write_data(0x1A);
  43.     write_register(0xB6);
  44.     write_data(0x0A);
  45.     write_data(0xA2);
  46.     write_register(0xF2);
  47.     write_data(0x00);
  48.     write_register(0x26);
  49.     write_data(0x01);
  50.     write_register(0xE0);
  51.     write_data(0x0F);
  52.     write_data(0x2A);
  53.     write_data(0x28);
  54.     write_data(0x08);
  55.     write_data(0x0E);
  56.     write_data(0x08);
  57.     write_data(0x54);
  58.     write_data(0XA9);
  59.     write_data(0x43);
  60.     write_data(0x0A);
  61.     write_data(0x0F);
  62.     write_data(0x00);
  63.     write_data(0x00);
  64.     write_data(0x00);
  65.     write_data(0x00);
  66.     write_register(0XE1);
  67.     write_data(0x00);
  68.     write_data(0x15);
  69.     write_data(0x17);
  70.     write_data(0x07);
  71.     write_data(0x11);
  72.     write_data(0x06);
  73.     write_data(0x2B);
  74.     write_data(0x56);
  75.     write_data(0x3C);
  76.     write_data(0x05);
  77.     write_data(0x10);
  78.     write_data(0x0F);
  79.     write_data(0x3F);
  80.     write_data(0x3F);
  81.     write_data(0x0F);
  82.     write_register(0x2B);
  83.     write_data(0x00);
  84.     write_data(0x00);
  85.     write_data(0x01);
  86.     write_data(0x3f);
  87.     write_register(0x2A);
  88.     write_data(0x00);
  89.     write_data(0x00);
  90.     write_data(0x00);
  91.     write_data(0xef);         
  92.     write_register(0x11);
  93.     DDL_DelayMS(10);
  94.     write_register(0x29);
  95. }

实现色彩清屏处理的函数为:
  1. void ili9341_clear(int c)
  2. {
  3.           uint32_t index=0;
  4.           set_cursor(0x00, 0x0000);
  5.           gram_prepare();
  6.           for(index = 0; index < (320*240); index++)
  7.           {
  8.                     write_data(c >> 8);
  9.                     write_data(c);
  10.           }
  11. }

仿照清屏函数,实现一个50*50像素点的图标显示函数为:
  1. void showimage(void)
  2. {
  3.     int i,j;
  4.     set_cursor(10,10);
  5.         gram_prepare();
  6.     for(j=0;j<50;j++)
  7.     {
  8.           set_cursor(10,10+j);
  9.           gram_prepare();
  10.               for(i=0;i<50;i++)
  11.           {
  12.               write_data(gImage_tb[(j*50+i)*2]);
  13.               write_data(gImage_tb[(j*50+i)*2+1]);
  14.           }
  15.     }
  16. }

其中,语句set_cursor(10,10)是将绘制图标的位置设置为x=10,y=10的坐标处;函数write_data()的作用则是输出色彩的数据。
实现字符显示的函数为:
  1. void _GUI_DispChar(char c, int x, int y, const char *pdata, int font_xsize, int font_ysize, int fcolor, int bcolor)
  2. {
  3.     uint8_t j,pos,t;
  4.     uint8_t temp;
  5.     uint8_t XNum;
  6.     uint32_t base;
  7.     XNum = (font_xsize/8) + 1;
  8.     if(font_ysize%8 == 0)
  9.     {
  10.         XNum--;
  11.     }
  12.     if(c < ' ')
  13.     {
  14.         return;
  15.     }
  16.     c = c - ' ';
  17.     base = (c*XNum*font_ysize);
  18.     for(j = 0; j < XNum; j++)
  19.     {
  20.         for(pos = 0; pos < font_ysize; pos++)
  21.         {
  22.             temp = (uint8_t)pdata[base + pos + j*font_ysize];
  23.             if(j < XNum)
  24.             {
  25.                 for(t = 0; t < 8; t++)
  26.                 {
  27.                     if((temp>>t)&0x01)
  28.                     {
  29.                         ili9341_draw_pixel(fcolor, x+t, y+pos);
  30.                     }
  31.                     else
  32.                     {
  33.                         ili9341_draw_pixel(bcolor, x+t, y+pos);
  34.                     }
  35.                 }
  36.             }
  37.             else
  38.             {
  39.                 for(t = 0; t < font_xsize%8; t++)
  40.                 {
  41.                     if((temp >> t) & 0x01)
  42.                     {
  43.                         ili9341_draw_pixel(fcolor, x+t, y+pos);
  44.                     }
  45.                     else
  46.                     {
  47.                         ili9341_draw_pixel(bcolor, x+t, y+pos);
  48.                     }
  49.                 }
  50.             }
  51.         }
  52.         x += 8;
  53.     }
  54. }

实现汉字显示的函数为:
  1. void showhanzi16(unsigned int x,unsigned int y,unsigned char index, int fcolor, int bcolor)
  2. {
  3.         unsigned char i,j,k;
  4.         unsigned char *temp=hanzi16;
  5.         temp+=index*32;
  6.         for(j=0;j<16;j++)
  7.         {
  8.                 for(k=0;k<2;k++)
  9.                 {
  10.                         for(i=0;i<8;i++)
  11.                         {
  12.                                  if((*temp&(1<<i))!=0)
  13.                                 {
  14.                                         ili9341_draw_pixel(fcolor, x+i+k*8, y+j);
  15.                                 }
  16.                                 else
  17.                                 {
  18.                                         ili9341_draw_pixel(bcolor, x+i+k*8, y+j);
  19.                                 }
  20.                         }
  21.                         temp++;
  22.                 }
  23.          }
  24. }

汉字显示函数所用的字模可由软件PCtoLCD2002来提取,其数据提取格式如图6所示。
5.jpg
5  工具软件

6.jpg
6 提取格式
字库在数组中的存放形式如下:
  1. unsigned char hanzi16[]=
  2. {
  3. 0x80,0x20,0x82,0x20,0xF4,0x17,0x84,0x08,0x80,0x00,0xE1,0x23,0x02,0x20,0xEA,0x13,
  4. 0x28,0x0A,0x24,0x42,0xE7,0x43,0x24,0x22,0x44,0x21,0x04,0x17,0xF4,0x08,0x20,0x04,
  5. ...  ...
  6. 0x80,0x00,0x84,0x78,0x88,0x48,0xE8,0x4B,0x81,0x48,0x82,0x78,0x82,0x48,0xE8,0x4B,
  7. 0x28,0x4A,0x24,0x7A,0x27,0x4A,0xE4,0x4B,0x24,0x4A,0x04,0x44,0x04,0x54,0x00,0x22,
  8. }

实现3所示效果的主程序为:
  1. int32_t main(void)
  2. {
  3.         LL_PERIPH_WE(EXAMPLE_PERIPH_WE);
  4.         BSP_CLK_Init();
  5.         BSP_IO_Init();
  6.         BSP_LED_Init();
  7.             BSP_LCD_IO_Init();
  8.         LL_PERIPH_WP(EXAMPLE_PERIPH_WP);
  9.             GPIO_ResetPins(GPIO_PORT_G, GPIO_PIN_02);
  10.             GPIO_ResetPins(GPIO_PORT_F, GPIO_PIN_11);
  11.             BSP_LCD_BKLCmd(EIO_PIN_SET);
  12.             BSP_LCD_RSTCmd(EIO_PIN_SET);
  13.             LCD_Init();
  14.                 ili9341_init();
  15.               ili9341_clear(RED);
  16.                 BACK_COLOR=RED;
  17.             POINT_COLOR=YELLOW;
  18.                 LCD_ShowString(70,17,"MDM-2802 & HC32F4A0");
  19.                 LCD_ShowString(70,37,"MP3");
  20.                 showhanzi16(100,37,32, YELLOW, RED);
  21.                 showhanzi16(120,37,33, YELLOW, RED);
  22.                 showhanzi16(140,37,34, YELLOW, RED);
  23.                 showhanzi16(160,37,35, YELLOW, RED);
  24.                 showhanzi16(180,37,36, YELLOW, RED);
  25.                 LCD_ShowString(60,300,"BY: jinglixixi");
  26.                 LCD_DrawLine(WHITE ,0, 10, 239, 10);
  27.                 LCD_DrawLine(WHITE ,0, 60, 239, 60);
  28.             LCD_DrawLine(WHITE,0, 296, 239, 296);
  29.                 showimage();
  30.                 showhanzi16(30,80,37, YELLOW, RED);
  31.                 showhanzi16(60,80,0, YELLOW, RED);
  32.                 showhanzi16(80,80,1, YELLOW, RED);
  33.                 showhanzi16(100,80,2, YELLOW, RED);
  34.                 showhanzi16(60,110,3, YELLOW, RED);
  35.                 showhanzi16(80,110,4, YELLOW, RED);
  36.                 showhanzi16(100,110,5, YELLOW, RED);
  37.                 showhanzi16(120,110,6, YELLOW, RED);
  38.                 showhanzi16(60,140,7, YELLOW, RED);
  39.                 showhanzi16(80,140,8, YELLOW, RED);
  40.                 showhanzi16(60,170,9, YELLOW, RED);
  41.                 showhanzi16(80,170,10, YELLOW, RED);
  42.                 showhanzi16(60,200,11, YELLOW, RED);
  43.                 showhanzi16(80,200,12, YELLOW, RED);
  44.                 showhanzi16(100,200,13, YELLOW, RED);
  45.                 showhanzi16(120,200,14, YELLOW, RED);
  46.                 showhanzi16(60,230,15, YELLOW, RED);
  47.                 showhanzi16(80,230,16, YELLOW, RED);
  48.                 showhanzi16(100,230,17, YELLOW, RED);
  49.                 showhanzi16(120,230,18, YELLOW, RED);
  50.                 showhanzi16(140,230,19, YELLOW, RED);
  51.                 showhanzi16(60,260,20, YELLOW, RED);
  52.                 showhanzi16(80,260,21, YELLOW, RED);
  53.                 showhanzi16(100,260,22, YELLOW, RED);
  54.                 showhanzi16(120,260,23, YELLOW, RED);
  55.                 showhanzi16(140,260,24, YELLOW, RED);
  56.                 showhanzi16(160,260,25, YELLOW, RED);
  57.                 showhanzi16(180,260,26, YELLOW, RED);
  58.                 for (;;) {
  59.               BSP_LED_Toggle(LED_BLUE);
  60.                           BSP_LED_Toggle(LED_YELLOW);
  61.                           BSP_LED_Toggle(LED_RED);
  62.                           DDL_DelayMS(500);
  63.           }
  64. }

其中:语句GPIO_ResetPins(GPIO_PORT_G, GPIO_PIN_02)GPIO_ResetPins(GPIO_PORT_F,GPIO_PIN_11)的作用是向引脚RSRD提供低电平,而引脚BSP_LCD_BKLCmd(EIO_PIN_SET)BSP_LCD_RSTCmd(EIO_PIN_SET)的作用则是向引脚
BKLRST提供高电平。

至于扩展I/O的使用,是建立在函数BSP_LCD_IO_Init()的基础上,通过它实现了扩展I/O口的初始化,随后就可仿照GPIO的使用来控制高低电平的输出。

函数BSP_LCD_IO_Init()的内容如下:
  1. void BSP_LCD_IO_Init(void)
  2. {
  3.     /* Init LCD backlight IO */
  4.     GPIO_OutputCmd(LCD_BKL_PORT, LCD_BKL_PIN, ENABLE);
  5.     /* Init LCD control IO before direction setting */
  6.     BSP_IO_WritePortPin(LCD_RST_PORT, LCD_RST_PIN, EIO_PIN_SET);
  7.     /* LCD panel control IO set to output */
  8.     BSP_IO_ConfigPortPin(LCD_RST_PORT, LCD_RST_PIN, EIO_DIR_OUT);
  9.     /* Init touch panel control IO before direction setting */
  10.     BSP_IO_WritePortPin(LCD_CTRST_PORT, LCD_CTRST_PIN, EIO_PIN_RESET);
  11.     BSP_IO_WritePortPin(LCD_CTINT_PORT, LCD_CTINT_PIN, EIO_PIN_RESET);
  12.     BSP_IO_ConfigPortPin(LCD_CTRST_PORT, LCD_CTRST_PIN, EIO_DIR_OUT);
  13.     BSP_IO_ConfigPortPin(LCD_CTINT_PORT, LCD_CTINT_PIN, EIO_DIR_OUT);
  14.     DDL_DelayMS(100UL);
  15.     BSP_IO_WritePortPin(LCD_CTINT_PORT, LCD_CTINT_PIN, EIO_PIN_SET);
  16.     DDL_DelayMS(100UL);
  17.     BSP_IO_WritePortPin(LCD_CTRST_PORT, LCD_CTRST_PIN, EIO_PIN_SET);
  18.     DDL_DelayMS(10UL);
  19.     BSP_IO_WritePortPin(LCD_CTINT_PORT, LCD_CTINT_PIN, EIO_PIN_RESET);
  20.     DDL_DelayMS(100UL);
  21.     BSP_IO_ConfigPortPin(LCD_CTRST_PORT, LCD_CTRST_PIN, EIO_DIR_IN);
  22.     BSP_IO_ConfigPortPin(LCD_CTINT_PORT, LCD_CTINT_PIN, EIO_DIR_IN);
  23. }

以语句BSP_LCD_RSTCmd(EIO_PIN_SET)为例,其执行的I/O控制的操作为BSP_IO_WritePortPin(LCD_RST_PORT,LCD_RST_PIN, EIO_PIN_SET);。
这要我们就以I/O口模拟SPI的方式实现了MDM_2802显示模组的驱动,并用到了芯片TCA9539所扩展的I/O口。
这种使用方式,对于那些只惯于以一种方式来解决问题的人来说将是难于完成驱动目标的。


朝生 发表于 2023-3-9 13:58 | 显示全部楼层
34引脚的SPI接口?
 楼主| jinglixixi 发表于 2023-3-10 00:06 | 显示全部楼层
本帖最后由 jinglixixi 于 2023-3-11 15:29 编辑
朝生 发表于 2023-3-9 13:58
34引脚的SPI接口?

是它有34个引脚,但只是以SPI方式工作,其它引脚没有用。
chenjun89 发表于 2023-3-21 08:06 来自手机 | 显示全部楼层
这是浪费引脚数啊
 楼主| jinglixixi 发表于 2023-3-21 16:37 | 显示全部楼层
chenjun89 发表于 2023-3-21 08:06
这是浪费引脚数啊

哈哈,是省引脚资源!
hilahope 发表于 2023-4-9 13:58 | 显示全部楼层
感觉串行的代码运行好复杂。              
mollylawrence 发表于 2023-4-9 14:24 | 显示全部楼层
HC32F4A0带有fsmc的接口吗
10299823 发表于 2023-4-9 14:29 | 显示全部楼层
这个评估板是官网提供的吗              
robincotton 发表于 2023-4-9 14:55 | 显示全部楼层
屏幕不错,分辨率挺高的。              
loutin 发表于 2023-4-9 15:28 | 显示全部楼层
驱动的移植的哪里的              
biechedan 发表于 2023-4-9 15:36 | 显示全部楼层
这个最大的刷   屏频率是多少              
pl202 发表于 2023-4-9 15:59 | 显示全部楼层
彩色屏幕的驱动效果不错。              
mnynt121 发表于 2023-4-9 16:13 | 显示全部楼层
可以使用dma驱动这个lcd?              
ingramward 发表于 2023-4-9 16:17 | 显示全部楼层
可以在开发板上LCD屏显示正弦波、方波、阶梯波信号吗
 楼主| jinglixixi 发表于 2023-4-10 08:11 | 显示全部楼层
ingramward 发表于 2023-4-9 16:17
可以在开发板上LCD屏显示正弦波、方波、阶梯波信号吗

可以
 楼主| jinglixixi 发表于 2023-4-10 08:12 | 显示全部楼层
mnynt121 发表于 2023-4-9 16:13
可以使用dma驱动这个lcd?

没试过
 楼主| jinglixixi 发表于 2023-4-10 08:13 | 显示全部楼层
loutin 发表于 2023-4-9 15:28
驱动的移植的哪里的

原飞思卡尔开发板的
 楼主| jinglixixi 发表于 2023-4-10 08:14 | 显示全部楼层
10299823 发表于 2023-4-9 14:29
这个评估板是官网提供的吗

是开发板测评提供的
喂什么玩意 发表于 2024-7-31 11:31 | 显示全部楼层
以GPIO口来模拟SPI的工作方式来驱动它。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

518

主题

2934

帖子

39

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

518

主题

2934

帖子

39

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