打印
[方案相关]

HC32F4A0开发板的LCD屏显示驱动

[复制链接]
1180|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 jinglixixi 于 2023-3-6 22:48 编辑

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

2  MDM_2802显示模组引脚排列


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

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

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

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


对所用引脚的初始化配置函数为:
void LCD_Init(void)
{
    stc_gpio_init_t stcGpioInit;
    (void)GPIO_StructInit(&stcGpioInit);
    stcGpioInit.u16PinState = PIN_STAT_RST;
    stcGpioInit.u16PinDir = PIN_DIR_OUT;
        (void)GPIO_Init(GPIO_PORT_E, GPIO_PIN_13, &stcGpioInit);
    (void)GPIO_Init(GPIO_PORT_F, GPIO_PIN_11, &stcGpioInit);
        (void)GPIO_Init(GPIO_PORT_G, GPIO_PIN_12, &stcGpioInit);
    (void)GPIO_Init(GPIO_PORT_G, GPIO_PIN_02, &stcGpioInit);
        (void)GPIO_Init(GPIO_PORT_E, GPIO_PIN_05, &stcGpioInit);
        (void)GPIO_Init(GPIO_PORT_C, GPIO_PIN_00, &stcGpioInit);
}

I/O口模拟SPI方式字节数据的函数为:
void send_byte(uint8_t data) 
{
    uint8_t count;
    for(count = 0; count < 8; count++)
    {
        CLR_CLK();
        if(data & 0x80)
        {
            SET_SDA();
        }
        else
        {
            CLR_SDA();
        }
        data <<= 1;
            SET_CLK();
    }
}

配置的写寄存器和数据的函数如下:
void write_register(uint8_t cmd)          
{
        CLR_CS();
        CLR_CLK();
        CLR_SDA();
        SET_CLK();
        send_byte(cmd);
        SET_CS();
}

void write_data(uint8_t data)
{
     CLR_CS();
         CLR_CLK();
         SET_SDA();
         SET_CLK();
         send_byte(data);
         SET_CS();
}

显示屏的初始化函数为:
void ili9341_init(void)
{
        write_register(0xCF);
    write_data(0x00);
    write_data(0xC1);
    write_data(0X30);
    write_register(0xED);
    write_data(0x64);
    write_data(0x03);
    write_data(0X12);
    write_data(0X81);
    write_register(0xE8);
    write_data(0x85);
    write_data(0x10);
    write_data(0x7A);
    write_register(0xCB);
    write_data(0x39);
    write_data(0x2C);
    write_data(0x00);
    write_data(0x34);
    write_data(0x02);
    write_register(0xF7);
    write_data(0x20);
    write_register(0xEA);
    write_data(0x00);
    write_data(0x00);
    write_register(0xC0);
    write_data(0x1B);
    write_register(0xC1);
    write_data(0x01);
    write_register(0xC5);
    write_data(0x30);
    write_data(0x30);
    write_register(0xC7);
    write_data(0XB7);
    write_register(0x36);
    write_data(0x08);
    write_register(0x3A);
    write_data(0x55);
    write_register(0xB1);
    write_data(0x00);
    write_data(0x1A);
    write_register(0xB6);
    write_data(0x0A);
    write_data(0xA2);
    write_register(0xF2);
    write_data(0x00);
    write_register(0x26);
    write_data(0x01);
    write_register(0xE0);
    write_data(0x0F);
    write_data(0x2A);
    write_data(0x28);
    write_data(0x08);
    write_data(0x0E);
    write_data(0x08);
    write_data(0x54);
    write_data(0XA9);
    write_data(0x43);
    write_data(0x0A);
    write_data(0x0F);
    write_data(0x00);
    write_data(0x00);
    write_data(0x00);
    write_data(0x00);
    write_register(0XE1);
    write_data(0x00);
    write_data(0x15);
    write_data(0x17);
    write_data(0x07);
    write_data(0x11);
    write_data(0x06);
    write_data(0x2B);
    write_data(0x56);
    write_data(0x3C);
    write_data(0x05);
    write_data(0x10);
    write_data(0x0F);
    write_data(0x3F);
    write_data(0x3F);
    write_data(0x0F);
    write_register(0x2B);
    write_data(0x00);
    write_data(0x00);
    write_data(0x01);
    write_data(0x3f);
    write_register(0x2A);
    write_data(0x00);
    write_data(0x00);
    write_data(0x00);
    write_data(0xef);         
    write_register(0x11);
    DDL_DelayMS(10);
    write_register(0x29);
}

