上一篇我们介绍了使用fpga驱动vga显示一个简单的彩色条纹。这一篇我们看看文字如何显示输出。
文字显示原理。文字的显示,其实也是把文字当做图片,一个像素点一个像素点的来输出。如下图:

如果对正方形内字符的每一个像素点进行标记,哪些点应该显示白色,哪些点应该显示黑色,那么就可以在vga输出的时候,输出对应像素点的颜色值,也就能输出这个文字。
如何得到这个字的像素点颜色值呢?这儿我们可以使用一些工具,比如“PCtoLCD2002”这个软件。比如上面这个“字”,软件的字模格式设置如下:

可以得到以下字模:
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x07,0x00,0x00
0x00,0x03,0x80,0x00,0x00,0x01,0xC0,0x00,0x1F,0xFF,0xFF,0xF8,0x1F,0xFF,0xFF,0xF8
0x1C,0x00,0x00,0x18,0x1C,0x00,0x00,0x18,0x1C,0x00,0x00,0x18,0x01,0xFF,0xFF,0x80
0x01,0xFF,0xFF,0x80,0x01,0xFF,0xFF,0x80,0x00,0x00,0x1E,0x00,0x00,0x00,0x3C,0x00
0x00,0x00,0xF0,0x00,0x00,0x01,0xE0,0x00,0x00,0x01,0xC0,0x00,0x3F,0xFF,0xFF,0xFC
0x3F,0xFF,0xFF,0xFC,0x3F,0xFF,0xFF,0xFC,0x00,0x01,0xC0,0x00,0x00,0x01,0xC0,0x00
0x00,0x01,0xC0,0x00,0x00,0x01,0xC0,0x00,0x00,0x01,0xC0,0x00,0x00,0x01,0xC0,0x00
0x00,0x1B,0xC0,0x00,0x00,0x1F,0x80,0x00,0x00,0x0F,0x80,0x00,0x00,0x00,0x00,0x00/*”字”,0*/
这是32X32的大小,点阵显得有点多。只要把这些值存到rom之中,当vga扫描到需要输出的位置时,从rom中取出对应的值给RGB输出即可。(如果要输出的字不多且固定,也可以把字模直接写在代码里)
参考代码入下:
module VGA_character(
input wire sysclk, //系统时钟,也就是板子的时钟
input wire rst,
output reg [3:0] R, //输出的颜色值
output reg [3:0] G, //输出的颜色值
output reg [3:0] B, //输出的颜色值
output wire HS, //水平同步信号
output wire VS //垂直同步信号
);
//显示分辨率 640*480@60Hz
//时钟25.175M
localparam HPOLA = 0; //水平同步信号极性
localparam VPOLA = 0; //垂直同步信号极性
localparam HTOTAL = 800;//水平总像素数
localparam HSYNCP = 96; //水平同步信号像素数
localparam HBACKP = 40; //扫描后沿像素数
localparam LBorder = 8; //左边框
localparam HDISP = 640;//显示区域
localparam RBorder = 8; //右边框
localparam HFRONTP = 8; //扫描前沿像素数
localparam VTOTAL = 525;//垂直总像素数
localparam VSYNCP = 2; //垂直同步信号
localparam VBACKP = 25; //扫描后沿像素数
localparam TBorder = 8; //顶边框
localparam VDISP = 480;//显示区域
localparam BBorder = 8; //底边框
localparam VFRONTP = 2; //扫描前沿像素数
wire vgaclk;
wire locked;
wire vgarst;
assign vgarst = ~locked; //locked为高表示时钟正常,此时不复位
//使用锁相环来输出指定时钟
pll pll_inst (
.areset ( rst ),
.inclk0 ( sysclk ),
.c0 ( vgaclk ),
.locked ( locked )
);
//*****************************************************
//“字”字模
reg [31:0] character[0:31]; //存储字模
reg [9:0] location_x = 432; //显示位置
reg [9:0] location_y = 243; //显示位置
initial begin
character[00] = 32'h00000000;
character[01] = 32'h00000000;
character[02] = 32'h00020000;
character[03] = 32'h00070000;
character[04] = 32'h00038000;
character[05] = 32'h0001C000;
character[06] = 32'h1FFFFFF8;
character[07] = 32'h1FFFFFF8;
character[08] = 32'h1C000018;
character[09] = 32'h1C000018;
character[10] = 32'h1C000018;
character[11] = 32'h01FFFF80;
character[12] = 32'h01FFFF80;
character[13] = 32'h01FFFF80;
character[14] = 32'h00001E00;
character[15] = 32'h00003C00;
character[16] = 32'h0000F000;
character[17] = 32'h0001E000;
character[18] = 32'h0001C000;
character[19] = 32'h3FFFFFFC;
character[20] = 32'h3FFFFFFC;
character[21] = 32'h3FFFFFFC;
character[22] = 32'h0001C000;
character[23] = 32'h0001C000;
character[24] = 32'h0001C000;
character[25] = 32'h0001C000;
character[26] = 32'h0001C000;
character[27] = 32'h0001C000;
character[28] = 32'h001BC000;
character[29] = 32'h001F8000;
character[30] = 32'h000F8000;
character[31] = 32'h00000000;
end
//*****************************************************
reg [9:0] hcnt; //行计数
reg [9:0] vcnt; //场计数
//行计数
always@(posedge vgaclk or posedge vgarst) begin
if(vgarst)
hcnt <= 0;
else
if(hcnt == HTOTAL - 1)
hcnt <= 0;
else
hcnt <= hcnt + 1;
end
//场计数
always@(posedge vgaclk or posedge vgarst) begin
if(vgarst)
vcnt <= 0;
else
if((hcnt == HTOTAL - 1) && (vcnt == VTOTAL - 1))
vcnt <= 0;
else if(hcnt == HTOTAL - 1)
vcnt <= vcnt + 1;
else
vcnt <= vcnt;
end
//行同步信号输出
assign HS = (hcnt <= HSYNCP - 1) ? HPOLA : ~HPOLA;
//场同步信号输出
assign VS = (vcnt <= VSYNCP - 1) ? VPOLA : ~VPOLA;
//显示区域的判断
wire h_disp;
assign h_disp = (hcnt > (HSYNCP + HBACKP + LBorder - 1) &&
hcnt < (HSYNCP + HBACKP + LBorder + HDISP - 1)) ? 1'b1 : 1'b0;
wire v_disp;
assign v_disp = (vcnt > (VSYNCP + VBACKP + TBorder - 1) &&
vcnt < (VSYNCP + VBACKP + TBorder + VDISP- 1)) ? 1'b1 : 1'b0;
wire disp;
assign disp = h_disp && v_disp;
always@(posedge vgaclk or posedge vgarst) begin
if(vgarst)
begin
R <= 4'b0000;
G <= 4'b0000;
B <= 4'b0000;
end
else
if(disp)
begin
if((hcnt>=location_x && hcnt<location_x+32) && (vcnt >= location_y && vcnt<location_y+32))
if(character[vcnt-location_y][hcnt-location_x])
begin
R <= 4'b1111;
G <= 4'b1111;
B <= 4'b1111;
end
else
begin
R <= 4'b0000;
G <= 4'b0000;
B <= 4'b0000;
end
else
begin
R <= 4'b0000;
G <= 4'b0000;
B <= 4'b0000;
end
end
else
begin
R <= 4'b0000;
G <= 4'b0000;
B <= 4'b0000;
end
end
endmodule
效果如下:
