DDZZ669 发表于 2020-9-20 15:46

【GD32450I-EVAL】+ 04液晶屏层叠显示与透明度调整测试

本帖最后由 DDZZ669 于 2020-9-20 15:44 编辑

<p>上篇 &quot;<a href="https://bbs.eeworld.com.cn/thread-1141611-1-1.html" target="_blank"> 【GD32450I-EVAL】+ 03库函数基础使用方法-以按键中断为例</a>&quot; 介绍了GD32库开发的基础使用方法,本篇来研究一下液晶显示屏。</p>

<p></p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p><strong><span style="font-size:26px;">1 RGB液晶屏</span></strong></p>

<p cid="n4" mdtype="paragraph">&nbsp;</p>

<p cid="n4" mdtype="paragraph">GD32450I开发板上带了一块4.3英寸的480x272的RGB接口显示屏,类型为TFT-LCD(Thin Film Transistor-Liquid Crystal Display),即薄膜晶体管液晶显示器。</p>

<p cid="n5" mdtype="paragraph">之前只用过MCU接口的屏幕,这里简单说一下区别:</p>

<ul>
        <li cid="n6" mdtype="paragraph"><strong>MCU-LCD</strong>:最初是为单片机(MCU)设计的,因单片机内存较小,把显存内置在LCD模块内部,通过专门的显示命令来更新显存,MCU屏不能做得很大。MCU屏显示图像,显示需要发送画点的命令来修改MCU内部RAM。</li>
        <li cid="n7" mdtype="paragraph"><strong>RGB-LCD</strong>:其显存是由系统内存充当,只要系统内存够大,RGB-LCD就可以做出较大尺寸。RGB屏显示图像,只需显存组织好数据,启动显示后,LCD-DMA会自动把显存通过RGB接口送到显示屏,因此RGB屏的刷新速度较快。</li>
</ul>

<p cid="n8" mdtype="paragraph">两种屏的工作方式示意图如下:</p>

<p cid="n8" mdtype="paragraph"></p>

<p cid="n8" mdtype="paragraph">&nbsp;</p>

<p cid="n8" mdtype="paragraph"><strong>关于屏幕的两种驱动模式:</strong></p>

<p cid="n8" mdtype="paragraph"></p>

<p>RGB屏一般有2种驱动模式:DE模式和SYNC模式(或称HV模式)。DE模式使用DE信号来确定有效数据,而SYNC模式,则需要行同步(Hsync)和场同步(Vsync),来表示扫描的行和列。</p>

<p>&nbsp;</p>

<p><strong>关于屏幕的一些参数:</strong></p>

<p></p>

<p>可以看到,虽然屏幕分辨率是480*272,但水平和垂直的总周期会大于这个数,边缘多出来的像素具体是什么作用可以先不用管,程序中屏幕初始化的时候会用到这些数,先知道如何对应起来即可。</p>

<p cid="n8" mdtype="paragraph">&nbsp;</p>

<p cid="n8" mdtype="paragraph">&nbsp;</p>

<p><strong><span style="font-size:26px;">2 GD32的TLI</span></strong></p>

<p>&nbsp;</p>

<p>TLI(TFT-LCD Interface)即液晶屏接口,它是GD32单片机自身提供的一种驱动RGB-LCD的一种控制接口。TLI支持两个独立的显示层,并支持层窗口和层混叠功能。其层叠显示过程如下图所示:</p>

<p></p>

<p>此图中,<strong>层0</strong>和<strong>层1</strong>即两个独立的显示层,另外还有一个<strong>BG层</strong>,即背景层,可以指定显示某种颜色,该层处于最底层。层0叠加在BG层之上,通过调节层0的透明度,可以与BG层融合显示。层1叠加在最上面,也可以调节透明度。这三个层叠加在一起,就是屏幕展现出来的效果。</p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p><span style="font-size:26px;"><strong>3 图片转RGB565</strong></span></p>

<p>&nbsp;</p>

<p>这款LCD支持多种像素格式,具体如下表,此次测试先使用RGB565格式,即红、绿、蓝分别占用5、6、5位来表示颜色值,所以描述一个彩色像素需要16位,即2个字节,也就是一个字。</p>

<p></p>

<p>&nbsp;</p>

<p><strong>图片转换成RGB565的16进制数据</strong>,可以使用一些小工具来转换,转换后保存成数组。</p>

