FPGA实现LCD显示屏显示彩条
目录
总体设计
读显示屏ID
读显示屏ID代码
时钟分频
时钟分频代码
LCD显示
lcd显示模块
LCD驱动模块
lcd驱动代码
顶层模块
顶层模块代码
总体设计
系统总体分为五个模块,分别是:rd_id(读显示屏ID模块),clk_div(时钟分频模块),lcd_display(lcd屏显示模块),lcd_driver(lcd屏驱动模块),和顶层模块lcd_rgb。
总体框图如下:
读显示屏ID
因为不同的LCD屏有着不同的分辨率,并对应了不同的时序参数,我们需要读取LCD_B7/G7/R7这三个管脚的状态,来判断当前显示屏的型号。
查找IO分配表可知LCD_B7/G7/R7分别为lcd_rgb[4],lcd_rgb[10],lcd_rgb[15]。
![](/assets/blank.gif)
读显示屏ID代码
module rd_id(
input wire sys_clk, //系统时钟
input wire sys_rst_n, //系统复位
input wire [15:0] lcd_rgb, //初始像素数据,用于读取IDoutput reg [15:0] lcd_id //读取到的ID
);reg rd_flag; //读ID标志always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n) beginrd_flag <= 1'b0;lcd_id <= 16'b0;endelse beginif(rd_flag == 1'b0) begin //说明开始上电rd_flag <= 1'b1;case({lcd_rgb[4],lcd_rgb[10],lcd_rgb[15]})3'b000: lcd_id <= 16'h4342; //4.3’ RES 480*2723'b001: lcd_id <= 16'h7084; //7’ RES 800*4803'b010: lcd_id <= 16'h7016; //7’ RES 1024*6003'b100: lcd_id <= 16'h4384; //4.3’ RES 800*4803'b101: lcd_id <= 16'h1018; //10’ RES 1280*800default : lcd_id <= 16'b0;endcaseendend
endendmodule
时钟分频
不同分辨率有着不同的时序参数,为了提高兼容性,我增加了时钟分频模块,能根据传入的ID号来产生对应所需的时钟。
其中时钟分频模块采用了quartus的IP核。
时钟分频代码
module clk_div(
input wire sys_clk, //系统时钟50MHz
input wire sys_rst_n, //系统复位
input wire [15:0] lcd_id, //ID号output reg lcd_pclk //lcd驱动时钟
);wire clk_10;
wire clk_34;
wire clk_50;
wire clk_70;wire locked;pll_clk pll_clk_inst (.areset ( ~sys_rst_n ), //锁相环高电平复位.inclk0 ( sys_clk ),.c0 ( clk_10 ),.c1 ( clk_34 ),.c2 ( clk_50 ),.c3 ( clk_70 ),.locked ( locked ));//---------根据分辨率选择对应的时钟-----------//
always @(*) beginif(locked) begincase(lcd_id)16'h4342 : lcd_pclk = clk_10; //9M16'h7084 : lcd_pclk = clk_34; //33.3M16'h7016 : lcd_pclk = clk_50; //50M16'h4384 : lcd_pclk = clk_34; //33.3M16'h1018 : lcd_pclk = clk_70; //70Mdefault : lcd_pclk = 1'b0;endcaseendelse beginlcd_pclk = 1'b0;end
endendmodule
LCD显示
显示的图案可以根据自己喜好设置,需要注意的就是h_disp和v_disp这两个信号,可以理解成LCD屏的有效显示边框/范围。原来是根据例程写了五等分的彩条(注释部分),后来图好玩改成了法国国旗,参数中的蓝色和红色我也改过了。
因为电脑自带画板显示的一般都是RGB888,但是LCD显示屏用的是RGB565,两者的位宽不一样。但RGB888转RGB565的方法也很简单,就是分别取8位红绿蓝的高位。
lcd显示模块代码
module lcd_display(
input wire lcd_pclk, //不同分辨率对应的时钟
input wire sys_rst_n, //系统复位信号
input wire [10:0] pixel_xpos, //当前像素点横坐标 (像素点数最大为1440,11位)
input wire [10:0] pixel_ypos, //当前像素点纵坐标
input wire [10:0] h_disp, //LCD屏水平分辨率
input wire [10:0] v_disp, //LCD屏垂直分辨率output reg [15:0] pixel_data //像素数据
);//parameter define
parameter WHITE = 16'b11111_111111_11111; //白色
parameter BLACK = 16'b00000_000000_00000; //黑色
parameter RED = 16'b11111_001111_00110; //红色
parameter GREEN = 16'b00000_111111_00000; //绿色
parameter BLUE = 16'b00000_010101_10100; //蓝色
parameter YELLOW = 16'b11111_111111_00000; //黄色always @(posedge lcd_pclk or negedge sys_rst_n) beginif(!sys_rst_n) beginpixel_data <= BLACK;endelse begin
// if(pixel_xpos > 11'b0 && pixel_xpos < h_disp/5*1)
// pixel_data <= RED;
// else if(pixel_xpos > h_disp/5*1 && pixel_xpos < h_disp/5*2)
// pixel_data <= YELLOW;
// else if(pixel_xpos > h_disp/5*2 && pixel_xpos < h_disp/5*3)
// pixel_data <= BLUE;
// else if(pixel_xpos > h_disp/5*3 && pixel_xpos < h_disp/5*4)
// pixel_data <= GREEN;
// else
// pixel_data <= WHITE;if(pixel_xpos > 11'b0 && pixel_xpos < h_disp/3*1)pixel_data <= BLUE;else if(pixel_xpos > h_disp/3*1 && pixel_xpos < h_disp/3*2)pixel_data <= WHITE;elsepixel_data <= RED;end
endendmodule
LCD驱动模块
每个时钟内会扫描一个像素点,所以需要设置计数器对扫到的像素点进行计数。根据计数值可以圈定LCD屏的有效区域,当处在这个范围之内时,lcd_de拉高,将传入的像素数据pixel_data通过数据端口lcd_rgb传出至屏幕。
在这里加一段别的博主对于lcd_req设置的理解,里面提到的子母计数器是h_cnt和v_cnt。
//...此处做一个简单的分析,lcd_de拉高,lcd_rgb[15:0]的值瞬间到达屏幕的对应像素点上。
// 我们最开始的分析是:cnt值->产生坐标->根据坐标确认有效范围->再往范围里放颜色值
// 所以说我们在上面写的那个就是有效范围,由于触发器的特性,所以要提前一个时钟周期将坐标值送出,才来的及在lcd_en为1时候准确的送出颜色值
// 而一场是由很多行组成的,母计数器,要比子计数器慢。子计数器变很多次,母计数器才变一次。所以对子计数器需要提前一个时钟周期发送出坐标。
// PS:如果没懂的话也没关系,因为我也比较晕。但只要时序对,屏幕就能出现颜色然后进行simulation或者实物调试
————————————————
版权声明:本文为CSDN博主「搞IC的那些年」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/helloworld573/article/details/113773634
lcd驱动代码
module lcd_driver(
input wire lcd_pclk, //不同分辨率对应的时钟
input wire sys_rst_n, //系统复位信号
input wire [15:0] lcd_id, //不同显示屏对应的ID
input wire [15:0] pixel_data, //像素数据output wire [10:0] pixel_xpos, //当前像素点横坐标 (像素点数最大为1440,11位)
output wire [10:0] pixel_ypos, //当前像素点纵坐标
output reg [10:0] h_disp, //LCD屏水平分辨率
output reg [10:0] v_disp, //LCD屏垂直分辨率output wire lcd_de, //RGB LCD数据使能
output wire lcd_hs, //RGB LCD行同步
output wire lcd_vs, //RGB LCD场同步
output wire lcd_clk, //RGB LCD像素时钟
output wire lcd_bl, //RGB LCD背光控制
output wire lcd_rst, //RGB LCD系统复位,低有效
output wire [15:0] lcd_rgb //RGB565颜色数据
);wire lcd_en;
wire data_req;//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 ;//数据使能
assign lcd_de = lcd_en;//行场同步
assign lcd_hs = 1'b1;
assign lcd_vs = 1'b1;//像素时钟
assign lcd_clk = lcd_pclk;//复位和背光
assign lcd_rst = (sys_rst_n == 1'b0) ? 1'b0 : 1'b1;
assign lcd_bl = (sys_rst_n == 1'b0) ? 1'b0 : 1'b1;//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; //场扫描周期 //行场时序参数
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'b0;endelse beginh_cnt <= (h_cnt == h_total - 1'b1) ? 11'b0 : h_cnt + 1'b1;end
end//场计数器对场像素点进行计数
always @(posedge lcd_pclk or negedge sys_rst_n) beginif(!sys_rst_n) beginv_cnt <= 11'b0;endelse if(h_cnt == h_total - 1'b1)beginv_cnt <= (v_cnt == v_total - 1'b1) ? 11'b0 : v_cnt + 1'b1;end
end//使能RGB565数据输出,lcd_en表示区域内像素点有效
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;//请求像素点颜色数据输入,提前一时钟将数据载入到lcd驱动模块
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;//RGB565数据输出
assign lcd_rgb = lcd_en ? pixel_data : 16'b0;//像素点坐标
assign pixel_xpos = data_req ? (h_cnt - (h_sync + h_back - 1'b1)) : 11'b0;
assign pixel_ypos = data_req ? (v_cnt - (v_sync + v_back - 1'b1)) : 11'b0;endmodule
顶层模块
比较需要注意的就是这里要把lcd_rgb定义为inout类型。当lcd_de信号为高电平时,此时输出的像素数据有效,将lcd_rgb的引脚方向切换成输出,并将LCD驱动模块输出的lcd_rgb_o(像素数据)连接至lcd_rgb引脚;当lcd_de信号为低电平时,此时输出的像素数据无效,将lcd_rgb 的引脚方向切换成输入。代码中将高阻状态“Z”赋值给lcd_rgb的引脚,表示此时lcd_rgb的引脚电平由外围电路决定,此时可以读取lcd_rgb的引脚电平,从而获取到LCD屏的ID。
顶层模块代码
module lcd_rgb(
input wire sys_clk, //系统时钟
input wire sys_rst_n, //系统复位信号output wire lcd_de, //RGB LCD数据使能
output wire lcd_hs, //RGB LCD行同步
output wire lcd_vs, //RGB LCD场同步
output wire lcd_clk, //RGB LCD像素时钟
output wire lcd_bl, //RGB LCD背光控制
output wire lcd_rst, //RGB LCD系统复位,低有效inout wire [15:0] lcd_rgb //RGB565颜色数据
);wire [15:0] lcd_rgb_i;
wire [15:0] lcd_rgb_o;
wire [15:0] lcd_id;
wire lcd_pclk; //分频时钟
wire [10:0] pixel_xpos;
wire [10:0] pixel_ypos;
wire [10:0] h_disp;
wire [10:0] v_disp;
wire [15:0] pixel_data;//数据双向端口
assign lcd_rgb = lcd_de ? lcd_rgb_o : 16'bz;
assign lcd_rgb_i = lcd_rgb;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), //50MHz.sys_rst_n(sys_rst_n),.lcd_id(lcd_id),.lcd_pclk(lcd_pclk)
);lcd_display u_lcd_display(.lcd_pclk(lcd_pclk), //不同分辨率对应的时钟.sys_rst_n(sys_rst_n), //系统复位信号.pixel_xpos(pixel_xpos), //当前像素点横坐标 (像素点数最大为1440,11位).pixel_ypos(pixel_ypos), //当前像素点纵坐标.h_disp(h_disp), //LCD屏水平分辨率.v_disp(v_disp), //LCD屏垂直分辨率.pixel_data(pixel_data) //像素数据
);lcd_driver u_lcd_driver(.lcd_pclk(lcd_pclk), //不同分辨率对应的时钟.sys_rst_n(sys_rst_n), //系统复位信号.lcd_id(lcd_id), //不同显示屏对应的ID.pixel_data(pixel_data), //像素数据.pixel_xpos(pixel_xpos), //当前像素点横坐标 (像素点数最大为1440,11位).pixel_ypos(pixel_ypos), //当前像素点纵坐标.h_disp(h_disp), //LCD屏水平分辨率.v_disp(v_disp), //LCD屏垂直分辨率.lcd_de(lcd_de), //RGB LCD数据使能.lcd_hs(lcd_hs), //RGB LCD行同步.lcd_vs(lcd_vs), //RGB LCD场同步.lcd_clk(lcd_clk), //RGB LCD像素时钟.lcd_bl(lcd_bl), //RGB LCD背光控制.lcd_rst(lcd_rst), //RGB LCD系统复位,低有效.lcd_rgb(lcd_rgb_o) //RGB565颜色数据
);endmodule
附一张野火画的框图
FPGA实现LCD显示屏显示彩条相关推荐
- DDR200T TFT - LCD 显示屏 显示图片 NucleiStudio 蜂鸟E203 详细教程 RISC-V
DDR200T TFT - LCD 显示屏 显示图片 NucleiStudio 蜂鸟E203 详细教程 RISC-V 前言 IMG2LCD软件生成RGB565格式图片 使用取模软件对图片取模 实验结果 ...
- ESP8266+CH340下载电路+LCD显示屏显示天气时钟
0.前言 之前一直进行软件编程方面的学习与应用,但所有软件都是基于一定的硬件基础,所以想通过做些比较有意思的小项目来入门硬件的设计与应用.看到ESP模块在物联网方面的应用比较多,于是准备设计一个许多人 ...
- 【Arduino】TFT LCD显示屏显示gif小电视太空人动图(基于Arduino框架ESP8266/ESP32、TFT_eSPI库、使用python脚本GIF转十六进制文件)
前言 之前使用ESP32 来控制TFT屏幕显示动图时,找到现有的工具,需要先将动图gif格式一帧帧转为jpg格式,再将一帧帧的jgp转为hex十六进制格式,整个过程好麻烦.现用python写了脚本 ...
- VGA显示彩条和图片(FPGA)
如愿 一.VGA协议 二.使用设备 三.模块设计 四.代码 五.总结 一.VGA协议 VGA(Video Graphics Array)视频图形阵列是 IBM 于1987年提出的一个使用模拟信号的电脑 ...
- 基于FPGA的VGA显示彩条、字符、图片
目录 一.VGA介绍 (一) VGA协议 (二) VGA端口介绍 (三) 色彩原理 (四)VGA显示原理 VGA通信协议: VGA时序解析 时钟分频 二.实现 1.彩条显示 2.字符显示 3.图片显 ...
- LCD显示屏常用函数总结(仅显示,不含触控)
LCD显示屏常用函数总结(仅显示,不含触控) size 清屏函数 画方块 显示字符 1 2 显示数字的函数 1,高位为0时不显示 2,高位为0时依旧显示 size LCD的size有三种可选:12-- ...
- 基于 FPGA 的 HDMI/DVI 显示
文章目录 前言 一.HDMI 与 DVI 的区别与联系 1.1 DVI 接口含义 1.2 HDMI 接口含义 1.3 HDMI 与 DVI 的区别 1.4 HDMI 与 DVI 的兼容性 1.5 HD ...
- F2—TFT显示彩条测试-2022-11-03
1.TFT与LCD TFT屏(ThinFilmTransistor)是薄膜晶体管型液晶显示屏,它的每一个象素点都是由集成在其后的薄膜晶体管即TFT来驱动的,这样不仅提高了显示屏的响应速度,同时可以精确 ...
- ZYNQ7020(黑金)纯verilog驱动4.3寸RGB接口TFT液晶屏(AN430)显示彩条
ZYNQ7020(黑金)纯verilog驱动4.3寸RGB接口TFT液晶屏(AN430)显示彩条 简介 像素(Pixel):像素是指由图像的小方格组成的,这些小方快都有一个明确的位置和被分配的色彩数值 ...
最新文章
- 《Typecript 入门教程》 2、访问控制符:public、private、protected、readonly
- 在JavaScript函数中定义全局变量
- 使用JSON.parse(),JSON.stringify()实现对对象的深拷贝
- Kubernetes存储之ConfigMap
- 摄像头图像分析目标物体大小位置_一文读懂图像定位及跟踪技术
- oracle 取第三大的值,Oracle 常见的几种访问提取数据的方式!
- TextView IME option
- 常用的CSS Hack技术集锦
- Inno Setup 操作XML
- hibernate中uuid和native等主键生成策略
- python生成器的作用是什么_看完这篇,你就知道Python生成器是什么
- 原生ES-Module在浏览器中的尝试
- 怎么轻松学JAVA(三个月拿实习Offer):小猿的JAVA后端之路(持续更新)
- 用html制作学生个人博客,网页制作论坛(学生个人网页制作代码)
- ildasm ilasm
- VMware | Workstation中如何进入恢复模式(Recovery)?
- 【友盟】 微博分享缺少C8998文件
- 将链接转成base64格式生成二维码和把页面生成图片
- 闭包:让外部函数能访问函数内的变量,让局部变量长期贮存在内存中
- 曝光程序员的桌面!有点心酸 |每日趣闻
热门文章
- AUC(Area under curve 即Roc曲线下面积)总结
- webpack配置局域网访问路径
- 2021 年河南省中等职业教育技能大赛“网络安全”项目比赛任务书解析教程
- SpringCloud+Dubbo3 = 王炸 !
- php 原生 excel,关于原生php实现excel文件读写的方法
- greenplum安装(单机环境)
- ASW3642 pin√pin替代TS3DV642方案,可使用原小板只需简单调整外围|ASW3642 HDMI二切一双向切换器方案
- 阿里云 OSS监控上传进度
- CDN公共库、前端开发常用插件一览表(VendorPluginLib)
- 易麦宝亚马逊软件怎么样? 先来了解一下。