基于FPGA的VGA彩条发生器

功能概述:通过FPGA在显示器上显示一些条纹或图案,用CRT显示器显示横条纹、竖条纹以及棋盘格子图案。用一个按键来控制显示模式,每按下一次,屏幕上的图案改变一次,依次为横条纹、竖条纹以及棋盘格子图案。

VGA的英文全称是 Video Graphics Array,中文名宇叫视频图形阵列,是IBM在1987年随PS/2机一起推出的_ 种视频传输标准,具有分辨率高、显示速率快、颜色丰富等优点,不支持热插拔,不支持音频传输,在彩色显示器领域得到了广泛的应用。这个标准对于现今的个人电脑市场已经十分过时,现在有更高级的HDMI和DVI等,即使如此,VGA仍然是最多制造商所共同支持的一个标准, 个人电脑在加载自己的独特驱动程序之前,都必须支持VGA的标准。这也说明它在显示标准中的重要性和兼容性。

接口与引脚定义如下图


在这15个管脚中,其中比较重要的是3根RGB彩色分量信号和2根扫描同步信号HSYNC 和VSYNC。需要注意的是:VGA显示器上每一个像素点可以有多种颜色,由三基色 信号R、G、B组合构成,如果每个像素点采用3位二进制数表示(R、G、B信号各一位),则 总共可以显示成2^S=8种颜色,每个像素点采用8位二进制数表示(R、G、B信号各为3、 3、2 )则总共可以显示成8*8*4=256种颜色。如果VGA显示真彩色BMP图像,则要R、G、 B三个分量各8位,即24位表示一个像素值,很多情况下还采用32位表示一个像素值。为了 节省显存的存储空间,可采用髙彩色图像,即每个像素值由16位表示,R、G、B三个分量分别 使用5位、6位、5位,比真彩色图像数据量减少一半,同时又能满足显示效果。介绍完了 VGA 的接口管脚定义。

显示原理图如下


要显示某个图像首先要有这个图像,有了图像以后,可以通过VGA控制器来产生相对应的VGA时序将图像数据送出,送出去之后。然而显示器不能识别数字信号,只能识别模拟信号,因此还需 要一个DA来将数字信号转换成显示器所识别的模拟信号。位数较少的情况下可通过R-2R电阻网络分流模拟DA来实现。

本人所用开发板原理图:


VGA通信时序图


帧时序和行时序都产生了四个部分,帧时序的四个部分分别是:同步脉冲(Sync o)、显示后沿(Back porch p)、显示时序段(Display interval q)和显示 前沿(Front porch r)。其中同步脉冲(Sync o)、显示后沿(Back porch p)和显示前沿(Front porch r)是消隐区,RGB信号无效,屏幕不显示数据。显示时序段(Display interval q)是有效数据区。 行时序的四个部分分别是:同步脉冲(Sync a)、显示后沿(Back porch b)、显示时序段(Display interval c)和显示前沿(Front porch d)。其中同步脉冲(Sync a)、显示后沿(Back porch b)和显示 前沿(Front porch d)是消隐区,RGB信号无效,屏幕不显示数据。显示时序段(Display inteival c)是有效数据区。

常用的分辨率及参数:

设计思路:结合VGA显示原理,可将整个系统分成三个模块,分别是:

(1)PLL模块:定制一个PLL IP核,接入系统时钟,产生显示模式相对应的时钟,我所用的是800*600@60(即分辨率为800*600,刷新频率为60Hz)的显示模式 相应的时钟为40 MHz,可以按照行、帧时序计算得到,行扫描时序共1056个时钟周期,帧扫描时序共625个行扫描周期,每秒刷新60帧 ,时钟频率=1056*625*60=3960000Hz,因为PLL并非可以随意分频,所以取40MHz。

(2)KEY模块:用以控制显示模式,每按下一次,屏幕显示转换一次,主要解决按键消抖问题,把消抖后的控制信号传给VGA模块。

(3)VGA模块:根据VGA通信时序产生VGA通信时序波形,在数据有效的时间输出RGB分量信号,并接收来自KEY模块的控制信号

RTL视图如下:


顶层模块代码如下

module VGA_TOP 
	(
		CLK_50M , RST_N ,	KEY,						//输入端口
		VGA_VSYNC , VGA_HSYNC , VGA_DATA		        //输出端口
	);

input  CLK_50M , RST_N , KEY;
output VGA_VSYNC , VGA_HSYNC ;
output [7:0] VGA_DATA ;

