• Chapter006-FPGA学习之LCD显示


    作为嵌入式的核心输出手段之一,LCD屏幕在嵌入式领域内也有较高的地位,最基础的内容就是显示图片、字符、触摸控制,顺序学习就需要从底开始,首当其冲的就是LCD屏幕显示。

    硬件原理

    在正点原子开发板中,LCD使用的接口为RGB LCD接口,接口的内容包括以下几部分:
    在这里插入图片描述

    原理图如下:
    RGB LCD接口原理:
    在这里插入图片描述
    LCD屏原理图:
    在这里插入图片描述
    对应引脚列表如下:
    在这里插入图片描述
    在这里插入图片描述

    设计目标

    在屏幕上显示背景色、图片、字符;
    背景色设置为深蓝
    图片设置如下:
    请添加图片描述
    字符设置:爱思瓦特奔奔

    模块分析
    由于使用的LCD屏幕型号较多,且型号是用R7、G7、B7三个点的电阻判定,当这三个点为高阻态模式时,即可根据这几个脚的电平判定屏幕型号。
    显示需要红绿蓝各8根线、使能线、列同步信号线、行同步信号线、像素时钟线;
    为保证图片刷新率【1秒刷新多少张图片,刷新越多流畅度越高】,像素时钟需要根据总像素点数量计算,像素点【分辨率长×宽的总数】,故像素时钟设置为:目标刷新率(假设60Hz)×单张图片像素点(800×480)= 60×800×480 = 23040000Hz 约为23MHz。
    屏幕每行刷新的时序图如下:
    在这里插入图片描述
    上述操作在不同行实现,重复总行数次后,即可显示图片,总图片显示时序如下所示:
    在这里插入图片描述
    VBP、VFP、HBP和HFP可以理解为屏幕的黑边,如下所示:
    在这里插入图片描述
    底层模块
    所以需要设计的底层模块如下所示:
    1、ID识别模块(识别屏幕的ID,判定屏幕的分辨率和尺寸)【re_id.v】
    2、像素时钟生成模块(为图像刷新提供时钟)【clk_div.v】
    3、显示驱动模块(将图片数据转换为驱动RGB_LCD的信号)【lcd_driver.v】
    4、显示内容模块(构建需要显示的图片数据)【lcd_display.v】

    上层模块
    输入:
    时钟
    复位
    输出:
    RGB_LCD接口引脚

    模块原理图如下所示:
    在这里插入图片描述

    代码编辑

    Verilog语言的代码包括以下几个部分:
    一个用于例化子模块的顶层模块;

    1. ID识别模块【re_id.v】
    2. 像素时钟生成模块【clk_div.v】
    3. 显示驱动模块【lcd_driver.v】
    4. 显示内容模块【lcd_display.v】

    顶层模块相关代码

    顶层模块代码(lcd_rgb_colorbar.v):

    `timescale 1ns / 1ps
    //
    // Company: 
    // Engineer: 
    // 
    // Create Date: 2022/07/17 22:53:15
    // Design Name: 
    // Module Name: lcd_rgb_colorbar
    // Project Name: 
    // Target Devices: 
    // Tool Versions: 
    // Description: 
    // 
    // Dependencies: 
    // 
    // Revision:
    // Revision 0.01 - File Created
    // Additional Comments:
    // 
    //
    
    
    module lcd_rgb_colorbar(
        input sys_clk, //系统时钟
        input sys_rst_n, //系统复位
        
        //RGB LCD 接口
        output lcd_de, //LCD 数据使能信号
        output lcd_hs, //LCD 行同步信号
        output lcd_vs, //LCD 场同步信号
        output lcd_bl, //LCD 背光控制信号
        output lcd_clk, //LCD 像素时钟
        output lcd_rst, //LCD 复位
        inout [23:0] lcd_rgb //LCD RGB888 颜色数据
        );
        
    //wire define
    wire    [15:0]  lcd_id ;    //LCD 屏 ID
    wire            lcd_pclk ;  //LCD 像素时钟
     
    wire    [10:0]  pixel_xpos; //当前像素点横坐标
    wire    [10:0]  pixel_ypos; //当前像素点纵坐标
    wire    [10:0]  h_disp ;    //LCD 屏水平分辨率
    wire    [10:0]  v_disp ;    //LCD 屏垂直分辨率
    wire    [23:0]  pixel_data; //像素数据
    wire    [23:0]  lcd_rgb_o ; //输出的像素数据
    wire    [23:0]  lcd_rgb_i ; //输入的像素数据
    
    //*****************************************************
    //****              main code
    //*****************************************************
    
    //像素数据方向切换
    assign lcd_rgb = lcd_de ? lcd_rgb_o : {24{1'bz}};
    assign lcd_rgb_i = lcd_rgb;
    
    //读 LCD ID 模块
    rd_id u_rd_id(
        .clk (sys_clk ),
        .rst_n (sys_rst_n),
        .lcd_rgb (lcd_rgb_i),
        .lcd_id (lcd_id )
        );
        
    //时钟分频模块
    clk_div u_clk_div(
        .clk (sys_clk ),
        .rst_n (sys_rst_n),
        .lcd_id (lcd_id ),
        .lcd_pclk (lcd_pclk )
        );
    
    //LCD 显示模块
    lcd_display u_lcd_display(
        .lcd_pclk (lcd_pclk ),
        .rst_n (sys_rst_n ),
        .pixel_xpos (pixel_xpos),
        .pixel_ypos (pixel_ypos),
        .pixel_data (pixel_data)
        );
        
    //LCD 驱动模块
    lcd_driver u_lcd_driver(
        .lcd_pclk (lcd_pclk ),
        .rst_n (sys_rst_n ),
        .lcd_id (lcd_id ),
        .pixel_data (pixel_data),
        .pixel_xpos (pixel_xpos),
        .pixel_ypos (pixel_ypos),
        .h_disp (h_disp ),
        .v_disp (v_disp ),
        
        .lcd_de (lcd_de ),
        .lcd_hs (lcd_hs ),
        .lcd_vs (lcd_vs ),
        .lcd_bl (lcd_bl ),
        .lcd_clk (lcd_clk ),
        .lcd_rst (lcd_rst ),
        .lcd_rgb (lcd_rgb_o )
        );
    
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103

    顶层约束文件(lcd_rgb_colorbar.xdc):

    set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk]
    set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]
    set_property -dict {PACKAGE_PIN W18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[0]}]
    set_property -dict {PACKAGE_PIN W19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[1]}]
    set_property -dict {PACKAGE_PIN R16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[2]}]
    set_property -dict {PACKAGE_PIN R17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[3]}]
    set_property -dict {PACKAGE_PIN W20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[4]}]
    set_property -dict {PACKAGE_PIN V20 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[5]}]
    set_property -dict {PACKAGE_PIN P18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[6]}]
    set_property -dict {PACKAGE_PIN N17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[7]}]
    set_property -dict {PACKAGE_PIN V17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[8]}]
    set_property -dict {PACKAGE_PIN V18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[9]}]
    set_property -dict {PACKAGE_PIN T17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[10]}]
    set_property -dict {PACKAGE_PIN R18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[11]}]
    set_property -dict {PACKAGE_PIN Y18 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[12]}]
    set_property -dict {PACKAGE_PIN Y19 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[13]}]
    set_property -dict {PACKAGE_PIN P15 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[14]}]
    set_property -dict {PACKAGE_PIN P16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[15]}]
    set_property -dict {PACKAGE_PIN V16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[16]}]
    set_property -dict {PACKAGE_PIN W16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[17]}]
    set_property -dict {PACKAGE_PIN T14 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[18]}]
    set_property -dict {PACKAGE_PIN T15 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[19]}]
    set_property -dict {PACKAGE_PIN Y17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[20]}]
    set_property -dict {PACKAGE_PIN Y16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[21]}]
    set_property -dict {PACKAGE_PIN T16 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[22]}]
    set_property -dict {PACKAGE_PIN U17 IOSTANDARD LVCMOS33} [get_ports {lcd_rgb[23]}]
    set_property -dict {PACKAGE_PIN N18 IOSTANDARD LVCMOS33} [get_ports lcd_hs]
    set_property -dict {PACKAGE_PIN T20 IOSTANDARD LVCMOS33} [get_ports lcd_vs]
    set_property -dict {PACKAGE_PIN U20 IOSTANDARD LVCMOS33} [get_ports lcd_de]
    set_property -dict {PACKAGE_PIN M20 IOSTANDARD LVCMOS33} [get_ports lcd_bl]
    set_property -dict {PACKAGE_PIN P19 IOSTANDARD LVCMOS33} [get_ports lcd_clk]
    set_property -dict {PACKAGE_PIN L17 IOSTANDARD LVCMOS33} [get_ports lcd_rst]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    下层功能模块代码

    ID识别模块(识别屏幕的ID,判定屏幕的分辨率和尺寸)【re_id.v】

    `timescale 1ns / 1ps
    //
    // Company: 
    // Engineer: 
    // 
    // Create Date: 2022/07/17 23:03:58
    // Design Name: 
    // Module Name: rd_id
    // Project Name: 
    // Target Devices: 
    // Tool Versions: 
    // Description: 
    // 
    // Dependencies: 
    // 
    // Revision:
    // Revision 0.01 - File Created
    // Additional Comments:
    // 
    //
    
    
    module rd_id(
        input           clk ,       //时钟
        input           rst_n ,     //复位,低电平有效
        input   [23:0]  lcd_rgb,    //RGB LCD 像素数据,用于读取 ID
        output reg [15:0] lcd_id    //LCD 屏 ID
        );
    
    //reg define
    reg     rd_flag; //读 ID 标志
    
    //*****************************************************
    //****                  main code
    //*****************************************************
    
    //获取 LCD ID M2:B7 M1:G7 M0:R7
    always@(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            rd_flag <= 1'b0;
            lcd_id <= 16'd0;
        end
        else begin
            if(rd_flag == 1'b0) begin
                rd_flag <= 1'b1;
                case({lcd_rgb[7],lcd_rgb[15],lcd_rgb[23]})
                    3'b000 : lcd_id <= 16'h4342; //4.3' RGB LCD RES:480x272
                    3'b001 : lcd_id <= 16'h7084; //7' RGB LCD RES:800x480
                    3'b010 : lcd_id <= 16'h7016; //7' RGB LCD RES:1024x600
                    3'b100 : lcd_id <= 16'h4384; //4.3' RGB LCD RES:800x480
                    3'b101 : lcd_id <= 16'h1018; //10' RGB LCD RES:1280x800
                    default : lcd_id <= 16'd0;
                endcase
            end
        end
    end
           
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    像素时钟生成模块(为图像刷新提供时钟)【clk_div.v】

    `timescale 1ns / 1ps
    //
    // Company: 
    // Engineer: 
    // 
    // Create Date: 2022/07/17 23:11:07
    // Design Name: 
    // Module Name: clk_div
    // Project Name: 
    // Target Devices: 
    // Tool Versions: 
    // Description: 
    // 
    // Dependencies: 
    // 
    // Revision:
    // Revision 0.01 - File Created
    // Additional Comments:
    // 
    //
    
    
    module clk_div(
        input           clk, //50Mhz
        input           rst_n,
        input   [15:0]  lcd_id,
        output  reg     lcd_pclk
        );
        
    //reg define
    reg clk_25m;    //25M时钟
    reg clk_12_5m;  //12.5M时钟
    reg div_4_cnt;  //四分频标记
    
    //*****************************************************
    //****                  main code
    //*****************************************************  
    
    //时钟 2 分频 输出 25MHz 时钟
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)
            clk_25m <= 1'b0;
        else
            clk_25m <= ~clk_25m;
    end
    
    //时钟 4 分频 输出 12.5MHz 时钟
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            div_4_cnt <= 1'b0;
            clk_12_5m <= 1'b0;
        end
        else begin
            div_4_cnt <= div_4_cnt + 1'b1;
            if(div_4_cnt == 1'b1)
                clk_12_5m <= ~clk_12_5m;
        end
    end
    
    //根据LCD的ID选择对应屏幕的时钟
    always @(*) begin
        case(lcd_id)
            16'h4342 : lcd_pclk = clk_12_5m;
            16'h7084 : lcd_pclk = clk_25m;
            16'h7016 : lcd_pclk = clk;
            16'h4384 : lcd_pclk = clk_25m;
            16'h1018 : lcd_pclk = clk;
            default : lcd_pclk = 1'b0;
        endcase
    end
    
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    显示驱动模块(将图片数据转换为驱动RGB_LCD的信号)【lcd_driver.v】

    `timescale 1ns / 1ps
    //
    // Company: 
    // Engineer: 
    // 
    // Create Date: 2022/07/17 23:19:09
    // Design Name: 
    // Module Name: lcd_driver
    // Project Name: 
    // Target Devices: 
    // Tool Versions: 
    // Description: 
    // 
    // Dependencies: 
    // 
    // Revision:
    // Revision 0.01 - File Created
    // Additional Comments:
    // 
    //
    
    
    module lcd_driver(
        input           lcd_pclk,   //时钟
        input           rst_n,      //复位,低电平有效
        input   [15:0]  lcd_id,     //LCD 屏 ID
        input   [23:0]  pixel_data, //像素数据
        output  [10:0]  pixel_xpos, //当前像素点横坐标
        output  [10:0]  pixel_ypos, //当前像素点纵坐标
        output reg [10:0] h_disp,   //LCD 屏水平分辨率
        output reg [10:0] v_disp,   //LCD 屏垂直分辨率
        //RGB LCD 接口
        output          lcd_de,     //LCD 数据使能信号
        output          lcd_hs,     //LCD 行同步信号
        output          lcd_vs,     //LCD 场同步信号
        output          lcd_bl,     //LCD 背光控制信号
        output          lcd_clk,    //LCD 像素时钟
        output          lcd_rst,    //LCD 复位
        output  [23:0]  lcd_rgb     //LCD RGB888 颜色数据
        );
        
    //parameter define
    // 4.3' 480*272
    parameter  H_SYNC_4342   =  11'd41;     //行同步
    parameter  H_BACK_4342   =  11'd2;      //行显示后沿
    parameter  H_DISP_4342   =  11'd480;    //行有效数据
    parameter  H_FRONT_4342  =  11'd2;      //行显示前沿
    parameter  H_TOTAL_4342  =  11'd525;    //行扫描周期
       
    parameter  V_SYNC_4342   =  11'd10;     //场同步
    parameter  V_BACK_4342   =  11'd2;      //场显示后沿
    parameter  V_DISP_4342   =  11'd272;    //场有效数据
    parameter  V_FRONT_4342  =  11'd2;      //场显示前沿
    parameter  V_TOTAL_4342  =  11'd286;    //场扫描周期
       
    // 7' 800*480   
    parameter  H_SYNC_7084   =  11'd128;    //行同步
    parameter  H_BACK_7084   =  11'd88;     //行显示后沿
    parameter  H_DISP_7084   =  11'd800;    //行有效数据
    parameter  H_FRONT_7084  =  11'd40;     //行显示前沿
    parameter  H_TOTAL_7084  =  11'd1056;   //行扫描周期
       
    parameter  V_SYNC_7084   =  11'd2;      //场同步
    parameter  V_BACK_7084   =  11'd33;     //场显示后沿
    parameter  V_DISP_7084   =  11'd480;    //场有效数据
    parameter  V_FRONT_7084  =  11'd10;     //场显示前沿
    parameter  V_TOTAL_7084  =  11'd525;    //场扫描周期       
       
    // 7' 1024*600   
    parameter  H_SYNC_7016   =  11'd20;     //行同步
    parameter  H_BACK_7016   =  11'd140;    //行显示后沿
    parameter  H_DISP_7016   =  11'd1024;   //行有效数据
    parameter  H_FRONT_7016  =  11'd160;    //行显示前沿
    parameter  H_TOTAL_7016  =  11'd1344;   //行扫描周期
       
    parameter  V_SYNC_7016   =  11'd3;      //场同步
    parameter  V_BACK_7016   =  11'd20;     //场显示后沿
    parameter  V_DISP_7016   =  11'd600;    //场有效数据
    parameter  V_FRONT_7016  =  11'd12;     //场显示前沿
    parameter  V_TOTAL_7016  =  11'd635;    //场扫描周期
       
    // 10.1' 1280*800   
    parameter  H_SYNC_1018   =  11'd10;     //行同步
    parameter  H_BACK_1018   =  11'd80;     //行显示后沿
    parameter  H_DISP_1018   =  11'd1280;   //行有效数据
    parameter  H_FRONT_1018  =  11'd70;     //行显示前沿
    parameter  H_TOTAL_1018  =  11'd1440;   //行扫描周期
       
    parameter  V_SYNC_1018   =  11'd3;      //场同步
    parameter  V_BACK_1018   =  11'd10;     //场显示后沿
    parameter  V_DISP_1018   =  11'd800;    //场有效数据
    parameter  V_FRONT_1018  =  11'd10;     //场显示前沿
    parameter  V_TOTAL_1018  =  11'd823;    //场扫描周期
    
    // 4.3' 800*480   
    parameter  H_SYNC_4384   =  11'd128;    //行同步
    parameter  H_BACK_4384   =  11'd88;     //行显示后沿
    parameter  H_DISP_4384   =  11'd800;    //行有效数据
    parameter  H_FRONT_4384  =  11'd40;     //行显示前沿
    parameter  H_TOTAL_4384  =  11'd1056;   //行扫描周期
       
    parameter  V_SYNC_4384   =  11'd2;      //场同步
    parameter  V_BACK_4384   =  11'd33;     //场显示后沿
    parameter  V_DISP_4384   =  11'd480;    //场有效数据
    parameter  V_FRONT_4384  =  11'd10;     //场显示前沿
    parameter  V_TOTAL_4384  =  11'd525;    //场扫描周期    
    
    //reg define
    reg  [10:0] h_sync ;
    reg  [10:0] h_back ;
    reg  [10:0] h_total;
    reg  [10:0] v_sync ;
    reg  [10:0] v_back ;
    reg  [10:0] v_total;
    reg  [10:0] h_cnt  ;
    reg  [10:0] v_cnt  ;
    
    //wire define    
    wire        lcd_en;     //LCD使能信号
    wire        data_req;   //像素点颜色请求
    
    //*****************************************************
    //**                    main code
    //*****************************************************
    
    //RGB LCD 采用DE模式时,行场同步信号需要拉高
    assign  lcd_hs = 1'b1;        //LCD行同步信号
    assign  lcd_vs = 1'b1;        //LCD场同步信号
    
    assign  lcd_bl = 1'b1;        //LCD背光控制信号  
    assign  lcd_clk = lcd_pclk;   //LCD像素时钟
    assign  lcd_rst= 1'b1;        //LCD复位
    assign  lcd_de = lcd_en;      //LCD数据有效信号
    
    //使能RGB888数据输出
    assign  lcd_en = ((h_cnt >= h_sync + h_back) && (h_cnt < h_sync + h_back + h_disp)
                      && (v_cnt >= v_sync + v_back) && (v_cnt < v_sync + v_back + v_disp)) 
                      ? 1'b1 : 1'b0;
    
    //请求像素点颜色数据输入  
    assign data_req = ((h_cnt >= h_sync + h_back - 1'b1) && (h_cnt < h_sync + h_back + h_disp - 1'b1)
                      && (v_cnt >= v_sync + v_back) && (v_cnt < v_sync + v_back + v_disp)) 
                      ? 1'b1 : 1'b0;
                      
    //像素点坐标  
    assign pixel_xpos = data_req ? (h_cnt - (h_sync + h_back - 1'b1)) : 11'd0;
    assign pixel_ypos = data_req ? (v_cnt - (v_sync + v_back - 1'b1)) : 11'd0;
    
    //RGB888数据输出
    assign lcd_rgb = lcd_en ? pixel_data : 24'd0;
    
    //行场时序参数【配置之前设置的参数】
    always @(*) begin
        case(lcd_id)
            16'h4342 : begin
                h_sync  = H_SYNC_4342; 
                h_back  = H_BACK_4342; 
                h_disp  = H_DISP_4342; 
                h_total = H_TOTAL_4342;
                v_sync  = V_SYNC_4342; 
                v_back  = V_BACK_4342; 
                v_disp  = V_DISP_4342; 
                v_total = V_TOTAL_4342;            
            end
            16'h7084 : begin
                h_sync  = H_SYNC_7084; 
                h_back  = H_BACK_7084; 
                h_disp  = H_DISP_7084; 
                h_total = H_TOTAL_7084;
                v_sync  = V_SYNC_7084; 
                v_back  = V_BACK_7084; 
                v_disp  = V_DISP_7084; 
                v_total = V_TOTAL_7084;        
            end
            16'h7016 : begin
                h_sync  = H_SYNC_7016; 
                h_back  = H_BACK_7016; 
                h_disp  = H_DISP_7016; 
                h_total = H_TOTAL_7016;
                v_sync  = V_SYNC_7016; 
                v_back  = V_BACK_7016; 
                v_disp  = V_DISP_7016; 
                v_total = V_TOTAL_7016;            
            end
            16'h4384 : begin
                h_sync  = H_SYNC_4384; 
                h_back  = H_BACK_4384; 
                h_disp  = H_DISP_4384; 
                h_total = H_TOTAL_4384;
                v_sync  = V_SYNC_4384; 
                v_back  = V_BACK_4384; 
                v_disp  = V_DISP_4384; 
                v_total = V_TOTAL_4384;             
            end        
            16'h1018 : begin
                h_sync  = H_SYNC_1018; 
                h_back  = H_BACK_1018; 
                h_disp  = H_DISP_1018; 
                h_total = H_TOTAL_1018;
                v_sync  = V_SYNC_1018; 
                v_back  = V_BACK_1018; 
                v_disp  = V_DISP_1018; 
                v_total = V_TOTAL_1018;        
            end
            default : begin
                h_sync  = H_SYNC_4342; 
                h_back  = H_BACK_4342; 
                h_disp  = H_DISP_4342; 
                h_total = H_TOTAL_4342;
                v_sync  = V_SYNC_4342; 
                v_back  = V_BACK_4342; 
                v_disp  = V_DISP_4342; 
                v_total = V_TOTAL_4342;          
            end
        endcase
    end
    
    //行计数器对像素时钟计数
    always@ (posedge lcd_pclk or negedge rst_n) begin
        if(!rst_n) 
            h_cnt <= 11'd0;
        else begin
            if(h_cnt == h_total - 1'b1)
                h_cnt <= 11'd0;
            else
                h_cnt <= h_cnt + 1'b1;           
        end
    end
    
    //场计数器对行计数
    always@ (posedge lcd_pclk or negedge rst_n) begin
        if(!rst_n) 
            v_cnt <= 11'd0;
        else begin
            if(h_cnt == h_total - 1'b1) begin
                if(v_cnt == v_total - 1'b1)
                    v_cnt <= 11'd0;
                else
                    v_cnt <= v_cnt + 1'b1;    
            end
        end    
    end
        
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245

    构建ROM IP核,用于存储图片
    首先在IP核中搜索并选择Block Memory Generator
    基础配置如图所示:
    在这里插入图片描述
    端口A配置如下,此部分配置ROM空间,由于一个像素点由红绿蓝个8bit构成,共24bit,故宽度配置为24;
    深度配置为37026是由于我使用的图片分辨率为198*187;
    在这里插入图片描述
    此处配置数据源,需要将图片使用正点原子的转换工具PicToLCD_V1.1工具将图片转换为coe文件:
    在这里插入图片描述

    根据如下配置,在文件框中找到生成的图像文件后直接点击OK即可
    在这里插入图片描述
    汉字部分则使用正点原子提供的字符取模软件,将需要的汉字先以32*32的大小生成为图片,再将图片生成数据,生成数据的配置如下所示:
    在这里插入图片描述
    我生成的数据可见lcd_display.v中的char数组中的内容。

    显示内容模块(构建需要显示的图片数据)【lcd_display.v】

    `timescale 1ns / 1ps
    //
    // Company: 
    // Engineer: 
    // 
    // Create Date: 2022/07/17 23:34:59
    // Design Name: 
    // Module Name: lcd_display
    // Project Name: 
    // Target Devices: 
    // Tool Versions: 
    // Description: 
    // 
    // Dependencies: 
    // 
    // Revision:
    // Revision 0.01 - File Created
    // Additional Comments:
    // 
    //
    
    
    module lcd_display(
        input                lcd_pclk,    //时钟
        input                rst_n,       //复位,低电平有效
        input        [10:0]  pixel_xpos,  //当前像素点横坐标
        input        [10:0]  pixel_ypos,  //当前像素点纵坐标      
        output  reg  [23:0]  pixel_data   //像素数据
        );
        
    //parameter define  
    parameter WHITE = 24'hFFFFFF;  //白色
    parameter BLACK = 24'h000000;  //黑色
    parameter RED   = 24'hFF0000;  //红色
    parameter GREEN = 24'h00FF00;  //绿色
    parameter BLUE  = 24'h0000FF;  //蓝色
    parameter YELLO = 24'hFFFF00;  //黄色
    parameter CYAN  = 24'h00FFFF;  //青色
    
    //parameter define
    localparam PIC_X_START = 11'd1; //图片起始点横坐标
    localparam PIC_Y_START = 11'd1; //图片起始点纵坐标
    localparam PIC_WIDTH = 11'd198; //图片宽度
    localparam PIC_HEIGHT = 11'd187; //图片高度
    localparam CHAR_X_START= 11'd1; //字符起始点横坐标
    localparam CHAR_Y_START= 11'd197; //字符起始点纵坐标
    localparam CHAR_WIDTH = 11'd192; //字符宽度,6 个字符:32*6
    localparam CHAR_HEIGHT = 11'd32; //字符高度
    localparam BACK_COLOR = 24'h164A7A; //背景色,深蓝色
    localparam CHAR_COLOR = 24'hffFF00; //字符颜色,黄色
    
    //reg define
    reg [191:0] char[31:0]; //字符数组
    reg [15:0] rom_addr ; //ROM 地址
    
    //wire define
    wire [10:0] x_cnt; //横坐标计数器
    wire [10:0] y_cnt; //纵坐标计数器
    wire rom_rd_en ; //ROM 读使能信号
    wire [23:0] rom_rd_data ;//ROM 数据
    
    //*****************************************************
    //*******             main code
    //*****************************************************
    
    assign x_cnt = pixel_xpos - CHAR_X_START; //像素点相对于字符区域起始点水平坐标
    assign y_cnt = pixel_ypos - CHAR_Y_START; //像素点相对于字符区域起始点垂直坐标
    assign rom_rd_en = 1'b1; //读使能拉高,即一直读 ROM 数据
    
    //给字符数组赋值,显示汉字“爱思瓦特奔奔”,每个汉字大小为 32*32
    always @(posedge lcd_pclk) begin
        char[0 ]  <= 192'h000000000000000000000000000000000000000000000000;
        char[1 ]  <= 192'h000000000000000000000000000000000000000000000000;
        char[2 ]  <= 192'h000000F0000000000000000001C00E000001C0000001C000;
        char[3 ]  <= 192'h0000FFF007FFFFE00000000001C00E000001800000018000;
        char[4 ]  <= 192'h1FFFFFF807FFFFE00000000001C00E000003800000038000;
        char[5 ]  <= 192'h1FFFFFC00701C0603FFFFFF801C00E000003000000030000;
        char[6 ]  <= 192'h0FF781E00701C0603FFFFFF819C1FFF81FFFFFFC1FFFFFFC;
        char[7 ]  <= 192'h03C783E00701C0600070000019C1FFF81FFFFFFC1FFFFFFC;
        char[8 ]  <= 192'h03E3C3C00701C0600070000019C00E00000E1800000E1800;
        char[9 ]  <= 192'h01E3E78007FFFFE00060000019C00E00001C1C00001C1C00;
        char[10]  <= 192'h00E1C78007FFFFE0006000003FF80E0000380E0000380E00;
        char[11]  <= 192'h3FFFFFFC0701C06000FFFE003FF80E0000F1C78000F1C780;
        char[12]  <= 192'h3FFFFFFC0701C06000FFFE0031C3FFFE03E1C3E003E1C3E0;
        char[13]  <= 192'h3C0E003C0701C06000FFFE0031C3FFFE0F81C1FC0F81C1FC;
        char[14]  <= 192'h3C0F003C0701C06000E0060071C000C03F7FFF7C3F7FFF7C;
        char[15]  <= 192'h3C0F003C07FFFFE000E0060001C000C0187FFF18187FFF18;
        char[16]  <= 192'h0FFFFFF007FFFFE000C40E0001C000C00001C0000001C000;
        char[17]  <= 192'h0FFFFFF00000000000CE0E0001F800C00021C0000021C000;
        char[18]  <= 192'h003C00000000000000CF0E0001FBFFFE0031C7000031C700;
        char[19]  <= 192'h007C00000000C00001C78E000FE3FFFE0031C7000031C700;
        char[20]  <= 192'h007FFFC00731C06001C38E003FC000C00030070000300700;
        char[21]  <= 192'h00FFFFC00E30E07001C1CE003DC000C00030070000300700;
        char[22]  <= 192'h01FFFF800E30707801808E0001C040C01FFFFFFC1FFFFFFC;
        char[23]  <= 192'h07FE0F001C30603801800C0001C0E0C01FFFFFFC1FFFFFFC;
        char[24]  <= 192'h0F9F1F001C30001C01808C0001C0E0C00070070000700700;
        char[25]  <= 192'h3F0FBE003830018C038F8C0E01C070C00060070000600700;
        char[26]  <= 192'h7E07FC003830038803FF8C1C01C060C000E0070000E00700;
        char[27]  <= 192'h3803FC003030038007FC0E1C01C000C001C0070001C00700;
        char[28]  <= 192'h00FFFFFC003FFF8003C00FFC01C001C00780070007800700;
        char[29]  <= 192'h07FF3FFC003FFF00020007F801C00FC01F0007001F000700;
        char[30]  <= 192'h07F807F8000000000000000001C007800C0007000C000700;
        char[31]  <= 192'h030000000000000000000000000000000000000000000000;
    end
    
    //为LCD不同显示区域绘制图片、字符和背景色
    always @(posedge lcd_pclk or negedge rst_n) begin
        if (!rst_n)
            pixel_data <= BACK_COLOR;
        else if( (pixel_xpos >= PIC_X_START) && (pixel_xpos < PIC_X_START + PIC_WIDTH) 
              && (pixel_ypos >= PIC_Y_START) && (pixel_ypos < PIC_Y_START + PIC_HEIGHT) )
            pixel_data <= rom_rd_data ;  //显示图片
        else if((pixel_xpos >= CHAR_X_START) && (pixel_xpos < CHAR_X_START + CHAR_WIDTH)
             && (pixel_ypos >= CHAR_Y_START) && (pixel_ypos < CHAR_Y_START + CHAR_HEIGHT)) begin
            if(char[y_cnt][CHAR_WIDTH -1'b1 - x_cnt])
                pixel_data <= CHAR_COLOR;    //显示字符
            else
                pixel_data <= BACK_COLOR;    //显示字符区域的背景色
        end
        else
            pixel_data <= BACK_COLOR;        //屏幕背景色
    end
    
    //根据当前扫描点的横纵坐标为ROM地址赋值
    always @(posedge lcd_pclk or negedge rst_n) begin
        if(!rst_n)
            rom_addr <= 14'd0;
        //当横纵坐标位于图片显示区域时,累加ROM地址    
        else if((pixel_ypos >= PIC_Y_START) && (pixel_ypos < PIC_Y_START + PIC_HEIGHT) 
            && (pixel_xpos >= PIC_X_START) && (pixel_xpos < PIC_X_START + PIC_WIDTH)) 
            rom_addr <= rom_addr + 1'b1;
        //当横纵坐标位于图片区域最后一个像素点时,ROM地址清零    
        else if((pixel_ypos >= PIC_Y_START + PIC_HEIGHT))
            rom_addr <= 14'd0;
    end
    
    //ROM:存储图片
    blk_mem_gen_0  blk_mem_gen_0 (
      .clka  (lcd_pclk),    // input wire clka
      .ena   (rom_rd_en),   // input wire ena
      .addra (rom_addr),    // input wire [13 : 0] addra
      .douta (rom_rd_data)  // output wire [23 : 0] douta
    );
    
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146

    实验结果

    将屏幕的FPC排线和开发板的RGB_LCD接口进行连接,在Vivado中生成二进制流文件,并将二进制流文件下载进入FPGA,效果如下:
    在这里插入图片描述
    由图可知,一切都在以预想的方向实现!

  • 相关阅读:
    按键中断小灯蜂鸣器风扇
    SQL 语法书写准则
    IntelliJ IDEA快速查询maven依赖关系
    /usr/lib/x86_64-linux-gnu/libQt5Core.so.5: version `Qt_5.15‘ not found
    都说“存算分离”好,分布式数据库为何还要“进一步分离”?
    Makefile 中一些常用语法讲解
    sentinel-3卫星测高学习资料整理
    记一次DNS问题排查
    贪心算法—Problem Q
    072:vue+openlayers拖拽放大所选区域(DragPan示例代码)
  • 原文地址:https://blog.csdn.net/ASWaterbenben/article/details/125882313