LCD彩条显示——FPGA学习笔记10

                                                                                                                        部分素材来自原子哥

一、LCD简介

        基本原理:在两块平行玻璃板中填充液晶材料,通过电场控制液晶分子旋转从而达到透光和遮光的目的。

LCD屏幕重要参数:分辨率、像素格式、驱动时序

分辨率:

像素格式:

        RGB:由红 绿 蓝三种颜色通道构成,这三种颜色的分量叠加决定实际颜色;通常,会给RGB图像加一个通道alpha,即透明度,这样就会有四个分量共同控制颜色。

        YUV:YUV是编译true-color颜色空间(color space)的种类,Y'UV, YUV, YCbCrYPbPr等专有名词都可以称为YUV,彼此有重叠。“Y”表示明亮度(LuminanceLuma),也就是灰阶值,“U”和“V”表示的则是色度(ChrominanceChroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。

格式转换:

驱动时序:

VSYNC:场同步信号        一帧信号的起始标志(切换下一张图片的标志)

VBP:场同步后沿

VFP:场同步前沿

HSYNC:行同步信号        切换下一行的标志

HBP:行同步后沿

HFP:行同步前沿

(行场同步前后沿统称消隐时间)

LCD屏幕参数:注意行显示周期单位是CLK,场显示周期是行

LCD行同步时序(DE):

可以使用DE做数据有效信号,DE拉高时,给出DATA数据。

LCD帧同步时序(DE):

可以使用DE做数据有效信号,DE拉高时,对DE进行计数,第一次拉高给出第一行数据,第二次拉高给出第二行数据........以此类推。

LCD屏幕接口:

LCD_RSTLCD复位信号
LCD_BL

背光

LCD_DE数据有效

二、实验任务

        本节的实验任务是使用正点原子开发板上的RGB TFT-LCD接口,驱动RGB LCD液晶屏(支持目前推出的所有RGB LCD屏),并显示出彩条。

三、程序设计

        1、框架设计

2、时序设计

(1)rd_id:

(2)clk_div:

(3) lcd_driver:

(4)lcd_display

(5)完整程序框架

3、波形时序图、代码编写

 (1)rd_id:

`timescale 1ns / 1ps

module rd_id(
input                   sys_clk     ,
input                   sys_rst_n   ,
input           [23:0]  lcd_rgb     ,
output  reg     [15:0]  lcd_id

);

reg  rd_flag;

always @(posedge sys_clk or negedge sys_rst_n ) begin
    if (!sys_rst_n) begin
        rd_flag <= 1'b0;
        lcd_id  <= 15'd0;
    end
    else begin
        if (rd_flag == 1'b0) begin
            rd_flag <= 1'b1;
            case ({lcd_rgb[7],lcd_rgb[15],lcd_rgb[23]})//BGR
                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: ;
            endcase
        end
    end
end

endmodule

(2)clk_div:(使用4384屏幕,驱动时钟25M)

`timescale 1ns / 1ps

module clk_div(
input           sys_clk     ,
input           sys_rst_n   ,
input   [15:0]  lcd_id      ,
output  reg     lcd_pclk

);

reg     div_4_cnt;
reg     clk_25M;
reg     clk_12_5M;

//25Mhz时钟
always @(posedge sys_clk or negedge sys_rst_n ) begin
    if (!sys_rst_n) begin
        clk_25M <= 1'b0;
    end
    else begin
        clk_25M <= !clk_25M;
    end
end