<p>转换方法如下,先找一张自己需要的图片,然后使用Picture2Hex这个小软件,指定转换后图片的宽度和高度,选择图片转换即可,然后产生一个logo.c文件,将该文件中的数组放到自己的代码工程中使用。</p>

<p></p>

<p>&nbsp;</p>

<p><span style="font-size:26px;"><strong>4 层叠与透明度显示测试</strong></span></p>

<p>&nbsp;</p>

<p>上面介绍了一些基本原理,下面写一个测试程序来看一下层叠显示的效果。</p>

<p>&nbsp;</p>

<p><strong>首先是主函数部分</strong>,就是各种初始化,最后在按键中断中会来改变3个层的颜色或透明度:</p>

<pre>
<code class="language-cpp">int main(void)
{
    system_clock_config();
        systick_config();
    mytimer_init();
       
        key_config();//通过按键来改变3个层的颜色或透明度
       
        lcd_init();//LCD的GPIO等的初始化
        lcd_layer_init();//LCD的显示层的初始化
       
        tli_layer_enable(LAYER0);
        tli_layer_enable(LAYER1);
        tli_enable();//使能两个显示层
       
        //设置两个显示层的透明度
        lcd_layer_set(LCD_LAYER_FOREGROUND);
        lcd_transparency_set(125);//0~255
        lcd_layer_set(LCD_LAYER_BACKGROUND);
        lcd_transparency_set(155);//0~255

    while (1)
        {
                //主循环,什么也不做,在按键中断中会只改变透明度
    }
}</code></pre>

<p>&nbsp;</p>

<p>初始化部分主要开看LCD的初始化和层的初始化。</p>

<p><strong>先看LCD的初始化</strong>:</p>

<pre>
<code class="language-cpp">void lcd_init(void)
{
//--------此处省去GPIO、时钟等的初始化
   
    /* TLI initialization */
    tli_init_struct.signalpolarity_hs = TLI_HSYN_ACTLIVE_LOW;
    tli_init_struct.signalpolarity_vs = TLI_VSYN_ACTLIVE_LOW;
    tli_init_struct.signalpolarity_de = TLI_DE_ACTLIVE_LOW;
    tli_init_struct.signalpolarity_pixelck = TLI_PIXEL_CLOCK_TLI;
   
    /* LCD display timing configuration */
    tli_init_struct.synpsz_hpsz = 40;
    tli_init_struct.synpsz_vpsz = 9;
    tli_init_struct.backpsz_hbpsz = 42;
    tli_init_struct.backpsz_vbpsz = 11;
    tli_init_struct.activesz_hasz = 522;
    tli_init_struct.activesz_vasz = 283;
    tli_init_struct.totalsz_htsz = 524;
    tli_init_struct.totalsz_vtsz = 285;
       
    /* LCD background color configure*///最底层
    tli_init_struct.backcolor_red = 0xFF;
    tli_init_struct.backcolor_green = 0xFF;
    tli_init_struct.backcolor_blue = 0xFF;
    tli_init(&amp;tli_init_struct);
}
</code></pre>

<p>第1部分中,DE参数为Low,所以采用的是SYNC模式。</p>

<p>第2部分中,好多参数,可以先对照上面的屏幕参数表格。</p>

<p>第2部分中,就是叠加层中的&ldquo;BG层&rdquo;,即最底层,这里先都给0xFF,即白色。</p>

<p>&nbsp;</p>

<p><strong>再来看层的初始化:</strong></p>

