提示:本文仅为个人学习记录
一、概述
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中进行修改即可。