明德扬吴老师 发表于 2020-10-8 14:00:13

【每周FPGA案例】至简设计系列_LCD入门案例_显示图片

至简设计系列_LCD显示图片

--作者:肖肖肖
本文为明德扬原创及录用文章,转载请注明出处!
1.1 总体设计1.1.1 概述液晶显示器是一-种通过液晶和色彩过滤器过滤光源,在平面面板上产生图像的数字显示器。LCD 的构造是在两片平行的玻璃基板当中放置液晶盒,下基板玻璃上设置薄膜晶体管,.上基板玻璃上设置彩色滤光片,通过薄膜晶体管上的信号与电压改变来控制液晶分子的转动方向,从而达到控制每个像素点偏振光出射与否而达到显示目的。与传统的阴极射线管相比,LCD具有占用空间小,低功耗,低辐射,无闪烁,降低视觉疲劳等优点。现在LCD已渐替代CRT成为主流,价格也已经下降了很多,并已充分的普及。
1.1.2 设计目标在7寸LCD显示屏上实现图片的居中显示。
1.1.3 系统结构框图系统结构框图如下所示:
图一1.1.4模块功能PLL模块实现功能1.       将输入的50MHz时钟分频输出40MHz时钟。
ROM模块实现功能2.       存储图像数据。
LCD驱动模块实现功能1、产生驱动LCD屏显示的时序2、读取ROM里存储的数据并输出显示
1.1.5顶层信号
信号名I/O位宽定义
clkI1系统工作时钟 50M
rst_nI1系统复位信号,低电平有效
hysO1LCD 行时序信号
vysO1LCD 场时序信号
lcd_deO1LCD 数据输入使能信号
lcd_rgbO24LCD RGB信号,RGB格式为使用24位来表示一个像素,RGB分量都用8位表示,取值范围为0-255。
lcd_dclkO1LCD 数据采样时钟



1.1.6参考代码
module top_mdyLcdPic(
    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接口信号下面为使用矩阵键盘时的接口信号:

信号名I/O位宽定义
aresetI1PLL复位信号,高电平有效
inclk0I1PLL输入时钟 50MHz
c0O1PLL输出时钟 40MHz

1.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工作时钟40MHz
qO8ROM输出数据

1.3.2设计思路本模块主要用于存储需要显示的图像数据,关于ROM的使用详细介绍请看下方数据手册:
1.4 LCD驱动模块设计1.4.1接口信号
信号名I/O位宽定义
clkI1模块工作时钟 40MHz
rst_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行像素。

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

   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                      rom_area      ;
   reg                rom_addr      ;
   wire            rom_data      ;


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
    rom_area = h_cnt >=((HDE_CENTRE-60) + (THB-1)) && h_cnt < ((HDE_CENTRE+60) + (THB-1)) && v_cnt >= ((VDE_CENTRE-27)+(TVB-1)) && v_cnt < ((VDE_CENTRE+28) +(TVB-1));
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(rom_area)
            lcd_rgb <= {rom_data,5'b11111,rom_data,5'b11111,rom_data,6'b111111};
      else
            lcd_rgb <= {24{1'b1}};
    end
    else begin
      lcd_rgb <=0;
    end
end


always@(*)begin
    if(active_area && rom_area)begin
            rom_addr = (h_cnt-((HDE_CENTRE-60)+(THB-1))) + 120*(v_cnt-((VDE_CENTRE-27)+(TVB-1)));
    end
end




fpga_rom u_fpga_rom(
                   .address (rom_addr),
                   .clock   (clk   ),
                   .q       (rom_data));


    endmodule

1.5 效果和总结
以下为工程上板后的现象效果图:
mp801开发板


ms980试验箱



感兴趣的朋友也可以访问明德扬论坛(http://www.fpgabbs.cn/)进行FPGA相关工程设计学习,也可以看一下我们往期的文章:《至简设计系列_LCD入门案例_边框显示》《至简设计系列_BCD译码实现》《至简设计系列_简易计算器》《至简设计系列_基于FPGA的超声波测距系统设计》《至简设计系列_串口回环工程》《至简设计系列_矩阵按键检测》《至简设计系列_闹钟》《至简设计系列_7段数码管显示》《阻塞赋值与非阻塞赋值》《参数例化时自动计算位宽的解决办法》
1.6 公司简介
明德扬是一家专注于FPGA领域的专业性公司,公司主要业务包括开发板、教育培训、项目承接、人才服务等多个方向。点拨开发板——学习FPGA的入门之选。
MP801开发板——千兆网、ADDA、大容量SDRAM等,学习和项目需求一步到位。网络培训班——不管时间和空间,明德扬随时在你身边,助你快速学习FPGA。周末培训班——明天的你会感激现在的努力进取,升职加薪明德扬来助你。就业培训班——七大企业级项目实训,获得丰富的项目经验,高薪就业。专题课程——高手修炼课:提升设计能力;实用调试技巧课:提升定位和解决问题能力;FIFO架构设计课:助你快速成为架构设计师;时序约束、数字信号处理、PCIE、综合项目实践课等你来选。项目承接——承接企业FPGA研发项目。人才服务——提供人才推荐、人才代培、人才派遣等服务。

【设计教程下载】


【设计视频教程】

https://www.bilibili.com/video/BV1Af4y117H4?p=46

【工程源码】











页: [1]
查看完整版本: 【每周FPGA案例】至简设计系列_LCD入门案例_显示图片