实现色彩清屏处理的函数为:
void ili9341_clear(int c)
{
          uint32_t index=0;
          set_cursor(0x00, 0x0000);
          gram_prepare();
          for(index = 0; index < (320*240); index++)
          {
                    write_data(c >> 8);
                    write_data(c);
          }
}

仿照清屏函数,实现一个50*50像素点的图标显示函数为:
void showimage(void)
{
    int i,j;
    set_cursor(10,10);
        gram_prepare();
    for(j=0;j<50;j++)
    {
          set_cursor(10,10+j);
          gram_prepare();
              for(i=0;i<50;i++)
          {
              write_data(gImage_tb[(j*50+i)*2]);
              write_data(gImage_tb[(j*50+i)*2+1]);
          }
    }
}

其中,语句set_cursor(10,10)是将绘制图标的位置设置为x=10,y=10的坐标处;函数write_data()的作用则是输出色彩的数据。
实现字符显示的函数为:
void _GUI_DispChar(char c, int x, int y, const char *pdata, int font_xsize, int font_ysize, int fcolor, int bcolor)
{
    uint8_t j,pos,t;
    uint8_t temp;
    uint8_t XNum;
    uint32_t base;
    XNum = (font_xsize/8) + 1;
    if(font_ysize%8 == 0)
    {
        XNum--;
    }
    if(c < ' ')
    {
        return;
    }
    c = c - ' ';
    base = (c*XNum*font_ysize);
    for(j = 0; j < XNum; j++)
    {
        for(pos = 0; pos < font_ysize; pos++)
        {
            temp = (uint8_t)pdata[base + pos + j*font_ysize];
            if(j < XNum)
            {
                for(t = 0; t < 8; t++)
                {
                    if((temp>>t)&0x01)
                    {
                        ili9341_draw_pixel(fcolor, x+t, y+pos);
                    }
                    else
                    {
                        ili9341_draw_pixel(bcolor, x+t, y+pos);
                    }
                }
            }
            else
            {
                for(t = 0; t < font_xsize%8; t++)
                {
                    if((temp >> t) & 0x01)
                    {
                        ili9341_draw_pixel(fcolor, x+t, y+pos);
                    }
                    else
                    {
                        ili9341_draw_pixel(bcolor, x+t, y+pos);
                    }
                }
            }
        }
        x += 8;
    }
}

实现汉字显示的函数为:
void showhanzi16(unsigned int x,unsigned int y,unsigned char index, int fcolor, int bcolor) 
{
        unsigned char i,j,k;
        unsigned char *temp=hanzi16;
        temp+=index*32;
        for(j=0;j<16;j++)
        {
                for(k=0;k<2;k++)
                {
                        for(i=0;i<8;i++)
                        {
                                 if((*temp&(1<<i))!=0)
                                {
                                        ili9341_draw_pixel(fcolor, x+i+k*8, y+j);
                                }
                                else
                                {
                                        ili9341_draw_pixel(bcolor, x+i+k*8, y+j);
                                }
                        }
                        temp++;
                }
         }
}

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

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

