目录
本例程大部分与VGA显示驱动内容相同,只是显示部分改变了,故此主要讲显示字符的方法。如有对VGA显示驱动不了解的朋友,建议先看这篇 http://t.csdn.cn/QqQzi 。
由之前讲VGA显示彩条的原理可知显示的本质就是点阵,将有用信息与背景色区分就可以显示信息,例如军训时很火的方阵以及平时见到的广告牌。
实验目标:在 VGA 显示器中心位置显示金色“天天向上”四个字,字符外的背景颜色为黑色。每个汉字大小为 56*56, 字模点阵为 64*64, VGA 显示模式为 640*480@60。
1.实操
1.1 字符取模
字符取模的基本原理
一般使用 0、 1 的组合来描述点阵,点阵中的每一个数据项表示单个像素点,我们使用单比特来表示,字符显示部分的数据项赋值为 1,非字符显示部分的数据项赋值为 0。这种赋值方式不包含颜色信息,只是区分点阵背景和字符信息。字符点阵示例,具体见下图。
字符取模操作流程
1. 生成一个整体字模
打开字符取模软件“PCtoLCD2002”,设置相关参数,将点阵大小设置为 64*64,字宽*字高设置为 56*56,字体随意;在下方文字输入框中输入要显示字符“天天向上”;注意,此处先不要进行字模生成,因为此处生成字模会得到四个字符各自对应的字模,不方便后续代码编写。
将生成的字符点阵保存为 BMP 图片格式,保存为 BMP格式的目的就是为了将四个单独字符合成一个整体。
再返回读取保存的 BMP 图片,四个字符已合为一个整体。
2. 设置字模输出的相关参数,生成字模、保存字模
将模式调为图形模式后,在点击 “选项” 按照下图所示, 设置字模输出的相关参数。
生成字模、保存字模
字模保存完毕,字模点阵大小为 256*64。
注意(1)进行下一次的字模生成,要将模式调回 字符模式 后再进行相关参数设置,否则无法修改参数设置,(2)汉字占两个字节,数字、字母和特殊符号占两个字节,在配置点阵大小时需注意。
1.2 顶层模块
顶层模块设计如下图。
以上模块除图像数据生成模块,其他模块在前面发布的VGA 显示器驱动设计与验证文章中已经详细说明,故不重复。
1.3 图像数据生成模块
1.3.1 模块框图
图像数据生成模块,模块功能是以 VGA 时序控制模块传入的图像有效显示区域像素点坐标(pix_x,pix_y)为约束条件, 产生 VGA 图像像素点色彩信息 pix_data 并回传给 VGA 时序控制模块。在字符显示区域 pi_data 赋值为金色,其他区域均为黑色。模块框图,具体见下图。
图像数据生成模块包含 4 路输入、 1 路输出,共 5 路信号,输入输出信号简介,具体见下表。
1.3.2 波形图绘制
第一部分:输入信号
本模块的输入信号包括四路,时钟信号、复位信号和 VGA 驱动控制模块传入的有效显示区域的坐标信号 pix_x、 pix_y。时钟信号和复位信号无需多说,对于坐标信号 pix_x、pix_y,在之前的文章有详细讲解,在此不再过多叙述。
第二部分:字符点阵显示区域坐标信号的设计与实现
首先确定字符有效显示区域,区域大小与字符点阵大小相同,显示区域的像素点与字模点阵中数据项对应,当字模点阵中的数据项数值为“1”时,赋值字符颜色给对应像素点;当字模点阵中的数据项数值为“0”时,赋值点阵背景颜色给对应像素点。所以为了确定字符点阵显示区域256*64
,声明两个变量 char_x、 char_y,两变量组成字符点阵显示区域坐标,在字符点阵有效显示区域内, char_x 信号 0-255 循环计数, char_y信号 0-63 循环计数 ,根据坐标(char_x,char_y)寻找字符点阵对应的数据项,根据数据项的数值,赋予对应坐标像素点颜色信息。 char_x、 char_y 信号波形具体见下图。
第三部分: 输出图像数据信号的波形设计与实现
设计本模块的目的是生成 VGA 图像像素点色彩信息回传给 VGA 时序控制模块,我们声明像素点色彩信息 pix_data 信号。在字符点阵显示区域内、字符点阵数据项数值为“1”时, pix_data 根据为字符颜色;其他区域均赋值为背景色。
1.3.3 代码编写
`timescale 1ns/1ns
module vga_pic
(
input wire vga_clk ,
input wire sys_rst_n ,
input wire [9:0] pix_x , //输入有效显示区域像素点X轴坐标
input wire [9:0] pix_y , //输入有效显示区域像素点Y轴坐标
output reg [15:0] pix_data //输出像素点色彩信息
);
parameter CHAR_B_H= 10'd192 , //字符开始X轴坐标
CHAR_B_V= 10'd208 ; //字符开始Y轴坐标
parameter CHAR_W = 10'd256 , //字符宽度
CHAR_H = 10'd64 ; //字符高度
parameter BLACK = 16'h0000, //黑色
WHITE = 16'hFFFF, //白色
GOLDEN = 16'hFEC0; //金色
wire [9:0] char_x ; //字符显示X轴坐标
wire [9:0] char_y ; //字符显示Y轴坐标
//reg define
reg [255:0] char [63:0] ; //位宽 与 列高
//字符显示坐标,组合逻辑0-255
assign char_x = (((pix_x >= CHAR_B_H) && (pix_x < (CHAR_B_H + CHAR_W))) //pix_x < (CHAR_B_H + CHAR_W)也可以写成 pix_x <= (CHAR_B_H + CHAR_W -1'b1)
&& ((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;
//char:“天天向上”字符数据(粘贴字模提取其中生成的数据)
always@(posedge vga_clk)
begin
char[0] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[1] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[2] <= 256'h0000000000000000000000000000000000000080000000000000000000000000;
char[3] <= 256'h00000000000000000000000000000000000001E0000000000000008000000000;
char[4] <= 256'h00000000003000000000000000200000000001F000000000000000E000000000;
char[5] <= 256'h00000000007800000000000000300000000001E000000000000000FC00000000;
char[6] <= 256'h0000000000FC00000000000000780000000001C000000000000000F000000000;
char[7] <= 256'h00FFFFFFFFFE00000000000000FC00000000038000000000000000E000000000;
char[8] <= 256'h007FFFFFFFFF0000007FFFFFFFFE00000000038000000000000000E000000000;
char[9] <= 256'h003C00F80000000000200078000000000000030000000000000000E000000000;
char[10] <= 256'h000000F80000000000000078000000000000020000020000000000E000000000;
char[11] <= 256'h000000F80000000000000078000000000080060000030000000000E000000000;
char[12] <= 256'h000000F800000000000000700000000000E0040000078000000000E000000000;
char[13] <= 256'h000000F800000000000000700000000000FFFFFFFFFFC000000000E000000000;
char[14] <= 256'h000000F800000000000000700000000000E0000000078000000000E000000000;
char[15] <= 256'h000000F800000000000000700000000000E0000000070000000000E000000000;
char[16] <= 256'h000000F800000000000000700000000000E0000000070000000000E000000000;
char[17] <= 256'h000000F800000000000000700000000000E0000000070000000000E000000000;
char[18] <= 256'h000000F800000000000000700000000000E0000000070000000000E000100000;
char[19] <= 256'h000000F800000000000000700000000000E0000000070000000000E000380000;
char[20] <= 256'h000000F800070000000000700002000000E0000000070000000000E0007C0000;
char[21] <= 256'h000000F8000F8000000000700007000000E0000000070000000000E000FE0000;
char[22] <= 256'h000000F8001FC00000000070000F800000E0300010070000000000FFFFFF0000;
char[23] <= 256'h1FFFFFFFFFFFE00000000070001FC00000E038003C070000000000E000000000;
char[24] <= 256'h1FFFFFFFFFFFF0000FFFFFFFFFFFE00000E01FFFFC070000000000E000000000;
char[25] <= 256'h0F8001F700000000040000E20000000000E01C0038070000000000E000000000;
char[26] <= 256'h000001F700000000000000E20000000000E01C0038070000000000E000000000;
char[27] <= 256'h000001F700000000000000E20000000000E01C0038070000000000E000000000;
char[28] <= 256'h000001F380000000000001E30000000000E01C0038070000000000E000000000;
char[29] <= 256'h000003E380000000000001E10000000000E01C0038070000000000E000000000;
char[30] <= 256'h000003E380000000000001C18000000000E01C0038070000000000E000000000;
char[31] <= 256'h000003E1C0000000000001C18000000000E01C0038070000000000E000000000;
char[32] <= 256'h000007C1C0000000000003C0C000000000E01C0038070000000000E000000000;
char[33] <= 256'h000007C1E000000000000380C000000000E01C0038070000000000E000000000;
char[34] <= 256'h00000780E0000000000007806000000000E01C0038070000000000E000000000;
char[35] <= 256'h00000F80F0000000000007006000000000E01C0038070000000000E000000000;
char[36] <= 256'h00000F807800000000000F003000000000E01FFFF8070000000000E000000000;
char[37] <= 256'h00001F007800000000000E003800000000E01C0038070000000000E000000000;
char[38] <= 256'h00003E003C00000000001E001800000000E03C0038070000000000E000000000;
char[39] <= 256'h00003E003E00000000001C001C00000000E03C0038070000000000E000000000;
char[40] <= 256'h00007C001F000000000038000E00000000E0380000070000000000E000000000;
char[41] <= 256'h0000F8000F800000000070000F00000000E0200000070000000000E000000000;
char[42] <= 256'h0001F0000FC000000000E00007C0000000E0000000070000000000E000000000;
char[43] <= 256'h0003E00007F000000001E00003E0000000E0000000070000000000E000000000;
char[44] <= 256'h0007C00003F800000003800001F0000000E0000000070000000000E000008000;
char[45] <= 256'h000F800001FE00000007000000FC000000E0000000070000000000E00001C000;
char[46] <= 256'h001F000000FF8000000E0000007F000000E0000000070000000000E00003E000;
char[47] <= 256'h003E0000007FF000001C0000003FE00000E000000FFF0000000000E00007F000;
char[48] <= 256'h00780000003FFC0000300000001FF80000E0000003FF00001FFFFFFFFFFFF800;
char[49] <= 256'h01F00000001FF80000E00000000FE00000E00000007F00000800000000000000;
char[50] <= 256'h07C000000007C000018000000003C00000E00000003E00000000000000000000;
char[51] <= 256'h0F00000000038000060000000001800000E00000001C00000000000000000000;
char[52] <= 256'h1C00000000000000180000000000000000800000000000000000000000000000;
char[53] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[54] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[55] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[56] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[57] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[58] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[59] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[60] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[61] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[62] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char[63] <= 256'h0000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000 00000;
end
//pix_data:输出像素点色彩信息,根据当前像素点坐标指定当前像素点颜色数据
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 ))
&& (pix_x < (CHAR_B_H + CHAR_W ))) //pix_x提前打一拍 【191-446】
&& ((pix_y >= CHAR_B_V) && (pix_y < (CHAR_B_V + CHAR_H))))
&& (char[char_y][10'd255 - char_x] == 1'b1)) //二维数组,当像素点为1时给金色
pix_data <= GOLDEN;
else
pix_data <= BLACK;
endmodule
代码重难点积累:
(1)复制字模时,以notepad++打开 .txt 文件,复制格式不会出错。
(2)2char[char_y][10'd255 - char_x] == 1'b1 使用二位数组定位要显示的像素点。
1.3.4 仿真验证
`timescale 1ns/1ns
module tb_vga_colorbar();
wire hsync ;
wire [15:0] rgb ;
wire vsync ;
//reg define
reg sys_clk ;
reg sys_rst_n ;
initial
begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
#200
sys_rst_n <= 1'b1;
end
//sys_clk:产生时钟
always #10 sys_clk = ~sys_clk ;
vga_colorbar vga_colorbar_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.hsync (hsync ),
.vsync (vsync ),
.rgb (rgb )
);
endmodule
2.总结
设计思想在于显示有效区域是传输数据。
说明:
本人使用的是野火家Xilinx Spartan6系列开发板及配套教程主要用于自我学习,以上内容如有疑惑或错误欢迎评论区指出,或者移步B站观看野火家视频教程。
开发软件:ise14.7 仿真:modelsim 10.5
如需上述资料私信或留下邮箱。