<pre>
<code class="language-cpp">void lcd_layer_init(void)
{
    tli_layer_parameter_structtli_layer_init_struct;
       
    /* TLI layer1 configuration */ //layer1 前景层(最上层)
    tli_layer_init_struct.layer_window_leftpos = (0 + 43);//最左侧从0开始
    tli_layer_init_struct.layer_window_rightpos = (0 + 400 + 43 - 1); //最右侧到400结束
    tli_layer_init_struct.layer_window_toppos = (0 + 12);//最上侧从0开始
    tli_layer_init_struct.layer_window_bottompos = (0 + 200 + 12 - 1);//最下侧到200结束
    tli_layer_init_struct.layer_ppf = LAYER_PPF_RGB565;//RGB565格式
    tli_layer_init_struct.layer_sa = 0x0;//其余部分透明显示
    tli_layer_init_struct.layer_default_blue = 0xFF;      
    tli_layer_init_struct.layer_default_green = 0xFF;      
    tli_layer_init_struct.layer_default_red = 0xFF;         
    tli_layer_init_struct.layer_default_alpha = 0x0;//图片部分的透明度,之后可以通过按键修改
    tli_layer_init_struct.layer_acf1 = LAYER_ACF1_PASA;//LAYER_ACF1_SA;   
    tli_layer_init_struct.layer_acf2 = LAYER_ACF2_PASA;//LAYER_ACF2_SA;
    tli_layer_init_struct.layer_frame_bufaddr = (uint32_t)image_eeworld;//eeworld图片的RGB565数组
    tli_layer_init_struct.layer_frame_line_length = ((LCD_PIXEL_WIDTH * 2) + 3);
    tli_layer_init_struct.layer_frame_buf_stride_offset = (LCD_PIXEL_WIDTH * 2);
    tli_layer_init_struct.layer_frame_total_line_number = LCD_PIXEL_HEIGHT;
    tli_layer_init(LAYER1, &amp;tli_layer_init_struct);

    /* TLI layer0 configuration */ //layer0 背景层(中间层)
    tli_layer_init_struct.layer_window_leftpos = (80 + 43);//最左侧从80开始
    tli_layer_init_struct.layer_window_rightpos = (80 + 400 + 43 - 1);//最右侧到80+400结束
    tli_layer_init_struct.layer_window_toppos = (72 + 12);//最上侧从72开始
    tli_layer_init_struct.layer_window_bottompos = (72+ 200 + 12 - 1);//最下侧到72+200结束
    tli_layer_init_struct.layer_ppf = LAYER_PPF_RGB565;
    tli_layer_init_struct.layer_sa = 0x0;//其余部分透明显示
    tli_layer_init_struct.layer_default_blue = 0xFF;      
    tli_layer_init_struct.layer_default_green = 0xFF;      
    tli_layer_init_struct.layer_default_red = 0xFF;         
    tli_layer_init_struct.layer_default_alpha = 0x0;
    tli_layer_init_struct.layer_acf1 = LAYER_ACF1_PASA;   
    tli_layer_init_struct.layer_acf2 = LAYER_ACF2_PASA;
    tli_layer_init_struct.layer_frame_bufaddr = (uint32_t)image_gd32;//gd32图片的RGB565数组
    tli_layer_init_struct.layer_frame_line_length = ((LCD_PIXEL_WIDTH * 2) + 3);
    tli_layer_init_struct.layer_frame_buf_stride_offset = (LCD_PIXEL_WIDTH * 2);
    tli_layer_init_struct.layer_frame_total_line_number = LCD_PIXEL_HEIGHT;
    tli_layer_init(LAYER0, &amp;tli_layer_init_struct);

    tli_reload_config(TLI_REQUEST_RELOAD_EN);
    lcd_font_set(&amp;LCD_DEFAULT_FONT);
    tli_dither_config(TLI_DITHER_ENABLE);
}
</code></pre>

<p>这里的layer0与layer1即叠加层中的&ldquo;层0&rdquo;和&ldquo;层1&rdquo;,两个显示层都配置为宽400高200,其余的部分透明显示。</p>

<p>&nbsp;</p>

<p><strong>使用按键来修改BG层的颜色:</strong></p>

<pre>
<code class="language-cpp">void change_backcolor(int n)
{
        int i = n%4;
        switch(i)
        {
                case 0:
                        tli_init_struct.backcolor_red   = 0xFF;
                        tli_init_struct.backcolor_green = 0xFF;
                        tli_init_struct.backcolor_blue= 0xFF;
                  break;
                case 1:
                        tli_init_struct.backcolor_red   = 0xFF;
                        tli_init_struct.backcolor_green = 0x00;
                        tli_init_struct.backcolor_blue= 0x00;
                  break;
                case 2:
                        tli_init_struct.backcolor_red   = 0x00;
                        tli_init_struct.backcolor_green = 0xFF;
                        tli_init_struct.backcolor_blue= 0x00;
                  break;
                case 3:
                        tli_init_struct.backcolor_red   = 0x00;
                        tli_init_struct.backcolor_green = 0x00;
                        tli_init_struct.backcolor_blue= 0xFF;
                  break;
        }
        tli_init(&amp;tli_init_struct);
}
</code></pre>

<p>&nbsp;</p>

<p><strong>使用按键来修改层0和层1的透明度:</strong></p>

<pre>
<code class="language-cpp">void lcd_layer_set(uint32_t layer)
{
    if (layer == LCD_LAYER_BACKGROUND)
        {
      current_framebuffer = (uint32_t)image_gd32;//LCD_FRAME_BUFFER;
      current_layer = LCD_LAYER_BACKGROUND;
    }else
        {
      current_framebuffer = (uint32_t)image_eeworld;//LCD_FRAME_BUFFER + BUFFER_OFFSET;
      current_layer = LCD_LAYER_FOREGROUND;
    }
}
void lcd_transparency_set(uint8_t trans)
{
    if (current_layer == LCD_LAYER_BACKGROUND)
        {
      TLI_LxSA(LAYER0) = trans;
    }
        else
        {
      TLI_LxSA(LAYER1) = trans;
    }
    tli_reload_config(TLI_REQUEST_RELOAD_EN);
}
//改变层0的透明度-------------
void change_layer0_transparency(int n)
{
        int i = n%6;//0 1 2 3 4 5
       
        lcd_layer_set(LCD_LAYER_BACKGROUND);
        lcd_transparency_set(i*50);
}
//改变层1的透明度-------------
void change_layer1_transparency(int n)
{
        int i = n%6;//0 1 2 3 4 5
       
        lcd_layer_set(LCD_LAYER_FOREGROUND);
        lcd_transparency_set(i*50);
}
</code></pre>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p><span style="font-size:26px;"><strong>5 下载验证</strong></span></p>

<p>&nbsp;</p>

<p>编译一下程序:</p>

<pre>
<code class="language-bash">compiling picture.c...
linking...
Program Size: Code=4360 RO-data=334236 RW-data=80 ZI-data=1088
FromELF: creating hex file...
".\GD32F4xx-OBJ\USBH-HID.axf" - 0 Error(s), 5 Warning(s).
Build Time Elapsed:00:00:03
</code></pre>

<p>可以看到Code为4360字节,即4K多点,而<strong>RO-data有334236字节</strong>,即326K多,主要是RGB565的数组占用了较大的空间。</p>

<p>这里用到了了2个400x200的RGB565的数组,总大小为400x200x2x2=320000字节,即320K,占据了RO-data的大部分。</p>

<p>关于这几个大小的含义,可参考上篇 &quot;<a href="https://bbs.eeworld.com.cn/thread-1141611-1-1.html" target="_blank">【GD32450I-EVAL】+ 03库函数基础使用方法-以按键中断为例</a>&quot;中 &quot;<strong>程序编译下载</strong>&quot; 处的介绍。</p>

<p>&nbsp;</p>

<p>由于图片占用较大空间,<strong>下载程序时间较长</strong>(约半分钟),之后可以考虑如何先把图片烧写到flash的某个位置,然后程序来读取,这样不用每次都花时间来烧写图片数据。</p>

<p>&nbsp;</p>

<p><strong>演示视频如下</strong>,通过调节各层的透明度,可以清楚的看到各个层的叠加关系:</p>

<p><iframe allowfullscreen="true" border="0" frameborder="no" framespacing="0" height="450px" scrolling="no" src="//player.bilibili.com/player.html?aid=287198624&amp;bvid=BV1ef4y1D7uR&amp;cid=237198373&amp;page=1" width="750px"></iframe><br />
&nbsp;</p>

okhxyyo 发表于 2020-9-27 10:57

<p><a href="https://bbs.eeworld.com.cn/thread-1140981-1-1.html" target="_blank">兆易GD32450I-EVAL</a></p>

<p>汇总贴:<a href="https://bbs.eeworld.com.cn/thread-1140981-1-1.html">https://bbs.eeworld.com.cn/thread-1140981-1-1.html</a></p>

laoganzheng 发表于 2021-2-1 12:03

<p>LCD驱动IC寄存器不需要初始化?</p>

Bob_Kang 发表于 2022-12-14 17:29

<p>您好,请问这个的源代码,以及项目工程,可以共享一下吗?谢啦</p>

DDZZ669 发表于 2022-12-15 22:01

laoganzheng 发表于 2021-2-1 12:03
LCD驱动IC寄存器不需要初始化?

<p>抱歉,时间有点久了,找不到那个工程了,前段时间也有人私信过我这个代码<img height="51" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/sweat.gif" width="50" /></p>
页: [1]
查看完整版本: 【GD32450I-EVAL】+ 04液晶屏层叠显示与透明度调整测试