FPGA VGA显示系统


提示:本文仅为个人学习记录

一、概述

1、目的及意义:

设计VGA显示系统,了解屏幕显示基本原理,并熟练掌握RAM储存器的相关知识。

2、主要功能:

在屏幕上显示指定图像;能通过按键改变图像位置;能显示指定功能的动态图像。

二、原理及步骤

1、原理框图:

在这里插入图片描述

图1 基本通信原理
在这里插入图片描述

图2 VGA接口说明

图3 VGA与FPGA引脚关系图
在这里插入图片描述

2、工作原理

VGA图像显示的实质显示RAM中的像素值,通过将像素值转换为对应的RGB值,再根据RAM的内存地址在显示屏上的指定位置进行颜色显示。
而图像的移动以及动图的实现实际上是通过改变RAM中对应地址的像素值实现的。

3、功能模块简介

1、RAM2 ram2存储器模块主要用于像素值的存储,以及后期像素值的修改添加。
2、vga_c vga模块用于根据RAM中的地址和像素值,并将像素值转换为RGB分量再到显示屏上进行显示。

4、实验步骤

1、根据课堂知识,烧写程序,显示初始图像(周老师头像)
2、初始化颜色后,根据行列地址显示蓝色边框,根据公式显示黄色的圆:
在这里插入图片描述

和白色背景。
3、设置按键改变X 和 Y 的值(通过改变圆心坐标改变园的位置),
4、第四题:通过使圆心的X Y坐标同时加减相同的值,实现以45度角匀速运动,通过状态机判断园是否触边,并根据触边的方向改变下一刻的运动方向。
三、程序设计及描述
代码:

vga_c 除了上课的改动并无其他改动所以不进行粘贴
module vga( 
		output      [7:0]  VGA_B,
      output reg         VGA_BLANK_N,
      output             VGA_CLK,
      output      [7:0]  VGA_G,
      output             VGA_HS,
      output      [7:0]  VGA_R,
      output             VGA_SYNC_N,
      output             VGA_VS,
		input              CLOCK_50,
		input              KEY,
		input[3:0] KEY1,
		input SW1,//控制第三题或第四题
		input[3:0] SW
 );
	
wire[15:0] q;
ram2 ram_inst(
	.rdaddress( address ),
	.wraddress(wraddr),
	.clock( CLOCK_50 ),
	.data(data_in),
	.rden( ~rdn ),
	.wren(1),
	.q( q ));
	
wire[15:0]	datain=q;
wire[16:0]	rd_a;
wire[16:0]	address=(rd_a[16:9]*320)+rd_a[8:0];
reg[16:0]  wraddr;
wire 			rdn;
wire 			vga_clk;
	
reg[22:0] count1;//时钟计数器
reg clk;//10hz
reg[15:0] data_in;
reg[8:0] x0;//圆心列
reg[8:0] y0;//圆心行
reg[16:0] count;//地址计数器
wire[7:0] row;//行
wire[8:0] col;//列
reg[4:0] speed;
reg[8:0] i;
reg[6:0] cur_st;