实现3所示效果的主程序为:
int32_t main(void)
{
        LL_PERIPH_WE(EXAMPLE_PERIPH_WE);
        BSP_CLK_Init();
        BSP_IO_Init();
        BSP_LED_Init();
            BSP_LCD_IO_Init();
        LL_PERIPH_WP(EXAMPLE_PERIPH_WP);
            GPIO_ResetPins(GPIO_PORT_G, GPIO_PIN_02);
            GPIO_ResetPins(GPIO_PORT_F, GPIO_PIN_11);
            BSP_LCD_BKLCmd(EIO_PIN_SET);
            BSP_LCD_RSTCmd(EIO_PIN_SET);
            LCD_Init();
                ili9341_init();
              ili9341_clear(RED);
                BACK_COLOR=RED;
            POINT_COLOR=YELLOW;
                LCD_ShowString(70,17,"MDM-2802 & HC32F4A0");
                LCD_ShowString(70,37,"MP3");
                showhanzi16(100,37,32, YELLOW, RED);
                showhanzi16(120,37,33, YELLOW, RED);
                showhanzi16(140,37,34, YELLOW, RED);
                showhanzi16(160,37,35, YELLOW, RED);
                showhanzi16(180,37,36, YELLOW, RED);
                LCD_ShowString(60,300,"BY: jinglixixi");
                LCD_DrawLine(WHITE ,0, 10, 239, 10);
                LCD_DrawLine(WHITE ,0, 60, 239, 60);
            LCD_DrawLine(WHITE,0, 296, 239, 296);
                showimage();
                showhanzi16(30,80,37, YELLOW, RED);
                showhanzi16(60,80,0, YELLOW, RED);
                showhanzi16(80,80,1, YELLOW, RED);
                showhanzi16(100,80,2, YELLOW, RED);
                showhanzi16(60,110,3, YELLOW, RED);
                showhanzi16(80,110,4, YELLOW, RED);
                showhanzi16(100,110,5, YELLOW, RED);
                showhanzi16(120,110,6, YELLOW, RED);
                showhanzi16(60,140,7, YELLOW, RED);
                showhanzi16(80,140,8, YELLOW, RED);
                showhanzi16(60,170,9, YELLOW, RED);
                showhanzi16(80,170,10, YELLOW, RED);
                showhanzi16(60,200,11, YELLOW, RED);
                showhanzi16(80,200,12, YELLOW, RED);
                showhanzi16(100,200,13, YELLOW, RED);
                showhanzi16(120,200,14, YELLOW, RED);
                showhanzi16(60,230,15, YELLOW, RED);
                showhanzi16(80,230,16, YELLOW, RED);
                showhanzi16(100,230,17, YELLOW, RED);
                showhanzi16(120,230,18, YELLOW, RED);
                showhanzi16(140,230,19, YELLOW, RED);
                showhanzi16(60,260,20, YELLOW, RED);
                showhanzi16(80,260,21, YELLOW, RED);
                showhanzi16(100,260,22, YELLOW, RED);
                showhanzi16(120,260,23, YELLOW, RED);
                showhanzi16(140,260,24, YELLOW, RED);
                showhanzi16(160,260,25, YELLOW, RED);
                showhanzi16(180,260,26, YELLOW, RED);
                for (;;) {
              BSP_LED_Toggle(LED_BLUE);
                          BSP_LED_Toggle(LED_YELLOW);
                          BSP_LED_Toggle(LED_RED);
                          DDL_DelayMS(500);
          }
}

