mdyfpga 发表于 2022-6-30 11:52:01

【案例】 LCD显示叠加图片

本文为明德扬原创文章,转载请注明出处!
1.1 总体设计1.1.1 概述液晶显示器是一-种通过液晶和色彩过滤器过滤光源,在平面面板上产生图像的数字显示器。LCD 的构造是在两片平行的玻璃基板当中放置液晶盒,下基板玻璃上设置薄膜晶体管,.上基板玻璃上设置彩色滤光片,通过薄膜晶体管上的信号与电压改变来控制液晶分子的转动方向,从而达到控制每个像素点偏振光出射与否而达到显示目的。与传统的阴极射线管相比,LCD具有占用空间小,低功耗,低辐射,无闪烁,降低视觉疲劳等优点。现在LCD已渐替代CRT成为主流,价格也已经下降了很多,并已充分的普及。
1.1.2 设计目标在7寸LCD显示屏上实现图片显示。其中,在显示屏左上角显示明德扬的LOGO图标,在显示屏的中间居中显示字母“E”。
1.1.3 系统结构框图系统结构框图如下所示:

图一1.1.4模块功能
PLL模块实现功能1.       将输入的50MHz时钟分频输出40MHz时钟。
ROM模块实现功能1.       FPGA_rom存储明德扬LOGO的图像数据;
2.       e_rom存储字母“E”的图像数据。
LCD驱动模块实现功能1、产生驱动LCD屏显示的时序2、读取ROM里存储的数据并输出显示
1.1.5顶层信号信号名I/O位宽定义clkI1系统工作时钟 50Mrst_nI1系统复位信号,低电平有效hysO1LCD 行时序信号vysO1LCD 场时序信号lcd_deO1LCD 数据输入使能信号lcd_rgbO24LCD RGB信号,RGB格式为使用24位来表示一个像素,RGB分量都用8位表示,取值范围为0-255。lcd_dclkO1LCD 数据采样时钟

1.1.6参考代码
[*]module top_mdyLcdPicOverlay(
[*]    clk       ,
[*]    rst_n   ,
[*]    hys       ,
[*]    vys       ,
[*]    lcd_de    ,
[*]    lcd_rgb   ,
[*]    lcd_dclk
[*]    );
[*]

[*]    parameter   PICTURE_W = 24;
[*]

[*]    input                   clk         ;
[*]    input                   rst_n       ;
[*]    output                  hys         ;
[*]    output                  vys         ;
[*]    output                  lcd_de      ;
[*]    output lcd_rgb   ;
[*]    output                  lcd_dclk    ;
[*]   
[*]

[*]    wire                     clk_0      ;
[*]   
[*]    wire                     hys      ;
[*]    wire                     vys      ;
[*]    wire                     lcd_de   ;
[*]    wire      lcd_rgb    ;
[*]    wire                     lcd_dclk   ;
[*]

[*]

[*]//40MHz
[*]pll_40m u_pll_40m(
[*]            .areset   (~rst_n ),
[*]      .inclk0   (clk    ),
[*]            .c0         (clk_0)
[*]    );
[*]

[*]

[*]lcd_driveru2(
[*]   .clk          (clk_0       ),//40MHz
[*]   .rst_n      (rst_n       ),
[*]                        
[*]   .hys          (hys         ),
[*]   .vys          (vys         ),
[*]   .lcd_de       (lcd_de      ),                  
[*]   .lcd_rgb      (lcd_rgb   ),
[*]   .lcd_dclk   (lcd_dclk    )
[*]    );
[*]

[*]endmodule
复制代码
1.2 PLL模块设计1.2.1接口信号下面为PLL的接口信号:
信号名I/O位宽定义aresetI1PLL复位信号,高电平有效inclk0I1PLL输入时钟 50MHzc0O1PLL输出时钟 40MHz1.2.2 设计思路本模块主要用于产生LCD驱动时序所需要的时钟,关于PLL的使用详细介绍请看下方链接:http://www.fpgabbs.cn/forum.php?mod=viewthread&tid=322&fromuid=100105
1.3 ROM模块设计
1.3.1接口信号信号名I/O位宽定义addressI16ROM数据存放地址clockI1ROM工作时钟40MHzqO8ROM输出数据1.3.2设计思路本模块主要用于存储需要显示的图像数据,关于ROM的使用详细介绍请查看IP核右上角数据手册“Documentation”。
1.4 LCD驱动模块设计
1.4.1接口信号信号名I/O位宽定义clkI1模块工作时钟 40MHzrst_nI1系统复位信号,低电平有效hysO1LCD 行时序信号vysO1LCD 场时序信号lcd_deO1LCD 数据输入使能信号lcd_rgbO24LCD RGB信号,RGB格式为使用24位来表示一个像素,RGB分量都用8位表示,取值范围为0-255。lcd_dclkO1LCD 数据采样时钟1.4.2设计思路产生驱动LCD显示的行场时序信号,其计数器架构如下图所示:

行计数器h_cnt:该计数器用来计算行同步信号的帧长。加一条件为1,表示一直在计数。结束条件为数1056个,也就是一行有1056个像素。场计数器v_cnt:该计数器用来计算场同步信号的帧长。加一条件为end_h_cnt,即行计数器的计数器的结束条件,表示每计数完一行像素就加一。结束条件为数525个,也就是一共有525行像素。其中,在从存储图像“E”的ROM里读取数据的时候,有一个操作就是读取的地址从第8位开始,也就是说18位数据地址,低三位不读,读取的是e_rom_addr。有这样一个操作的话就能实现对存储的图像进行8倍的放大显示。
1.4.3参考代码
[*]module lcd_driver(
[*]    clk          ,//40MHz
[*]    rst_n      ,
[*]

[*]    hys          ,
[*]    vys          ,
[*]    lcd_de       ,
[*]    lcd_rgb      ,
[*]    lcd_dclk   
[*]);
[*]

[*]   input                  clk             ;
[*]   input                  rst_n         ;
[*]

[*]   output                   hys             ;
[*]   output                   vys             ;
[*]   output                   lcd_de          ;
[*]   output             lcd_rgb         ;
[*]   output                   lcd_dclk      ;
[*]

[*]   reg                      hys             ;
[*]   reg                      vys             ;
[*]   reg                      lcd_de          ;
[*]   reg                lcd_rgb         ;
[*]   wire                     lcd_dclk      ;
[*]

[*]   //1056
[*]   parameter         THPW      = 20         ;   
[*]   parameter         THB       = 46         ;   
[*]   parameter         THD       = 800      ;   
[*]   parameter         THFP      = 210      ;   
[*]   
[*]   //525
[*]   parameter         TVPW      = 10         ;   
[*]   parameter         TVB       = 23         ;   
[*]   parameter         TVD       = 480      ;   
[*]   parameter         TVFP      = 22         ;   
[*]

[*]   parameter       HDE_CENTRE= THD/2      ;//400
[*]   parameter       VDE_CENTRE= TVD/2      ;//240
[*]

[*]   parameter       LOGO_X0   = (0   + (THB-1))         ;   
[*]   parameter       LOGO_X1   = (120 + (THB-1))         ;   
[*]   parameter       LOGO_Y0   = (0   + (TVB-1))         ;   
[*]   parameter       LOGO_Y1   = (55+ (TVB-1))         ;
[*]

[*]   parameter         E_X0      = ((HDE_CENTRE-200) + (THB-1))      ;   
[*]   parameter         E_X1      = ((HDE_CENTRE+200) + (THB-1))      ;   
[*]   parameter         E_Y0      = ((VDE_CENTRE-150) + (TVB-1))      ;   
[*]   parameter         E_Y1      = ((VDE_CENTRE+150) + (TVB-1))      ;   
[*]

[*]   reg   [ 10:0]            h_cnt         ;
[*]   wire                     add_h_cnt       ;
[*]   wire                     end_h_cnt       ;
[*]   reg   [ 9:0]             v_cnt         ;
[*]   wire                     add_v_cnt       ;
[*]   wire                     end_v_cnt       ;
[*]

[*]

[*]   wire                     active_area   ;
[*]   reg                      logo_rom_area      ;
[*]   reg                logo_rom_addr      ;
[*]   wire            logo_rom_data      ;
[*]   reg                      e_rom_area      ;
[*]   reg                e_rom_addr      ;
[*]   wire            e_rom_data      ;
[*]   reg               e_rom_addr_low    ;
[*]   reg                      e_sel             ;
[*]   
[*]

[*]

[*]always @(posedge clk or negedge rst_n) begin
[*]    if (rst_n==0) begin
[*]      h_cnt <= 0;
[*]    end
[*]    else if(add_h_cnt) begin
[*]      if(end_h_cnt)
[*]            h_cnt <= 0;
[*]      else
[*]            h_cnt <= h_cnt+1 ;
[*]   end
[*]end
[*]assign add_h_cnt = 1;
[*]assign end_h_cnt = add_h_cnt&& h_cnt == (THB + THD + THFP)-1 ;
[*]

[*]

[*]

[*]always @(posedge clk or negedge rst_n) begin
[*]    if (rst_n==0) begin
[*]      v_cnt <= 0;
[*]    end
[*]    else if(add_v_cnt) begin
[*]      if(end_v_cnt)
[*]            v_cnt <= 0;
[*]      else
[*]            v_cnt <= v_cnt+1 ;
[*]   end
[*]end
[*]assign add_v_cnt = end_h_cnt;
[*]assign end_v_cnt = add_v_cnt&& v_cnt == (TVB + TVD + TVFP)-1 ;
[*]