always@(posedge CLOCK_50)//地址计数器
begin
	if(count == 17'd76800)
	begin
		count <= 1'b0;
	end
	else
	begin
		count <= count + 1;
	end
end
	
assign row = count / 320;//行
assign col = count % 320;//列

initial
	begin
		x0 = 9'd160;
		y0 = 9'd120;
	end
	
always@(posedge CLOCK_50)//时钟计数模块
	begin
		if(count1 == 23'd5000000)
			begin
			count1<=0;
		end
		else
		begin
			count1 <= count1+1;
		end
	end

always@(posedge CLOCK_50)//产生10hz模块
	begin
		if(count1 == 23'd5000000)
			begin
				clk = !clk;//10hz时钟 0.1s一个上升沿
			end
	end
	

initial
	VGA_BLANK_N=1;
	
assign VGA_CLK=vga_clk;

vga_c u0(
	.clk(CLOCK_50),//50MHZ
	.clrn(KEY),
	.datain(datain),
	.h_count(),
	.v_count(),
	.vga_clk(vga_clk),
	.rdn(rdn), //读使能"0"有效
	.rd_a(rd_a),//读地址read_address={row(8),col(9bit)} output
	.hs(VGA_HS),
	.vs(VGA_VS),
	.r(VGA_R),
	.g(VGA_G),
	.b(VGA_B));

//颜色初值
   localparam [15:0]yellow=16'b1111111111100000;
	localparam [15:0]white=16'b1111111111111111;
	localparam [15:0]blue=16'b0000000000011111;
	
always@(posedge CLOCK_50) 
	begin
		if((row<=8'd40&&row>=1'd0&&col>=1'd0&&col<9'd320)||(col>=1'd0&&col<9'd320&&row>9'd200 && row<9'd240)||(col>=1'd0&&col<=8'd40&&row>=1'd0&&row<=9'd240)||(col>=9'd280&&col<9'd320&&row>=1'd0&&row<=9'd240))//上下左右
			 begin
				wraddr <= count;
				data_in = blue;
			 end	
		else if((col - x0)*(col - x0) + (row - y0)*(row - y0) <= 625)//(x-x0)^2+(y-y0)=R^2
				begin
					wraddr <= count;
					data_in = yellow;
				end
		else
		begin
			wraddr <= count ;
			data_in = white;
    	end
	end	

//移动模块
always@(posedge clk)//10hz时钟
begin
	if(SW1 == 1'b1)
	begin
		case(KEY1)
			4'b1110:begin							//右
							if(x0>=9'd65 && x0<=9'd255)
								begin
									x0 = x0 + 5;
								end
							else
								begin
									x0 = x0;
								end
						end
			4'b1101:begin							//左	
							if(x0>=9'd65 && x0<=9'd255)
								begin
									x0 = x0 - 5;
								end
							else
								begin
									x0 = x0;
								end
						end
			4'b1011:begin							//下
							if(y0>=9'd65 && y0<=9'd175)
								begin
								y0 = y0 + 5;
								end
							else
								begin
									y0 = y0;
								end
						end
			4'b0111:begin							//上
							if(y0>=9'd65 && y0<=9'd175)
								begin
									y0 = y0 - 5;
								end
							else
								begin
									y0 = y0;
								end
						end
			default:
						begin
							x0 = x0;
							y0 = y0;
						end
		endcase
	end
else //第四题
begin
	case(cur_st)
			4'd0:begin 
					x0 = x0 + speed;//右下方向
					y0 = y0 + speed;
					if(y0 >= 9'd175)
					begin
						cur_st <= 4'd1;
					end
					else if(x0 >= 9'd255)
					begin
						cur_st <= 4'd3;
					end
			end
			4'd1:begin
					x0 = x0 + speed;//右上方向
					y0 = y0 - speed;
					if(x0 >= 9'd255)
					begin
						cur_st <= 4'd2;
					end
					else if(y0 <= 9'd65)
					begin
						cur_st <= 4'd0;
					end
			end
			4'd2:begin
					x0 = x0 - speed;//左上方向
					y0 = y0 - speed;
					if(y0 <= 9'd65)
					begin
						cur_st <= 4'd3;
					end
					else if(x0 <= 9'd65)
					begin
						cur_st <= 4'd1;
					end
			end
			4'd3:begin
					x0 = x0 - speed;//左下方向
					y0 = y0 + speed;
					if(x0 <= 9'd65)
					begin
						cur_st <= 4'd0;
					end
					else if(y0 >= 9'd175)
					begin
						cur_st <= 4'd2;
					end
			end
			default:cur_st <= 4'd0;
		endcase
end
end


//速度模块
always@(posedge CLOCK_50)
begin
	if(SW == 4'b0000)
		begin
			speed = 5'd0;
		end
	else if(SW == 4'b0001)
		begin
			speed = 5'd4;
		end
	else if(SW == 4'b0011)
		begin
			speed = 5'd8;
		end
	else if(SW == 4'b0111)
		begin
			speed = 5'd12;
		end
	else if(SW == 4'b1111)
		begin
			speed = 5'd16;
		end
end
endmodule

四、仿真与综合测试

1、 实物图
在这里插入图片描述

五、 总结

1、 Vga显示图像因为有代码铺垫实质上并不困难,我们只需要对显示屏地址和RAM地址进行理解。完成作业的时候对显示屏对应位置的RAM中进行修改即可。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值