其中:语句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()的内容如下:
void BSP_LCD_IO_Init(void)
{
    /* Init LCD backlight IO */
    GPIO_OutputCmd(LCD_BKL_PORT, LCD_BKL_PIN, ENABLE);
    /* Init LCD control IO before direction setting */
    BSP_IO_WritePortPin(LCD_RST_PORT, LCD_RST_PIN, EIO_PIN_SET);
    /* LCD panel control IO set to output */
    BSP_IO_ConfigPortPin(LCD_RST_PORT, LCD_RST_PIN, EIO_DIR_OUT);
    /* Init touch panel control IO before direction setting */
    BSP_IO_WritePortPin(LCD_CTRST_PORT, LCD_CTRST_PIN, EIO_PIN_RESET);
    BSP_IO_WritePortPin(LCD_CTINT_PORT, LCD_CTINT_PIN, EIO_PIN_RESET);
    BSP_IO_ConfigPortPin(LCD_CTRST_PORT, LCD_CTRST_PIN, EIO_DIR_OUT);
    BSP_IO_ConfigPortPin(LCD_CTINT_PORT, LCD_CTINT_PIN, EIO_DIR_OUT);
    DDL_DelayMS(100UL);
    BSP_IO_WritePortPin(LCD_CTINT_PORT, LCD_CTINT_PIN, EIO_PIN_SET);
    DDL_DelayMS(100UL);
    BSP_IO_WritePortPin(LCD_CTRST_PORT, LCD_CTRST_PIN, EIO_PIN_SET);
    DDL_DelayMS(10UL);
    BSP_IO_WritePortPin(LCD_CTINT_PORT, LCD_CTINT_PIN, EIO_PIN_RESET);
    DDL_DelayMS(100UL);
    BSP_IO_ConfigPortPin(LCD_CTRST_PORT, LCD_CTRST_PIN, EIO_DIR_IN);
    BSP_IO_ConfigPortPin(LCD_CTINT_PORT, LCD_CTINT_PIN, EIO_DIR_IN);
}

以语句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 | 只看该作者
这是浪费引脚数啊

使用特权

评论回复
5
jinglixixi|  楼主 | 2023-3-21 16:37 | 只看该作者
chenjun89 发表于 2023-3-21 08:06
这是浪费引脚数啊

哈哈,是省引脚资源!

使用特权

评论回复
6
hilahope| | 2023-4-9 13:58 | 只看该作者
感觉串行的代码运行好复杂。              

使用特权

评论回复
7
mollylawrence| | 2023-4-9 14:24 | 只看该作者
HC32F4A0带有fsmc的接口吗

使用特权

评论回复
8
10299823| | 2023-4-9 14:29 | 只看该作者
这个评估板是官网提供的吗              

使用特权

评论回复
9
robincotton| | 2023-4-9 14:55 | 只看该作者
屏幕不错,分辨率挺高的。              

使用特权

评论回复
10
loutin| | 2023-4-9 15:28 | 只看该作者
驱动的移植的哪里的              

使用特权

评论回复
11
biechedan| | 2023-4-9 15:36 | 只看该作者
这个最大的刷   屏频率是多少              

使用特权

评论回复
12
pl202| | 2023-4-9 15:59 | 只看该作者
彩色屏幕的驱动效果不错。              

使用特权

评论回复
13
mnynt121| | 2023-4-9 16:13 | 只看该作者
可以使用dma驱动这个lcd?              

使用特权

评论回复
14
ingramward| | 2023-4-9 16:17 | 只看该作者
可以在开发板上LCD屏显示正弦波、方波、阶梯波信号吗

使用特权

评论回复
15
jinglixixi|  楼主 | 2023-4-10 08:11 | 只看该作者
ingramward 发表于 2023-4-9 16:17
可以在开发板上LCD屏显示正弦波、方波、阶梯波信号吗

可以

使用特权

评论回复
16
jinglixixi|  楼主 | 2023-4-10 08:12 | 只看该作者
mnynt121 发表于 2023-4-9 16:13
可以使用dma驱动这个lcd?

没试过

使用特权

评论回复
17
jinglixixi|  楼主 | 2023-4-10 08:13 | 只看该作者
loutin 发表于 2023-4-9 15:28
驱动的移植的哪里的

原飞思卡尔开发板的

使用特权

评论回复
18
jinglixixi|  楼主 | 2023-4-10 08:14 | 只看该作者
10299823 发表于 2023-4-9 14:29
这个评估板是官网提供的吗

是开发板测评提供的

使用特权

评论回复
19
喂什么玩意| | 2024-7-31 11:31 | 只看该作者
以GPIO口来模拟SPI的工作方式来驱动它。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

455

主题

2756

帖子

38

粉丝