【【RGB LCD字符 和图片的显示实验】】
RGB LCD字符 和图片的显示实验
本次实验参考自《正点原子 领航者ZYNQ 之 FPGA 开发指南》 RGB LCD字符和图片显示实验
本次实验采用的板子是 正点原子 ZYNQ 7020
本次实验 的大体代码可以参照 上次实验的代码
主要是为了 学习 字体取模的操作 然后将其 显示在屏幕上
实验任务
通过领航者开发板上的 RGB TFT-LCD 接口,在正点原子的 RGB LCD 液晶屏的左上角位置从上到下依次显示图片以及 4 个汉字“正点原子”。其中每个汉字的大小为 3232,图片的大小为100100。
说实话 我觉得 用 纯FPGA 去做 会显得很吃力 很复杂 但是主要学一个思路
倒不如用MCU 搭配 控制 寄存器来的方便
这和我们之前玩 51单片机的方法类似 其实是一个道理 只是各种实现的层次不同
51单片机自带了 点阵还有核心的链接 FPGA 都没有 只有输出的几个管脚 这反而 凸显了 FPGA无与伦比的强大 特性
由于本章实验与“RGB LCD 彩条显示实验”基本一致,所以我们可以在“RGB LCD 彩条显示实验”的系统框图稍作修改。那么需要修改什么地方呢?只需要修、改 LCD 显示模块就可以实现在 LCD 液晶屏上显示字符和图片的功能。另外,由于图片的像素数据较多,因此我们采用在 LCD 显示模块中例化了一个 ROM,用来存储图片数据。
我们这边记录一下 图片的显示原理
其实图片和字模的实现原理差不多 图片是通过 COE文件生成的
字模我们在这里通过一个PCtoLCD2002这个软件实现
因为 对于 一个图片来说 一些点阵真的是 太大了 用点阵并不能很好的实现
所以我们需要的是通过 COE 将其转化成信息
在FPGA内部 我们可以通过内部资源构建 ROM 只读文件 将其存进去 方便使用
我们直接点击下面的生成字模 之后 会发现 其实 生成的是多个汉字的 并不方便我们去操作
我们最好是将其另存为一下
先保存BMP 然后再打开 就会把这几个字 变成一个字模了
LCD 显示模块中的 ROM 是通过例化 IP 核来实现的只读存储器,它使用 FPGA 的片上存储资源,即BRAM。由于 FPGA 的片上存储资源有限,所以 ROM 中存储的图片大小也受到限制,本次实验采用的图片分辨率为 100100。领航者 ZYNQ 开发板上的 RGB TFT-LCD 接口采用 RGB888 数据格式,即每个像素点的颜色用 24bit 的数据来表示,因此大小为 100100*24bit = 240000bit=234.375Kbit≈0.23Mbit。XC7Z020 芯片的 BRAM 存储容量为 4.9Mbit
系统框图 如下所示
对于 本节实验 我们的 字模可以直接放进 verilog代码中 而 COE 文件放入 ROM中进行存储
ROM 作为只读存储器,在调用 IP 核时需要指定初始化文件,在这里就是写入存储器中的图片数据,各种格式的图片(bmp、jpg 等)在 Xilinx 开发软件中都是以 COE 文件或者 HEX 文件的形式导入到 ROM 中的。COE 文件格式较为简单,因此本次实验选取 COE 的文件格式。COE 是一种 Xilinx 工具能识别的文件格式,在文件的开头定义了存储数据的进制和初始化的数据,存储的数据最后一行以“;”结束,其余的以“,”结束。例如一个存储数据为 16 进制深度为 5 的 COE 文件内容如下图所示:
第一行定义存储的数据为 16 进制,第二行初始化的数值向量,分别对应不同存储单元的数据,存储地址从 0 开始,依次累加,最后一个存储地址的数据以“;”结束。
我们拼成一个大字模 这里就会显示 32*5 与 32 具体长宽怎么显示的 我还没研究
我们来叙述一些之前了解到的设计的具体含义
pixel_xpos 的 初始值为1
assign pixel_xpos = data_reg ? (h_cnt - ( h_sync + h_back - 1) 坐标 从 1 开始
同理 其实它也是想把值 限定在 pixel_ypos 从1开始取
它其实就是想把 pixel_xpos的值 限定在 从1开始 计数
h_cnt 其实从主端口开始 就是一直变化的 不断移动
需要注意的是 它移动的显示的范围永远是这么大 你管它是叫从0 开始 从1 开始 我从外部进来扫描的这个过程中
其实整个大小就是这么大 未曾改变
这样来说的话 我们 x_cnt这个计数值又重新归为从0 开始取了
就相当于 指定了第一个像素点的位置是 (0,0)
好的 看完了 正点原子的 叙述 我们现在下面开始自己对于此处代码段的写作
clk_div.v
module clk_div(
input clk, //50Mhz
input rst_n,
input [15:0] lcd_id,
output reg lcd_pclk
);
reg clk_25m;
reg clk_12_5m;
reg div_4_cnt;
//时钟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
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
lcd_display.v
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
localparam PIC_X_START = 11'd1; //图片起始点横坐标
localparam PIC_Y_START = 11'd1; //图片起始点纵坐标
localparam PIC_WIDTH = 11'd100; //图片宽度
localparam PIC_HEIGHT = 11'd100; //图片高度
localparam CHAR_X_START= 11'd1; //字符起始点横坐标
localparam CHAR_Y_START= 11'd110; //字符起始点纵坐标
localparam CHAR_WIDTH = 11'd128; //字符宽度,4个字符:32*4
localparam CHAR_HEIGHT = 11'd32; //字符高度
localparam BACK_COLOR = 24'hE0FFFF; //背景色,浅蓝色
localparam CHAR_COLOR = 24'hff0000; //字符颜色,红色
//reg define
reg [127:0] char[31:0]; //字符数组
reg [13: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 ] <= 128'h00000000000000000000000000000000;
char[1 ] <= 128'h00000000000000000000000000000000;
char[2 ] <= 128'h00000000000100000000002000000000;
char[3 ] <= 128'h000000100001800002000070000000C0;
char[4 ] <= 128'h000000380001800003FFFFF803FFFFE0;
char[5 ] <= 128'h07FFFFFC0001800003006000000001E0;
char[6 ] <= 128'h0000C000000180600300600000000300;
char[7 ] <= 128'h0000C0000001FFF00300C00000000600;
char[8 ] <= 128'h0000C000000180000310804000001800;
char[9 ] <= 128'h0000C00000018000031FFFE000003000;
char[10] <= 128'h0000C00000018000031800400001C000;
char[11] <= 128'h0000C00000018000031800400001C000;
char[12] <= 128'h00C0C000018181800318004000018000;
char[13] <= 128'h00C0C00001FFFFC0031FFFC000018010;
char[14] <= 128'h00C0C060018001800318004000018038;
char[15] <= 128'h00C0FFF001800180031800403FFFFFFC;
char[16] <= 128'h00C0C000018001800318004000018000;
char[17] <= 128'h00C0C000018001800218004000018000;
char[18] <= 128'h00C0C00001800180021FFFC000018000;
char[19] <= 128'h00C0C000018001800210304000018000;
char[20] <= 128'h00C0C00001FFFF800200300000018000;
char[21] <= 128'h00C0C000018001800606300000018000;
char[22] <= 128'h00C0C000018001000607370000018000;
char[23] <= 128'h00C0C00000000000060E31C000018000;
char[24] <= 128'h00C0C000001000400418307000018000;
char[25] <= 128'h00C0C000020830600430303800018000;
char[26] <= 128'h00C0C010020C18300860301800018000;
char[27] <= 128'h00C0C038060E18180883700800018000;
char[28] <= 128'h3FFFFFFC0C0618181100F008003F8000;
char[29] <= 128'h000000001C0408182000600000070000;
char[30] <= 128'h00000000000000000000000000020000;
char[31] <= 128'h00000000000000000000000000000000;
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
lcd_driver.v
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;
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
lcd_rgb_char.v
module lcd_rgb_char(
input sys_clk ,
input sys_rst_n ,
//RGB LCD接口
output lcd_hs , //LCD 行同步信号
output lcd_vs , //LCD 场同步信号
output lcd_de , //LCD 数据输入使能
inout [23:0] lcd_rgb , //LCD RGB565颜色数据
output lcd_bl , //LCD 背光控制信号
output lcd_rst, //LCD 复位
output lcd_clk //LCD 采样时钟
);
//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
rd_id.v
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
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!