第二十章 VGA字符显示实验
我们在VGA彩条显示实验和VGA方块移动实验中分别在显示器上显示出了静态和动态的图案。然而彩条和方块都是一些非常简单的图案,本章我们将通过在屏幕上显示汉字,来给大家演示如何使用VGA接口显示字符。
本章包括以下几个部分:
1
1.1 VGA简介
1.2 实验任务
1.3 硬件设计
1.4 程序设计
1.5 下载验证
1.1 VGA简介我们在“VGA彩条显示实验”中对VGA视频传输标准作了详细的介绍,包括VGA接口定义、行场同步时序、以及显示分辨率等。如果大家对这部分内容不是很熟悉的话,请参考“VGA彩条显示实验”中的VGA简介部分。
1.2 实验任务本章的实验任务是使用开拓者开发板上的VGA接口在显示器的屏幕中心位置显示四个汉字“正点原子”。显示分辨率为640*480,刷新速率为60hz,每个汉字的大小为16*16。
1.3 硬件设计VGA接口部分的硬件设计原理及本实验中各端口信号的管脚分配与“VGA彩条显示实验”完全相同,请参考“VGA彩条显示实验”中的硬件设计部分。
1.4 程序设计图20.4.1是根据本章实验任务画出的系统框图。其中,时钟分频模块负责产生像素时钟,VGA驱动模块产生行场同步信号及像素点的纵横坐标,VGA显示模块输出图像数据。
图 20.4.1 VGA方块移动实验系统框图
我们在屏幕上显示彩条和方块时,只需要将屏幕上不同的区域分别使用不同的颜色填充即可。然而在显示字符或其他复杂图案时,同一个区域内不同位置的像素点颜色也可能不同,因此我们需要在VGA显示模块中指定字符显示区域中各个像素点的颜色值。
字符(包括汉字、字母和符号等)的本质都是点阵,在VGA屏幕上体现为字符显示区域内像素点的集合。字符的大小决定了字符显示区域内像素点的数目,而字符的样式(字体、颜色等)则决定了各像素点的颜色值。因此,在显示字符之前,我们需要先指定字符的大小、样式,然后获取该字符的点阵,这个过程我们称之为“提取字模”,或简称“取模”。
我们一般使用0和1的组合来描述字符的点阵排列:点阵中每个像素点用一位(1 bit)数据来表示,其中用于表征字符的像素点用数字1来表示,其他的像素点作为背景用数字0来表示,如图 20.4.2所示。采用这种方式描述的字符是不含有颜色特征的,只能区分点阵中的字符和背景。
图 20.4.2 汉字“正”及其点阵描述
字模的提取可通过字符取模软件来实现,在这里我们使用取模软件“PCtoLCD2002”来获取汉字“正点原子”的字模。首先在开发板所随附的资料中“6_软件资料/1_软件/PCtoLCD2002完美版”目录下找到“PCtoLCD2002”并双击打开。
图 20.4.3 取模软件PCtoLCD2002
如上图所示,在取模软件中设置字体为“宋体”,字宽和字高均为“16”,然后在下方文本框中输入汉字“正点原子”。由于PCtoLCD2002会给每个字符生成一个独立的字模,如果此时点击文本框右侧的“生成字模”按钮,我们将会得到四个16*16的字模。然而为了方便在VGA上显示,我们将四个汉字看作一个整体,从而获得一个字宽为64,字高为16的“大字模”。为了达到这个目的,我们首先将图 20.4.3中四个汉字的点阵保存为.BMP格式的图片。在菜单栏中点击“文件”并选择“另存为”,在保存界面中指定文件存储路径,并选择保存类型为“BMP图像文件”,然后输入文件名“正点原子_bmp”,最后点击“保存”。
图 20.4.4 BMP格式图片保存界面
我们在“画图”中打开刚刚保存的BMP格式的图片如下所示:
图 20.4.5 保存的BMP格式图片
接下来我们将取模软件PCtoLCD2002切换至图形模式,在菜单栏中点击“模式”,然后选择“图形模式”。
图 20.4.6 切换显示模式
然后在菜单栏中点击“文件”并选择“打开”,指定图 20.4.4中存放BMP格式图片的路径并打开图片“正点原子_bmp”,图片打开后如下所示。
图 20.4.7 PCtoLCD2002图形模式
请大家注意比较图 20.4.7与图 20.4.3的差异,在上图中,四个汉字“正点原子”被看作一个整体,而不再是四个独立的字符。实际上,这四个汉字也确实是作为一个整体以BMP图片的形式导入到取模软件中的。
在生成字模之前,我们需要先设置字模的格式。在菜单栏中点击“选项”,并在弹出的配置界面中按照下图进行配置,配置完成后点击确定。
图 20.4.8 字模格式配置界面
在配置界面中,当鼠标悬浮在各配置选项上时,软件会自动提示当前配置的含义。需要注意的是图 20.4.8左下角“每行显示数据”是以字节(Byte)为单位的,而一个字节的数据为8个bit,即可以表示一行点阵中的8个像素点。由于图 20.4.7中的点阵每行为64个像素点,所以需要8个Byte的数据来表示一行,因此将“每行显示数据—点阵”处设置为8。
配置字模选项完成后,点击“生成字模”,即可得到汉字“正点原子”所对应的点阵数据,如下图所示:
图 20.4.9 生成字模
最后点击保存字模,可将生成的点阵数据保存在txt格式的文本文档中,如图 20.4.10所示。数据以十六进制显示,每行有8个Byte,对应每行四个汉字共64个像素点;共有16行,对应每个汉字的高度为16。
图 20.4.10 “正点原子”字模
到这里提取字模的过程已经完成了,接下来我们需要在VGA显示模块中将获取的点阵数据映射到屏幕中心16*64个的像素点的字符显示区域,从而实现字符的显示。
程序中各模块端口及信号连接如图 20.4.11所示:
图 20.4.11 顶层模块原理图
图20.4.11中的顶层模块(vga_blockmove)、时钟分频模块(vga_pll)以及VGA驱动模块(vga_driver)均与“VGA彩条显示实验”完全相同,只对VGA显示模块(vga_display)作了修改。因此,这里我们重点讲解VGA显示模块,其他部分大家可以参考“VGA彩条显示实验”。
VGA显示模块的代码如下:
1 modulevga_display(
2 input vga_clk, //VGA驱动时钟
3 input sys_rst_n, //复位信号
4
5 input [ 9:0]pixel_xpos, //像素点横坐标
6 input [ 9:0]pixel_ypos, //像素点纵坐标
7 outputreg [15:0]pixel_data //像素点数据,
8 );
9
10 //parameter define
11 parameter H_DISP = 10'd640; //分辨率——行
12 parameter V_DISP = 10'd480; //分辨率——列
13
14 localparam POS_X = 10'd288; //字符区域起始点横坐标
15 localparam POS_Y = 10'd232; //字符区域起始点纵坐标
16 localparam WIDTH = 10'd64; //字符区域宽度
17 localparam HEIGHT =10'd16; //字符区域高度
18 localparam RED = 16'b11111_000000_00000; //字符颜色
19 localparam BLUE = 16'b00000_000000_11111; //字符区域背景色
20 localparam BLACK = 16'b00000_000000_00000; //屏幕背景色
21
22 //reg define
23 reg [63:0] char[15:0]; //二维字符数组
24
25 //wire define
26 wire [ 9:0] x_cnt;
27 wire [ 9:0] y_cnt;
28
29 //*****************************************************
30 //** main code
31 //*****************************************************
32 assign x_cnt =pixel_xpos - POS_X; //像素点相对于字符区域起始点水平坐标
33 assign y_cnt =pixel_ypos - POS_Y; //像素点相对于字符区域起始点竖直坐标
34
35 //给字符数组赋值,显示汉字“正点原子”,汉字大小为16*16
36 always @(posedge vga_clk)begin
37 char[0] <= 64'h0000020000000000;
38 char[1] <= 64'h7FFC02003FFE7FF8;
39 char[2] <= 64'h0100020020800010;
40 char[3] <= 64'h010003FC21000020;
41 char[4] <= 64'h0100020027F00040;
42 char[5] <= 64'h0100020024100180;
43 char[6] <= 64'h11003FF024100100;
44 char[7] <= 64'h11F8201027F0FFFE;
45 char[8] <= 64'h1100201024100100;
46 char[9] <= 64'h1100201024100100;
47 char[10] <= 64'h11003FF027F00100;
48 char[11] <= 64'h1100000020800100;
49 char[12] <= 64'h1100248824900100;
50 char[13] <= 64'h1100224448880100;
51 char[14] <= 64'hFFFE424452840500;
52 char[15] <= 64'h0000800481000200;
53 end
54
55 //给不同的区域绘制不同的颜色
56 always @(posedge vga_clk ornegedge sys_rst_n) begin
57 if (!sys_rst_n)
58 pixel_data <=BLACK;
59 elsebegin
60 if((pixel_xpos >=POS_X) &&(pixel_xpos <POS_X + WIDTH)
61 &&(pixel_ypos >=POS_Y) &&(pixel_ypos <POS_Y + HEIGHT)) begin
62 if(char[y_cnt][10'd63 - x_cnt])
63 pixel_data <= RED; //绘制字符为红色
64 else
65 pixel_data <= BLUE; //绘制字符区域背景为蓝色
66 end
67 else
68 pixel_data <= BLACK; //绘制屏幕背景为黑色
69 end
70 end
71
72 endmodule
代码中14至20行声明了一系列的变量,方便大家修改字符大小、颜色、以及字符在屏幕上显示的位置等,其中字符显示的位置由字符显示区域左上角的纵横坐标来指定。
程序的第23行定义了一个大小为16*64bit的二维数组char,用于存储对汉字“正点原子”取模得到的点阵数据。二维数组char共16行,每一行有64位数据,在程序的第35至53行完成了对该二维数组的赋值。赋值后数组中每一行数据从高位到低位分别对应点阵中该行从左向右的每一个像素点。
程序第55至70行完成了字符的绘制。当字符显示区域的尺寸(WIDTH、 HEIGHT)已知时,根据左上角的纵横坐标,我们就可以在屏幕上确定字符的显示区域,如60、61行所示。程序第62行根据字符显示区域中像素点相对于起始点(左上角)的距离,将屏幕上字符显示区域内的像素点与字符数组char中的点阵数据一一映射。当点阵数据为1时,将像素点颜色赋值为红色,用来显示字符;当点阵数据为0时,将像素点颜色赋值为蓝色,用来作为字符显示区域的背景。屏幕上除字符显示区域之外的其他区域内的像素点均赋值为黑色。
图20.4.12为VGA显示模块显示汉字“正点原子”第7行时SignalTap抓取的波形图。对照取模得到的点阵数据第7行(11003FF024100100)可以看出,当点阵数据为0时,像素点被赋值为蓝色(001F);当点阵数据为1时,像素点被赋值为红色(F800)。各区域中的像素点能够被赋以正确的颜色值。
图 20.4.12 SignalTap波形图
1.5 下载验证 VGA字符显示实验的工程位于vga_char文件夹中,请大家参考VGA彩条显示实验中的下载验证方法,将vga_char/par/output_files目录下的“vga_char.sof”文件下载至开发板。下载完成后在VGA显示器上观察显示的汉字如图 20.5.1所示,说明VGA字符显示程序下载验证成功。
图 20.5.1 VGA字符显示效果图