wire CLK_40M;
wire KEY_DATA;

KEY_Single_Button key
(
	.KEY		(KEY),
	.KEY_DATA	(KEY_DATA),
	.RST_N		(RST_N),
	.CLK		(CLK_40M)
);

PLL pll_50m_to_40m
	(
		.inclk0 (CLK_50M),
		.c0	    (CLK_40M)
	);

VGA vga_control
(
	.CLK_40M	(CLK_40M), 
	.RST_N		(RST_N),	
	.KEY_DATA   (KEY_DATA),
	.VGA_VSYNC 	(VGA_VSYNC), 
	.VGA_HSYNC 	(VGA_HSYNC), 
	.VGA_DATA	(VGA_DATA)	
);
endmodule

KEY模块代码

module KEY_Single_Button (KEY,KEY_DATA,RST_N,CLK);
	input  KEY;
	input RST_N,CLK;
	output reg  KEY_DATA;
	
	reg  key_r , KEY_DATA_N;
	reg [20:0] cnt,cnt_n;
	wire key_an;
	
	parameter time_40ms = 21'd4000000;
	
	always @ (posedge CLK or negedge RST_N)
	begin
		if (!RST_N)
			key_r <= 1'b0;
		else 
			key_r <= KEY;
	end
	
	assign key_an = !key_r & KEY;
	
	always @ (posedge CLK or negedge RST_N)
	begin
		if (!RST_N)
			cnt <= 21'd0;
		else
			cnt <= cnt_n;
	end
	
	always @(*)
	begin
		if (cnt == time_40ms || key_an)
			cnt_n = 21'd0;
		else
			cnt_n = cnt + 1'b1;
	end
	
	always @ (posedge CLK or negedge RST_N)
	begin 
		if (!RST_N)
			KEY_DATA <= 1'b0;
		else
			KEY_DATA <= KEY_DATA_N;
		end
	
	always @ (*)
	begin
		if (cnt == time_40ms)
			KEY_DATA_N = key_r;
		else
			KEY_DATA_N = 1'b0;
	end
endmodule
VGA模块代码

`define HSYNC_A   16'd128  // 128
`define HSYNC_B   16'd216  // 128 + 88
`define HSYNC_C   16'd1016 // 128 + 88 + 800
`define HSYNC_D   16'd1056 // 128 + 88 + 800 + 40

`define VSYNC_O   16'd4    // 4 
`define VSYNC_P   16'd27   // 4 + 23
`define VSYNC_Q   16'd627  // 4 + 23 + 600
`define VSYNC_R   16'd628  // 4 + 23 + 600 + 1


module VGA 
	(
		CLK_40M, RST_N,	KEY_DATA	,					 //输入端口
		VGA_VSYNC , VGA_HSYNC , VGA_DATA	          //输出端口
	);
//输入输出端口声明	
input  CLK_40M, RST_N,KEY_DATA;
output reg VGA_VSYNC , VGA_HSYNC ;  
output reg [7:0] VGA_DATA ;

//内部端口声明
reg [15:0] cnt_hsync , cnt_hsync_n , cnt_vsync ,cnt_vsync_n;
reg [7:0]  VGA_DATA_N ;
reg VGA_VSYNC_N , VGA_HSYNC_N ;
reg vga_en , vga_en_n ;
reg [1:0] control , control_n;

always @ (posedge CLK_40M or negedge RST_N)
begin
	if (!RST_N)
		control <= 2'd0;
	else 
		control <= control_n;
end

always @ (*)
begin
	if (KEY_DATA)
		control_n = control + 1'b1;
	else
		control_n = control;
end

//行扫描计数器
always @ (posedge CLK_40M or negedge RST_N)
begin
	if (!RST_N)
		cnt_hsync <= 16'd0;
	else 
		cnt_hsync <= cnt_hsync_n;
end

always @(*)
begin
	if (cnt_hsync == `HSYNC_D)
		cnt_hsync_n = 16'd0;
	else
		cnt_hsync_n = cnt_hsync + 1'b1;
end

//垂直扫描计数器
always @ (posedge CLK_40M or negedge RST_N)
begin
	if (!RST_N)
		cnt_vsync <= 16'd0;
	else 
		cnt_vsync <= cnt_vsync_n;
end

always @(*)
begin
	if ((cnt_vsync == `VSYNC_R) && (cnt_hsync == `HSYNC_D))
		cnt_vsync_n = 16'd0;
	else  if (cnt_hsync == `HSYNC_D)
		cnt_vsync_n = cnt_vsync + 16'd1;
		else
			cnt_vsync_n = cnt_vsync;
