本文主要是介绍LCD彩条显示——FPGA学习笔记10,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
部分素材来自原子哥
一、LCD简介
基本原理:在两块平行玻璃板中填充液晶材料,通过电场控制液晶分子旋转从而达到透光和遮光的目的。
LCD屏幕重要参数:分辨率、像素格式、驱动时序
分辨率:
像素格式:
RGB:由红 绿 蓝三种颜色通道构成,这三种颜色的分量叠加决定实际颜色;通常,会给RGB图像加一个通道alpha,即透明度,这样就会有四个分量共同控制颜色。
YUV:YUV是编译true-color颜色空间(color space)的种类,Y'UV, YUV, YCbCr,YPbPr等专有名词都可以称为YUV,彼此有重叠。“Y”表示明亮度(Luminance或Luma),也就是灰阶值,“U”和“V”表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。
格式转换:
驱动时序:
VSYNC:场同步信号 一帧信号的起始标志(切换下一张图片的标志)
VBP:场同步后沿
VFP:场同步前沿
HSYNC:行同步信号 切换下一行的标志
HBP:行同步后沿
HFP:行同步前沿
(行场同步前后沿统称消隐时间)
LCD屏幕参数:注意行显示周期单位是CLK,场显示周期是行
LCD行同步时序(DE):
可以使用DE做数据有效信号,DE拉高时,给出DATA数据。
LCD帧同步时序(DE):
可以使用DE做数据有效信号,DE拉高时,对DE进行计数,第一次拉高给出第一行数据,第二次拉高给出第二行数据........以此类推。
LCD屏幕接口:
LCD_RST | LCD复位信号 |
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 / 1psmodule 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 ) beginif (!sys_rst_n) beginrd_flag <= 1'b0;lcd_id <= 15'd0;endelse beginif (rd_flag == 1'b0) beginrd_flag <= 1'b1;case ({lcd_rgb[7],lcd_rgb[15],lcd_rgb[23]})//BGR3'b000: lcd_id <= 16'h4342; //4.3' RGB-LCD RES:480x2723'b001: lcd_id <= 16'h7084; //7' RGB-LCD RES:800x4803'b010: lcd_id <= 16'h7016; //7' RGB-LCD RES:1024x6003'b100: lcd_id <= 16'h4384; //4.3' RGB-LCD RES:800x4803'b101: lcd_id <= 16'h1018; //10' RGB-LCD RES:1280x800default: ;endcaseendend
endendmodule
(2)clk_div:(使用4384屏幕,驱动时钟25M)
`timescale 1ns / 1psmodule 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 ) beginif (!sys_rst_n) beginclk_25M <= 1'b0;endelse beginclk_25M <= !clk_25M;end
end//12.5Mhz时钟
//位宽为1,会自动溢出,无需手动清零
always @(posedge sys_clk or negedge sys_rst_n ) beginif (!sys_rst_n) begindiv_4_cnt <= 1'b0;clk_12_5M <= 1'b0;end else beginif (div_4_cnt == 1'b1) beginclk_12_5M <= !clk_12_5M;endelse beginclk_12_5M <= clk_12_5M;endend
end//使用组合逻辑进行赋值
always @(*) begincase (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
endendmodule
(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) begincase(lcd_id)16'h4342 : beginh_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; end16'h7084 : beginh_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; end16'h7016 : beginh_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; end16'h4384 : beginh_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 : beginh_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; enddefault : beginh_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; endendcase
end//行计数
always @(posedge lcd_pclk or negedge sys_rst_n ) beginif (!sys_rst_n) beginh_cnt <= 11'd0;end else beginif (h_cnt == h_total - 1'd1) beginh_cnt <= 11'd0;endelse beginh_cnt <= h_cnt + 1'b1;endend
end//场计数
always @(posedge lcd_pclk or negedge sys_rst_n ) beginif (!sys_rst_n) beginv_cnt <= 11'b0;end else beginif (h_cnt == h_total - 1'd1) beginif (v_cnt == v_total - 1'b1) beginv_cnt <= 11'd0;end else beginv_cnt <= v_cnt +1'b1;endendend
end//数据请求信号,data_req
always @(posedge lcd_pclk or negedge sys_rst_n) beginif (!sys_rst_n) begindata_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))begindata_req <= 1'b1;endelse begindata_req <= 1'b0;end
end//阻塞赋值,会延迟一拍,因此lcd_de 比 data_req晚一拍
always @(posedge lcd_pclk or negedge sys_rst_n ) beginif (!sys_rst_n) beginlcd_de <= 1'b0;endelse beginlcd_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 / 1psmodule 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) beginif(!sys_rst_n)pixel_data <= BLACK;else beginif((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
endendmodule
(5)lcd_top:
三态门:
`timescale 1ns / 1psmodule 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 / 1psmodule 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 beginsys_clk = 1'b0;sys_rst_n = 1'b0;#200sys_rst_n = 1'b1;
endLCD_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
五、下载验证
总结:
这篇关于LCD彩条显示——FPGA学习笔记10的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!