//12.5Mhz时钟
//位宽为1,会自动溢出,无需手动清零
always @(posedge sys_clk or negedge sys_rst_n ) begin
    if (!sys_rst_n) begin
        div_4_cnt <= 1'b0;
        clk_12_5M <= 1'b0;
    end    
    else begin
        if (div_4_cnt == 1'b1) begin
            clk_12_5M <= !clk_12_5M;
        end
        else begin
            clk_12_5M <= clk_12_5M;
        end
    end
end

//使用组合逻辑进行赋值
always @(*) begin
    case (lcd_id)
        16'h4342: lcd_pclk = clk_12_5M     ;
        16'h7084: lcd_pclk = clk_25M       ;
        16'h7016: lcd_pclk = sys_clk       ;
        16'h4384: lcd_pclk = clk_25M       ;
        16'h1018: lcd_pclk = sys_clk       ;
        default:  lcd_pclk = 1'b0          ;
    endcase
end

endmodule

 (3) lcd_driver:

`timescale 1ns / 1ps
//LCD屏幕驱动
module lcd_driver(
input               lcd_pclk         ,           //时钟
input               sys_rst_n       ,           //复位,低电平有效
input       [14:0]  lcd_id          ,           //LCD屏ID
input       [23:0]  pixel_data      ,           //像素数据

output              lcd_clk         ,           //LCD 像素时钟       
output              lcd_hs          ,           //LCD 行同步信号   
output              lcd_vs          ,           //LCD 场同步信号   
output              lcd_bl          ,           //LCD 背光控制信号  
output  reg         lcd_de          ,           //LCD 数据使能信号   
output              lcd_rst         ,           //LCD 屏幕复位信号      
output      [23:0]  lcd_rgb         ,           //LCD RGB888颜色数据       
output      [10:0]  pixel_xpos      ,           //当前像素点横坐标       
output      [10:0]  pixel_ypos      ,           //当前像素点纵坐标        
output  reg [10:0]  h_disp          ,           //LCD屏水平分辨率   
output  reg [10:0]  v_disp          ,           //LCD屏垂直分辨率   
output  reg         data_req                    //LCD屏幕 数据请求信号    

);

// 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  [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  ;    //场计数

assign  lcd_clk  =  lcd_pclk ;
assign  lcd_hs   =  1'b1     ;
assign  lcd_vs   =  1'b1     ;
assign  lcd_bl   =  1'b1     ;
assign  lcd_rst  =  1'b1     ;

assign  lcd_rgb = lcd_de ? pixel_data : 24'd0;

//行场时序参数
always @(posedge lcd_pclk) 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 sys_rst_n ) begin
    if (!sys_rst_n) begin
        h_cnt <= 11'd0;
    end 
    else begin
        if (h_cnt == h_total - 1'd1) begin
            h_cnt <= 11'd0;
        end
        else begin
            h_cnt <= h_cnt + 1'b1;
        end
    end
end

//场计数
always @(posedge lcd_pclk or negedge sys_rst_n ) begin
    if (!sys_rst_n) begin
        v_cnt <= 11'b0;
    end 
    else begin
        if (h_cnt == h_total - 1'd1) begin
            if (v_cnt == v_total - 1'b1) begin
                v_cnt <= 11'd0;
            end 
            else begin
                v_cnt <= v_cnt +1'b1;
            end
        end
    end
end

//数据请求信号,data_req
always @(posedge lcd_pclk or negedge sys_rst_n) begin
    if (!sys_rst_n) begin
        data_req <= 1'b0;
    end 
    else if((h_cnt >= h_sync + h_back - 2'd2) && (h_cnt < h_sync + h_back + h_disp - 2'd2) && (v_cnt >= v_sync + v_back) && (v_cnt < v_sync + v_back + v_disp))begin
        data_req <= 1'b1;
    end
    else begin
        data_req <= 1'b0;
    end
end

//阻塞赋值,会延迟一拍,因此lcd_de 比 data_req晚一拍
always @(posedge lcd_pclk or negedge sys_rst_n ) begin
    if (!sys_rst_n) begin
        lcd_de <= 1'b0;
    end
    else begin
        lcd_de <= data_req;
    end
end

//像素点坐标  
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;


endmodule





  

  





(4)lcd_display:

`timescale 1ns / 1ps

module lcd_display(
input               sys_clk     ,
input               sys_rst_n   ,
input   [10:0]      pixel_xpos  ,
input   [10:0]      pixel_ypos  ,
input   [10:0]      h_disp      ,
input   [10:0]      v_disp      ,
output  reg[23:0]   pixel_data                
);

parameter WHITE = 24'hFFFFFF;  //白色
parameter BLACK = 24'h000000;  //黑色
parameter RED   = 24'hFF0000;  //红色
parameter GREEN = 24'h00FF00;  //绿色
parameter BLUE  = 24'h0000FF;  //蓝色

//根据当前像素点坐标指定当前像素点颜色数据,在屏幕上显示彩条
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        pixel_data <= BLACK;
    else begin
        if((pixel_xpos >= 11'd0) && (pixel_xpos < h_disp/5*1))
            pixel_data <= WHITE;
        else if((pixel_xpos >= h_disp/5*1) && (pixel_xpos < h_disp/5*2))    
            pixel_data <= BLACK;
        else if((pixel_xpos >= h_disp/5*2) && (pixel_xpos < h_disp/5*3))    
            pixel_data <= RED;   
        else if((pixel_xpos >= h_disp/5*3) && (pixel_xpos < h_disp/5*4))    
            pixel_data <= GREEN;                
        else 
            pixel_data <= BLUE;      
    end    
end

endmodule

(5)lcd_top:

三态门:

`timescale 1ns / 1ps

module LCD_RGB_colorbar(
input               sys_clk     ,
input               sys_rst_n   ,

output              lcd_clk         ,           //LCD 像素时钟       
output              lcd_hs          ,           //LCD 行同步信号   
output              lcd_vs          ,           //LCD 场同步信号   
output              lcd_bl          ,           //LCD 背光控制信号  
output  reg         lcd_de          ,           //LCD 数据使能信号   
output              lcd_rst         ,           //LCD 屏幕复位信号      
inout      [23:0]  lcd_rgb                     //LCD RGB888颜色数据 
);

wire    [23:0]  lcd_rgb_o   ;
wire    [23:0]  lcd_rgb_i   ;
wire    [15:0]  lcd_id      ;

wire    [10:0]  pixel_xpos  ;
wire    [10:0]  pixel_ypos  ;
wire    [10:0]  h_disp      ;
wire    [10:0]  v_disp      ;

assign  lcd_rgb   = lcd_de ? lcd_rgb_o :{24{1'bz}} ;
assign  lcd_rgb_i = lcd_rgb ;


//识别屏幕ID
rd_id u_rd_id(
.sys_clk            (sys_clk  ),
.sys_rst_n          (sys_rst_n),
.lcd_rgb            (lcd_rgb_i),
.lcd_id             (lcd_id   )
);

//产生驱动屏幕时钟
clk_div u_clk_div(
.sys_clk            (sys_clk  ),
.sys_rst_n          (sys_rst_n),
.lcd_id             (lcd_id   ),
.lcd_pclk           (lcd_pclk )   
);

//LCD屏幕驱动
lcd_driver u_lcd_driver(
.lcd_pclk           (lcd_pclk  ),           //时钟
.sys_rst_n          (sys_rst_n ),           //复位,低电平有效
.lcd_id             (lcd_id    ),           //LCD屏ID
.pixel_data         (pixel_data),           //像素数据
       
.lcd_clk            (lcd_clk   ),           //LCD 像素时钟       
.lcd_hs             (lcd_hs    ),           //LCD 行同步信号   
.lcd_vs             (lcd_vs    ),           //LCD 场同步信号   
.lcd_bl             (lcd_bl    ),           //LCD 背光控制信号  
.lcd_de             (lcd_de    ),           //LCD 数据使能信号   
.lcd_rst            (lcd_rst   ),           //LCD 屏幕复位信号      
.lcd_rgb            (lcd_rgb_o ),           //LCD RGB888颜色数据       
.pixel_xpos         (pixel_xpos),           //当前像素点横坐标       
.pixel_ypos         (pixel_ypos),           //当前像素点纵坐标        
.h_disp             (h_disp    ),           //LCD屏水平分辨率 有效显示区域  
.v_disp             (v_disp    ),           //LCD屏垂直分辨率 有效显示区域  
.data_req           (data_req  )            //LCD屏幕 数据请求信号    
);

lcd_display u_lcd_display(
.sys_clk            (lcd_pclk   ),
.sys_rst_n          (sys_rst_n ),
.pixel_xpos         (pixel_xpos),
.pixel_ypos         (pixel_ypos),
.h_disp             (h_disp    ),
.v_disp             (v_disp    ),
.pixel_data         (pixel_data)              
);


endmodule

4、仿真文件

`timescale 1ns / 1ps

module lcd_rgb_tb();


reg     sys_clk         ;
reg     sys_rst_n       ;
wire    lcd_clk         ;
wire    lcd_hs          ;
wire    lcd_vs          ;
wire    lcd_bl          ;
wire    lcd_de          ;
wire    lcd_rst         ;
wire   [23:0]  lcd_rgb  ;         


always #10 sys_clk = !sys_clk;
assign lcd_rgb = lcd_de ? {24{1'bz}} : 24'h80;

initial begin
    sys_clk = 1'b0;
    sys_rst_n = 1'b0;
    #200
    sys_rst_n = 1'b1;
end

LCD_RGB_colorbar LCD_RGB_colorbar(
.sys_clk         (sys_clk  ),
.sys_rst_n       (sys_rst_n),
.lcd_clk         (lcd_clk  ),           //LCD 像素时钟       
.lcd_hs          (lcd_hs   ),           //LCD 行同步信号   
.lcd_vs          (lcd_vs   ),           //LCD 场同步信号   
.lcd_bl          (lcd_bl   ),           //LCD 背光控制信号  
.lcd_de          (lcd_de   ),           //LCD 数据使能信号   
.lcd_rst         (lcd_rst  ),           //LCD 屏幕复位信号      
.lcd_rgb         (lcd_rgb  )           //LCD RGB888颜色数据 

);

endmodule

五、下载验证

4.3寸
7寸

总结:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值