end

//VSYNC时序波形生成
always @ (posedge CLK_40M or negedge RST_N)
begin
	if (!RST_N)
		VGA_VSYNC <= 1'b0;
	else 
		VGA_VSYNC <= VGA_VSYNC_N;
end

always @(*)
begin
	if (cnt_vsync < `VSYNC_O)
		VGA_VSYNC_N = 1'b0;
	else
		VGA_VSYNC_N =1'b1;
end

//HSYNC时序波形生成
always @ (posedge CLK_40M or negedge RST_N)
begin
	if (!RST_N)
		VGA_HSYNC <= 1'b0;
	else 
		VGA_HSYNC <= VGA_HSYNC_N;
end

always @(*)
begin
	if (cnt_hsync < `HSYNC_A)
		VGA_HSYNC_N = 1'b0;
	else
		VGA_HSYNC_N =1'b1;
end

//判断显示有效区(即通信时序图的Q与重叠的区域),在显示有效区域对vga_en赋1
always @ (posedge CLK_40M or negedge RST_N)
begin
	if (!RST_N)
		vga_en <= 1'b0;
	else 
		vga_en <= vga_en_n;
end

always @(*)
begin
	if (((cnt_hsync > `HSYNC_B)&&(cnt_hsync < `HSYNC_C)) && ((cnt_vsync > `VSYNC_P)&&(cnt_vsync < `VSYNC_Q)))
		vga_en_n = 1'b1;
	else
		vga_en_n =1'b0;
end

//对VGA_DATA赋值
always @ (posedge CLK_40M or negedge RST_N)
begin
	if (!RST_N)
		VGA_DATA <= 8'h0;
	else 
		VGA_DATA <= VGA_DATA_N;
end

