`
Marshal_R
  • 浏览: 129949 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Verilog实现VGA字符显示

阅读更多

Verilog实现VGA字符显示

 

 实现目标

    在显示器中以640*480的分辨率显示0-9、A-Z、‘:’、‘*’的任意字符,字符大小为7*8的像素规模。

 

 

实现原理

    1、基本的VGA显示

        所有VGA显示差不多都是基于下面这一段Verilog代码的,时钟分频、行同步信号hs、场同步信号vs、rgb颜色值,这些都是必不可少的,还要注意的是对于640*480的分辨率,显示器真正可显示的区域为行计数介于31~510、列计数介于144~783之间(实际上对不同的显示器可能会有几个像素的差异),在这个范围之外都必须把rgb值设置为全0,否则会对显示造成干扰。

 

        下面代码效果为在显示器屏幕中央显示一个绿色矩形方块。

 

// vga_display.v
`timescale 1ns / 1ps

module vga_display(
    input clk,
    input rst,
    output reg [2:0] r,
    output reg [2:0] g,
    output reg [1:0] b,
    output hs,
    output vs
    );

	// 显示器可显示区域
	parameter UP_BOUND = 31;
	parameter DOWN_BOUND = 510;
	parameter LEFT_BOUND = 144;
	parameter RIGHT_BOUND = 783;

	// 屏幕中央的矩形方块
	parameter up_pos = 211;
	parameter down_pos = 330;
	parameter left_pos = 384;
	parameter right_pos = 543;
	
	wire pclk;
	reg [1:0] count;
	reg [9:0] hcount, vcount;
	
	// 获得像素时钟25MHz
	assign pclk = count[1];
	always @ (posedge clk or posedge rst)
	begin
		if (rst)
			count <= 0;
		else
			count <= count+1;
	end
	
	// 列计数与行同步
	assign hs = (hcount < 96) ? 0 : 1;
	always @ (posedge pclk or posedge rst)
	begin
		if (rst)
			hcount <= 0;
		else if (hcount == 799)
			hcount <= 0;
		else
			hcount <= hcount+1;
	end
	
	// 行计数与场同步
	assign vs = (vcount < 2) ? 0 : 1;
	always @ (posedge pclk or posedge rst)
	begin
		if (rst)
			vcount <= 0;
		else if (hcount == 799) begin
			if (vcount == 520)
				vcount <= 0;
			else
				vcount <= vcount+1;
		end
		else
			vcount <= vcount;
	end
	
	// 设置显示信号值
	always @ (posedge pclk or posedge rst)
	begin
		if (rst) begin
			r <= 0;
			g <= 0;
			b <= 0;
		end
		else if (vcount>=UP_BOUND && vcount<=DOWN_BOUND
				&& hcount>=LEFT_BOUND && hcount<=RIGHT_BOUND) begin
			if (vcount>=up_pos && vcount<=down_pos
					&& hcount>=left_pos && hcount<=right_pos) begin
				r <= 3'b000;
				g <= 3'b111;
				b <= 2'b00;
			end
			else begin
				r <= 3'b000;
				g <= 3'b000;
				b <= 2'b00;
			end
		end
		else begin
			r <= 3'b000;
			g <= 3'b000;
			b <= 2'b00;
		end
	end

