VGA显示器字符显示
实验目标
在640 * 480 @60模式下显示汉字,与彩条显示是一样的,点阵大小是64 * 64,字符大小56 * 56
字符取模
平时我们在广告屏、LED显示屏上看到的字符本质都是点阵,点阵看作是纸,点阵中的字符就是笔顺,将点阵和字符分别设置两种颜色,这样的色差就能实现字符的显示,点阵的大小决定着显示区域的大小,也决定着字符的大小和清晰度,一般使用01组合描述点阵
点阵中的每一个数据都表示一个像素点,如果用单比特,那么点阵就不包含色彩信息,只是区别背景和字符信息
取模用PCtoLCD进行,默认生成的字模是分开的
设置一下,就能将四个字符生成一个整体的字模:
-
先BMP格式保存,重新打开bmp文件,可以看到四个字符合成了整体的字符
-
用PCtoLCD中打开bmp文件,就看到四个独立的字符合成了整体
-
打开设置,对字模的格式重新设置,然后确定,重新生成字模
-
txt格式保存字模,此时的字模点阵大小是256*64,
模块设计
- clk_gen
调用PPL锁相环,25MHz时钟生成模块 - vga_pic
图像生成模块,产生要显示的图像数据 - vga_ctrl
vga控制模块,在25MHz工作时钟下,产生横纵坐标信号(pix_x, pix_y),(0, 0)~(639, 479),传送给vga_pic模块,并且生成行场同步信号hsync和sync,再将vga_pic模块传过来的像素点信息pix_data输出到rgb端口
如何将字符显示在一帧图像的中间位置,可以类比坐标信号(pix_x, pix_y)的生成方式,当pix_x扫描到A部分,pix_y扫描到B部分,那么就可以给字符坐标信号(char_x, char_y)进行赋值(0 ,0)~(255, 63),然后根据字符坐标给对应的字符点阵进行像素数据赋值
vga_pic模块以及测试
这个相对于前面的彩条显示,多了一些条件,拿到(pix_x, pix_y)后,先找到256*64大小的点阵显示区域,然后在的点阵范围内,根据字模数据,给对应的像素点赋值像素数据
module vga_pic(
input wire vga_clk,
input wire sys_rst_n,
input wire [ 9: 0] pix_x,
input wire [ 9: 0] pix_y,
output reg [15: 0] pix_data
);
// 定义(char_x, char_y)相对与(pix_x, pix_y)的开始坐标
parameter CHAR_B_H = 10'd192,
CHAR_B_V = 10'd208;
parameter CHAR_W = 10'd256,
CHAR_H = 10'd64;
parameter BLACK = 16'h0000,
GOLDEN = 16'hFEC0;
wire [ 9: 0] char_x;
wire [ 9: 0] char_y;
assign char_x = (((pix_x >= CHAR_B_H) && (pix_x < (CHAR_B_H + CHAR_W)))
&& ((pix_y >= CHAR_B_V) && (pix_y < (CHAR_B_V + CHAR_H))))
? (pix_x - CHAR_B_H) : 10'h3ff;
assign char_y = (((pix_x >= CHAR_B_H) && (pix_x < (CHAR_B_H + CHAR_W)))
&& ((pix_y >= CHAR_B_V) && (pix_y < (CHAR_B_V + CHAR_H))))
? (pix_y - CHAR_B_V) : 10'h3ff;
// 引入字模数据
reg [255:0] char [63:0]; // 256 * 64
always @ (posedge vga_clk)
begin
char[ 0] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[ 1] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
... ...
char[61] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[62] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[63] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
end
/*
判断条件不能直接使用char_x和char_y,因为pix_data是一个时序逻辑,到时候pix_data会滞后插入坐标一个节拍
对pix_x的范围前推一个,代表提前一个节拍
如果对pix_y的范围推前一个,代表超前一行,不可取
*/
always @ (posedge vga_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
pix_data <= BLACK;
else if ((((pix_x >= (CHAR_B_H - 1'b1))
&& (pix_x < (CHAR_B_H + CHAR_W - 1'b1)))
&& ((pix_y >= CHAR_B_V) && (pix_y < (CHAR_B_V + CHAR_H))))
&& (char[char_y][10'd255 - char_x] == 1'b1))
// && (char[char_x][char_y] == 1'b1))
pix_data <= GOLDEN;
else
pix_data <=BLACK;
endmodule
下板总结
第一次下板:妙啊,是个倒像,能用手机前置看
显示图像是倒着的,从每一行的最右边开始显示,而且字的下面几行有些多余的行也显示了
这是因为vga_pic模块里面是否要给pix_data的赋值的组合逻辑判断条件(char[char_x][char_y] == 1’b1),把x和y弄翻了,而且忘了给pix_x < (CHAR_B_H + CHAR_W)这个加括号
彩条显示范围是pix_x、pix_y的(0, 0) ~ (639, 479),现在显示字符的是char_x、char_y的(0, 0) ~ (255, 63)