always @ (*)
begin
	case (control)
	2'b00:						//横条纹
			if (vga_en)
			begin
					if((cnt_vsync > `VSYNC_P) && (cnt_vsync <= `VSYNC_P + 10'd150))						//判断屏幕位置
						VGA_DATA_N = 8'hE0;			//红色
					else if((cnt_vsync > `VSYNC_P + 10'd150) && (cnt_vsync <= `VSYNC_P + 10'd300))//判断屏幕位置
						VGA_DATA_N = 8'h03;			//黄色
					else if((cnt_vsync > `VSYNC_P + 10'd300) && (cnt_vsync <= `VSYNC_P + 10'd450))	//判断屏幕位置
						VGA_DATA_N = 8'hFC;			//蓝色
					else if((cnt_vsync > `VSYNC_P + 10'd450) && (cnt_vsync <= `VSYNC_P + 10'd600))	//判断屏幕位置
						VGA_DATA_N = 8'h1C;			//绿色
					else
						VGA_DATA_N = 8'h0;			//黑色	 
			end
			else
					VGA_DATA_N = 8'h0;
	2'b01:						//竖条纹
			if (vga_en)
				begin
						if((cnt_hsync > `HSYNC_B) && (cnt_hsync <= `HSYNC_B + 10'd200))						//判断屏幕位置
							VGA_DATA_N = 8'hE0;			//红色
						else if((cnt_hsync > `HSYNC_B + 10'd200) && (cnt_hsync <= `HSYNC_B + 10'd400))//判断屏幕位置
							VGA_DATA_N = 8'h03;			//黄色
						else if((cnt_hsync > `HSYNC_B + 10'd400) && (cnt_hsync <= `HSYNC_B + 10'd600))	//判断屏幕位置
							VGA_DATA_N = 8'hFC;			//蓝色
						else if((cnt_hsync > `HSYNC_B + 10'd600) && (cnt_hsync <= `HSYNC_B + 10'd800))	//判断屏幕位置
							VGA_DATA_N = 8'h1C;			//绿色
						else
							VGA_DATA_N = 8'h0;			//黑色	 
				end
				else
						VGA_DATA_N = 8'h0;
	2'b10:				//棋盘格
			if (vga_en)
				begin
						if((cnt_hsync > `HSYNC_B) && (cnt_hsync <= `HSYNC_B + 10'd200))						//判断屏幕位置
							begin
								if ((cnt_vsync <= `VSYNC_P + 10'd100) || ((cnt_vsync > `VSYNC_P + 10'd200) && (cnt_vsync <= `VSYNC_P + 10'd300)) ||((cnt_vsync > `VSYNC_P + 10'd400) && (cnt_vsync <= `VSYNC_P + 10'd500)))
									VGA_DATA_N = 8'hE0;			//
								else if (((cnt_vsync > `VSYNC_P + 10'd100) && (cnt_vsync <= `VSYNC_P + 10'd200))|| ((cnt_vsync > `VSYNC_P + 10'd300) && (cnt_vsync <= `VSYNC_P + 10'd400)) ||((cnt_vsync > `VSYNC_P + 10'd500) && (cnt_vsync <= `VSYNC_P + 10'd600)))
									VGA_DATA_N = 8'h03;			//
									else
										VGA_DATA_N = 8'h0;
							end	
						else if((cnt_hsync > `HSYNC_B + 10'd200) && (cnt_hsync <= `HSYNC_B + 10'd400))//判断屏幕位置
							begin
								if ((cnt_vsync <= `VSYNC_P + 10'd100) || ((cnt_vsync > `VSYNC_P + 10'd200) && (cnt_vsync <= `VSYNC_P + 10'd300)) ||((cnt_vsync > `VSYNC_P + 10'd400) && (cnt_vsync <= `VSYNC_P + 10'd500)))
									VGA_DATA_N = 8'hFC;			//
								else if (((cnt_vsync > `VSYNC_P + 10'd100) && (cnt_vsync <= `VSYNC_P + 10'd200))|| ((cnt_vsync > `VSYNC_P + 10'd300) && (cnt_vsync <= `VSYNC_P + 10'd400)) ||((cnt_vsync > `VSYNC_P + 10'd500) && (cnt_vsync <= `VSYNC_P + 10'd600)))
									VGA_DATA_N = 8'h1C;			//
									else
										VGA_DATA_N = 8'h0;
							end	
						else if((cnt_hsync > `HSYNC_B + 10'd400) && (cnt_hsync <= `HSYNC_B + 10'd600))	//判断屏幕位置
							begin
								if ((cnt_vsync <= `VSYNC_P + 10'd100) || ((cnt_vsync > `VSYNC_P + 10'd200) && (cnt_vsync <= `VSYNC_P + 10'd300)) ||((cnt_vsync > `VSYNC_P + 10'd400) && (cnt_vsync <= `VSYNC_P + 10'd500)))
									VGA_DATA_N = 8'h03;			//
								else if (((cnt_vsync > `VSYNC_P + 10'd100) && (cnt_vsync <= `VSYNC_P + 10'd200))|| ((cnt_vsync > `VSYNC_P + 10'd300) && (cnt_vsync <= `VSYNC_P + 10'd400)) ||((cnt_hsync > `VSYNC_P + 10'd500) && (cnt_vsync <= `VSYNC_P + 10'd600)))
									VGA_DATA_N = 8'hE0;			//
									else
										VGA_DATA_N = 8'h0;
							end	
						else if((cnt_hsync > `HSYNC_B + 10'd600) && (cnt_hsync <= `HSYNC_B + 10'd800))	//判断屏幕位置
								begin
								if ((cnt_vsync <= `VSYNC_P + 10'd100) || ((cnt_vsync > `VSYNC_P + 10'd200) && (cnt_vsync <= `VSYNC_P + 10'd300)) ||((cnt_vsync > `VSYNC_P + 10'd400) && (cnt_vsync <= `VSYNC_P + 10'd500)))
									VGA_DATA_N = 8'h1C;			//
								else if (((cnt_vsync > `VSYNC_P + 10'd100) && (cnt_vsync <= `VSYNC_P + 10'd200))|| ((cnt_vsync > `VSYNC_P + 10'd300) && (cnt_vsync <= `VSYNC_P + 10'd400)) ||((cnt_vsync > `VSYNC_P + 10'd500) && (cnt_vsync <= `VSYNC_P + 10'd600)))
									VGA_DATA_N = 8'hFC;			//
									else
										VGA_DATA_N = 8'h0;
							end	
						else
							VGA_DATA_N = 8'h0;			
				end
				else
						VGA_DATA_N = 8'h0;
	
	2'b11:VGA_DATA_N = 8'h0;
	default : VGA_DATA_N = 8'h0;
	endcase
end

endmodule






  • 12
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值