endmodule
 

    2、基于RAM和字模的VGA显示

        我们都知道电脑有显存,它存储了显示器每个像素应该显示的rgb颜色值,显存不断被刷新,于是可以显示动态的图像。基于此,最简单的想法就是可以在Verilog里面定义一个640*480的8位寄存器二维数组作为VGA显示的显存,然后在reset信号使能的时候对每个数组单元赋值,这样我们就用一个数组存储了一幅静态图像,然后在VGA扫描显示的时候,分别根据寄存器数组的值来设置各个像素的rgb值。

 

        显然,上面的方法是可行的,只不过工程浩大,难以实现!试想,要在屏幕显示一个7*8的字符就要分别设置56个寄存器的值,而且每个寄存器都要根据不同的字符设置不同的值,这是多么可怕的事情!

 

        除此之外,可以考虑通过一个通用的RAM_set模块来一次性设置一个字符对应的寄存器的值。以显示两个字符为例(字符颜色白色,背景黑色),通过Verilog声明一个长度为14的8位寄存器数组reg [7:0] p[13:0],因为两个字符占用2*7*8=14*8个像素,所以p[i][j]=0表示第i+1列第j+1行像素为黑色,反之1为白色。这样的话,就可以分别把p[13:7]、p[6:0]通过RAM_set来设置。RAM_set模块可以根据要显示的不同字符的字模给寄存器赋不同的值。



图1  常见字符字模图

 

 

 

实现代码

    下面的代码实现在显示器屏幕中央显示两个字符"3D"。

 

// vga_char_display.v
`timescale 1ns / 1ps

module vga_char_display(
    input clk,
    input rst,
    output reg [2:0] r,
    output reg [2:0] g,
    output reg [1:0] b,
    output hs,
    output vs
    );

	// 显示器可显示区域
	parameter UP_BOUND = 31;
	parameter DOWN_BOUND = 510;
	parameter LEFT_BOUND = 144;
	parameter RIGHT_BOUND = 783;

	// 屏幕中央两个字符的显示区域
	parameter up_pos = 267;
	parameter down_pos = 274;
	parameter left_pos = 457;
	parameter right_pos = 470;
	
	wire pclk;
	reg [1:0] count;
	reg [9:0] hcount, vcount;
	wire [7:0] p[13:0];

	RAM_set u_ram_1 (
		.clk(clk),
		.rst(rst),
		.data(6'b00_0011),
		.col0(p[0]),
		.col1(p[1]),
		.col2(p[2]),
		.col3(p[3]),
		.col4(p[4]),
		.col5(p[5]),
		.col6(p[6])
	);
	RAM_set u_ram_2 (
		.clk(clk),
		.rst(rst),
		.data(6'b00_1101),
		.col0(p[7]),
		.col1(p[8]),
		.col2(p[9]),
		.col3(p[10]),
		.col4(p[11]),
		.col5(p[12]),
		.col6(p[13])
	);
	
	// 获得像素时钟25MHz
	assign pclk = count[1];
	always @ (posedge clk or posedge rst)
	begin
		if (rst)
			count <= 0;
		else
			count <= count+1;
	end
	
	// 列计数与行同步
	assign hs = (hcount < 96) ? 0 : 1;
	always @ (posedge pclk or posedge rst)
	begin
		if (rst)
			hcount <= 0;
		else if (hcount == 799)
			hcount <= 0;
		else
			hcount <= hcount+1;
	end
	
	// 行计数与场同步
	assign vs = (vcount < 2) ? 0 : 1;
	always @ (posedge pclk or posedge rst)
	begin
		if (rst)
			vcount <= 0;
		else if (hcount == 799) begin
			if (vcount == 520)
				vcount <= 0;
			else
				vcount <= vcount+1;
		end
		else
			vcount <= vcount;
	end
	
	// 设置显示信号值
	always @ (posedge pclk or posedge rst)
	begin
		if (rst) begin
			r <= 0;
			g <= 0;
			b <= 0;
		end
		else if (vcount>=UP_BOUND && vcount<=DOWN_BOUND
				&& hcount>=LEFT_BOUND && hcount<=RIGHT_BOUND) begin
			if (vcount>=up_pos && vcount<=down_pos
					&& hcount>=left_pos && hcount<=right_pos) begin
				if (p[hcount-left_pos][vcount-up_pos]) begin
					r <= 3'b111;
					g <= 3'b111;
					b <= 2'b11;
				end
				else begin
					r <= 3'b000;
					g <= 3'b000;
					b <= 2'b00;
				end
			end
			else begin
				r <= 3'b000;
				g <= 3'b000;
				b <= 2'b00;
			end
		end
		else begin
			r <= 3'b000;
			g <= 3'b000;
			b <= 2'b00;
		end
	end

endmodule

 

 

// RAM_set.v
`timescale 1ns / 1ps