[*]/*******************************************************/
[*]    //dclk
[*]    assign lcd_dclk = clk;
[*]

[*]    //hsync
[*]    always@(posedge clk or negedge rst_n)begin
[*]      if(rst_n==1'b0)begin
[*]            hys <= 0;
[*]      end
[*]      else if(add_h_cnt && h_cnt==THPW-1)begin
[*]            hys <= 1;
[*]      end
[*]      else if(end_h_cnt)begin
[*]            hys <= 0;
[*]      end
[*]    end
[*]

[*]

[*]    //vsync
[*]    always@(posedge clk or negedge rst_n)begin
[*]      if(rst_n==1'b0)begin
[*]            vys <= 0;
[*]      end
[*]      else if(add_v_cnt && v_cnt==TVPW-1)begin
[*]            vys <= 1;
[*]      end
[*]      else if(end_v_cnt)begin
[*]            vys <= 0;
[*]      end
[*]    end
[*]   
[*]

[*]    //lcd_de
[*]    always@(posedge clk or negedge rst_n)begin
[*]      if(rst_n==1'b0)begin
[*]            lcd_de <= 0;
[*]      end
[*]      else if(active_area)begin
[*]            lcd_de <= 1;
[*]      end
[*]      else begin
[*]            lcd_de <= 0;
[*]      end
[*]    end
[*]   
[*]

[*]/********************************************************************/   
[*]

[*]

[*]

[*]assign active_area = h_cnt>=(THB-1) && h_cnt<(THB+THD-1) && v_cnt>=(TVB-1) && v_cnt<(TVB+TVD-1);
[*]

[*]

[*]always@(*)begin
[*]    logo_rom_area = h_cnt >=LOGO_X0 && h_cnt < LOGO_X1 && v_cnt >= LOGO_Y0 && v_cnt < LOGO_Y1;
[*]end
[*]

[*]always@(*)begin
[*]    e_rom_area = h_cnt >=E_X0 && h_cnt < E_X1 && v_cnt >= E_Y0 && v_cnt < E_Y1;
[*]end
[*]

[*]

[*]

[*]always@(posedge clk or negedge rst_n)begin
[*]    if(rst_n==1'b0)begin
[*]      lcd_rgb <= 0;
[*]    end
[*]    else if(active_area)begin
[*]      if(logo_rom_area)
[*]            lcd_rgb <= {logo_rom_data,5'b11111,logo_rom_data,5'b11111,logo_rom_data,6'b111111};
[*]      else if(e_rom_area)
[*]            lcd_rgb <= {24{e_sel}};
[*]      else
[*]            lcd_rgb <= {24{1'b1}};
[*]    end
[*]    else begin
[*]      lcd_rgb <=0;
[*]    end
[*]end
[*]

[*]

[*]

[*]

[*]always@(*)begin
[*]    logo_rom_addr = (h_cnt-LOGO_X0) + 120*(v_cnt-LOGO_Y0);
[*]end
[*]

[*]always@(*)begin
[*]    e_rom_addr = (h_cnt-E_X0) + 400*(v_cnt-E_Y0);
[*]end
[*]

[*]

[*]

[*]always@(posedge clk or negedge rst_n)begin
[*]    if(rst_n==1'b0)begin
[*]      e_rom_addr_low <= 0;
[*]    end
[*]    else begin
[*]      e_rom_addr_low <= e_rom_addr;
[*]    end
[*]end
[*]

[*]

[*]always@(*)begin
[*]    e_sel = ~e_rom_data;
[*]end
[*]

[*]

[*]fpga_rom u_fpga_rom(
[*]                   .address (logo_rom_addr),
[*]                   .clock   (clk   ),
[*]                   .q       (logo_rom_data));
[*]

[*]e_rom u_e_rom(
[*]    .address   (e_rom_addr),
[*]    .clock   (clk),
[*]    .q         (e_rom_data));
[*]

[*]

[*]    endmodule
复制代码
1.5 效果和总结以下为工程上板后的现象效果图:
mp801开发板
https://article.biliimg.com/bfs/article/9c80e33cf7a60a059f5c9be8321865785e340e4d.jpg
ms980试验箱
https://article.biliimg.com/bfs/article/2c139b04fb83d2192feb5281dead92fd3458a5e6.jpg


设计视频和源工程代码请到论坛下载学习:http://www.fpgabbs.cn/thread-1162-1-1.html访问明德扬论坛(http://www.fpgabbs.cn/)进行更多FPGA相关工程设计学习。
需要更多案例请联系易老师领取:13112063618
//article.biliimg.com/bfs/article/7f295d2415c07fdab8feab915bc968a2122f9d58.jpg@860w_860h.webp明德扬科技教育
页: [1]
查看完整版本: 【案例】 LCD显示叠加图片

Baidu
map