module RAM_set(
	input clk,
	input rst,
	input [5:0] data,
	output reg [7:0] col0,
	output reg [7:0] col1,
	output reg [7:0] col2,
	output reg [7:0] col3,
	output reg [7:0] col4,
	output reg [7:0] col5,
	output reg [7:0] col6
	);

	always @(posedge clk or negedge rst)
		begin
			if (!rst)
				begin
					col0 <= 8'b0000_0000;
					col1 <= 8'b0000_0000;
					col2 <= 8'b0000_0000;
					col3 <= 8'b0000_0000;
					col4 <= 8'b0000_0000;
					col5 <= 8'b0000_0000;
					col6 <= 8'b0000_0000;
				end
			else
				begin
					case (data)
						6'b00_0000: // "0"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0011_1110;
								col2 <= 8'b0101_0001;
								col3 <= 8'b0100_1001;
								col4 <= 8'b0100_0101;
								col5 <= 8'b0011_1110;
								col6 <= 8'b0000_0000;
							end
						6'b00_0001: // "1"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0000_0000;;
								col2 <= 8'b0100_0010;
								col3 <= 8'b0111_1111;
								col4 <= 8'b0100_0000;
								col5 <= 8'b0000_0000;;
								col6 <= 8'b0000_0000;
							end
						6'b00_0010: // "2"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0100_0010;
								col2 <= 8'b0110_0001;
								col3 <= 8'b0101_0001;
								col4 <= 8'b0100_1001;
								col5 <= 8'b0100_0110;
								col6 <= 8'b0000_0000;
							end
						6'b00_0011: // "3"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0010_0010;
								col2 <= 8'b0100_0001;
								col3 <= 8'b0100_1001;
								col4 <= 8'b0100_1001;
								col5 <= 8'b0011_0110;
								col6 <= 8'b0000_0000;
							end
						6'b00_0100: // "4"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0001_1000;
								col2 <= 8'b0001_0100;
								col3 <= 8'b0001_0010;
								col4 <= 8'b0111_1111;
								col5 <= 8'b0001_0000;
								col6 <= 8'b0000_0000;
							end
						6'b00_0101: // "5"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0010_0111;
								col2 <= 8'b0100_0101;
								col3 <= 8'b0100_0101;
								col4 <= 8'b0100_0101;
								col5 <= 8'b0011_1001;
								col6 <= 8'b0000_0000;
							end
						6'b00_0110: // "6"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0011_1110;
								col2 <= 8'b0100_1001;
								col3 <= 8'b0100_1001;
								col4 <= 8'b0100_1001;
								col5 <= 8'b0011_0010;
								col6 <= 8'b0000_0000;
							end
						6'b00_0111: // "7"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0110_0001;
								col2 <= 8'b0001_0001;
								col3 <= 8'b0000_1001;
								col4 <= 8'b0000_0101;
								col5 <= 8'b0000_0011;
								col6 <= 8'b0000_0000;
							end
						6'b00_1000: // "8"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0011_0110;
								col2 <= 8'b0100_1001;
								col3 <= 8'b0100_1001;
								col4 <= 8'b0100_1001;
								col5 <= 8'b0011_0110;
								col6 <= 8'b0000_0000;
							end
						6'b00_1001: // "9"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0010_0110;
								col2 <= 8'b0100_1001;
								col3 <= 8'b0100_1001;
								col4 <= 8'b0100_1001;
								col5 <= 8'b0011_1110;
								col6 <= 8'b0000_0000;
							end
						6'b00_1010: // "A"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0111_1100;
								col2 <= 8'b0001_0010;
								col3 <= 8'b0001_0001;
								col4 <= 8'b0001_0010;
								col5 <= 8'b0111_1100;
								col6 <= 8'b0000_0000;
							end
						6'b00_1011: // "B"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0111_1111;
								col2 <= 8'b0100_1001;
								col3 <= 8'b0100_1001;
								col4 <= 8'b0100_1001;
								col5 <= 8'b0011_0110;
								col6 <= 8'b0000_0000;
							end
						6'b00_1100: // "C"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0011_1110;
								col2 <= 8'b0100_0001;
								col3 <= 8'b0100_0001;
								col4 <= 8'b0100_0001;
								col5 <= 8'b0010_0010;
								col6 <= 8'b0000_0000;
							end
						6'b00_1101: // "D"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0111_1111;
								col2 <= 8'b0100_0001;
								col3 <= 8'b0100_0001;
								col4 <= 8'b0100_0001;
								col5 <= 8'b0011_1110;
								col6 <= 8'b0000_0000;
							end
						6'b00_1110: // "E"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0111_1111;
								col2 <= 8'b0100_1001;
								col3 <= 8'b0100_1001;
								col4 <= 8'b0100_1001;
								col5 <= 8'b0100_0001;
								col6 <= 8'b0000_0000;
							end
						6'b00_1111: // "F"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0111_1111;
								col2 <= 8'b0000_1001;
								col3 <= 8'b0000_1001;
								col4 <= 8'b0000_1001;
								col5 <= 8'b0000_0001;
								col6 <= 8'b0000_0000;
							end
						6'b01_0000: // "G"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0011_1110;
								col2 <= 8'b0100_0001;
								col3 <= 8'b0100_1001;
								col4 <= 8'b0100_1001;
								col5 <= 8'b0011_1010;
								col6 <= 8'b0000_0000;
							end
						6'b01_0001: // "H"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0111_1111;
								col2 <= 8'b0000_1000;
								col3 <= 8'b0000_1000;
								col4 <= 8'b0000_1000;
								col5 <= 8'b0111_1111;
								col6 <= 8'b0000_0000;
							end
						6'b01_0010: // "I"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0000_0000;
								col2 <= 8'b0100_0001;
								col3 <= 8'b0111_1111;
								col4 <= 8'b0100_0001;
								col5 <= 8'b0000_0000;
								col6 <= 8'b0000_0000;
							end
						6'b01_0011: // "J"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0010_0000;
								col2 <= 8'b0100_0001;
								col3 <= 8'b0100_0001;
								col4 <= 8'b0011_1111;
								col5 <= 8'b0000_0001;
								col6 <= 8'b0000_0000;
							end
						6'b01_0100: // "K"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0111_1111;
								col2 <= 8'b0000_1000;
								col3 <= 8'b0001_0100;
								col4 <= 8'b0010_0010;
								col5 <= 8'b0100_0001;
								col6 <= 8'b0000_0000;
							end
						6'b01_0101: // "L"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0111_1111;
								col2 <= 8'b0100_0000;
								col3 <= 8'b0100_0000;
								col4 <= 8'b0100_0000;
								col5 <= 8'b0100_0000;
								col6 <= 8'b0000_0000;
							end
						6'b01_0110: // "M"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0111_1111;
								col2 <= 8'b0000_0010;
								col3 <= 8'b0000_1100;
								col4 <= 8'b0000_0010;
								col5 <= 8'b0111_1111;
								col6 <= 8'b0000_0000;
							end
						6'b01_0111: // "N"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0111_1111;
								col2 <= 8'b0000_0010;
								col3 <= 8'b0000_0100;
								col4 <= 8'b0000_1000;
								col5 <= 8'b0111_1111;
								col6 <= 8'b0000_0000;
							end
						6'b01_1000: // "O"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0011_1110;
								col2 <= 8'b0100_0001;
								col3 <= 8'b0100_0001;
								col4 <= 8'b0100_0001;
								col5 <= 8'b0011_1110;
								col6 <= 8'b0000_0000;
							end
						6'b01_1001: // "P"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0111_1111;
								col2 <= 8'b0000_1001;
								col3 <= 8'b0000_1001;
								col4 <= 8'b0000_1001;
								col5 <= 8'b0000_0110;
								col6 <= 8'b0000_0000;
							end
						6'b01_1010: // "Q"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0011_1110;
								col2 <= 8'b0100_0001;
								col3 <= 8'b0101_0001;
								col4 <= 8'b0110_0001;
								col5 <= 8'b0111_1110;
								col6 <= 8'b0000_0000;
							end
						6'b01_1011: // "R"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0111_1111;
								col2 <= 8'b0000_1001;
								col3 <= 8'b0001_1001;
								col4 <= 8'b0010_1001;
								col5 <= 8'b0100_0110;
								col6 <= 8'b0000_0000;
							end
						6'b01_1100: // "S"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0010_0110;
								col2 <= 8'b0100_1001;
								col3 <= 8'b0100_1001;
								col4 <= 8'b0100_1001;
								col5 <= 8'b0011_0010;
								col6 <= 8'b0000_0000;
							end
						6'b01_1101: // "T"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0000_0001;
								col2 <= 8'b0000_0001;
								col3 <= 8'b0111_1111;
								col4 <= 8'b0000_0001;
								col5 <= 8'b0000_0001;
								col6 <= 8'b0000_0000;
							end
						6'b01_1110: // "U"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0011_1111;
								col2 <= 8'b0100_0000;
								col3 <= 8'b0100_0000;
								col4 <= 8'b0100_0000;
								col5 <= 8'b0011_1111;
								col6 <= 8'b0000_0000;
							end
						6'b01_1111: // "V"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0001_1111;
								col2 <= 8'b0010_0000;
								col3 <= 8'b0100_0000;
								col4 <= 8'b0010_0000;
								col5 <= 8'b0001_1111;
								col6 <= 8'b0000_0000;
							end
						6'b10_0000: // "W"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0011_1111;
								col2 <= 8'b0100_0000;
								col3 <= 8'b0011_0000;
								col4 <= 8'b0100_0000;
								col5 <= 8'b0011_1111;
								col6 <= 8'b0000_0000;
							end
						6'b10_0001: // "X"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0110_0011;
								col2 <= 8'b0001_0100;
								col3 <= 8'b0000_1000;
								col4 <= 8'b0001_0100;
								col5 <= 8'b0110_0011;
								col6 <= 8'b0000_0000;
							end
						6'b10_0010: // "Y"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0000_0011;
								col2 <= 8'b0000_0100;
								col3 <= 8'b0111_1000;
								col4 <= 8'b0000_0100;
								col5 <= 8'b0000_0011;
								col6 <= 8'b0000_0000;
							end
						6'b10_0011: // "Z"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0110_0001;
								col2 <= 8'b0101_0001;
								col3 <= 8'b0100_1001;
								col4 <= 8'b0100_0101;
								col5 <= 8'b0100_0011;
								col6 <= 8'b0000_0000;
							end
						6'b11_1110: // " "
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0000_0000;
								col2 <= 8'b0000_0000;
								col3 <= 8'b0000_0000;
								col4 <= 8'b0000_0000;
								col5 <= 8'b0000_0000;
								col6 <= 8'b0000_0000;
							end
						6'b11_1111: // ":"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0000_0000;
								col2 <= 8'b0011_0110;
								col3 <= 8'b0011_0110;
								col4 <= 8'b0000_0000;
								col5 <= 8'b0000_0000;
								col6 <= 8'b0000_0000;
							end
						default: // "*"
							begin
								col0 <= 8'b0000_0000;
								col1 <= 8'b0010_0010;
								col2 <= 8'b0001_0100;
								col3 <= 8'b0000_1000;
								col4 <= 8'b0001_0100;
								col5 <= 8'b0010_0010;
								col6 <= 8'b0000_0000;
							end
					endcase
				end
		end

endmodule

 

 

  • 大小: 142.6 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics