实验三 VGA显示实验报告
目录
实验目的
利用VGA接口,在显示屏上显示横条纹和彩色棋盘格。
实验内容
原理描述
vga介绍
VGA(Video Graphics Array)主要用于老式CRT显示器,核心原理是通过加热阴极发射电子,经过聚焦和偏转,最终击打在涂有三色荧光粉的屏幕上发光。VGA接口有15针,分三排,每排五个。本实验用到RGB彩色分量信号和HSYNC(行同步)、VSYNC(场同步)信号。
- HSYNC:行同步信号,单位为像素。
- VSYNC:场同步信号,单位为行。
- RGB:红绿蓝三基色信号。
时序
- 行时序以像素为单位,利用计数器按像素时钟计满后清零,再拉低同步信号。
- 场时序以行为单位,行计数器满一行,场计数器加1,满一场后清零,再拉低同步信号。
数据显示
在Hor Active Video和Ver Active Video均有效期间,向RGB分量送数据,即可在屏幕显示图案。FPGA输出的RGB为数字信号,通过电阻网络或数模转换芯片转换为模拟信号输出。FPGA输出的RGB三基色共16位,Red占5位、Green占6位、Blue占5位。
注意事项
- 行时序是“像素”为单位,场时序是“行”为单位。
- VGA工业标准要求同步信号为负极性(负脉冲)。
- 行、场时序有具体的同步、消隐、有效、前肩等规范。
Verilog HDL设计源代码
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/04/29 17:06:31
// Design Name:
// Module Name: vga
// Project Name:
// Target Devices:
// Tool Versions:
// Description: VGA显示横条纹、竖条纹和彩色棋盘格
//
//
module vga(
input clock, // 系统输入时钟 100MHz
input [1:0] switch, // 显示内容选择
output [2:0] disp_RGB,// VGA 数据输出
output hsync, // VGA 行同步信号
output vsync // VGA 场同步信号
);
reg [9:0] hcount; // 行扫描计数器
reg [9:0] vcount; // 场扫描计数器
reg [2:0] data;
reg [2:0] h_dat;
reg [2:0] v_dat;
reg [1:0] cnt;
wire hcount_ov;
wire vcount_ov;
wire dat_act;
reg vga_clk;
// VGA时序参数
parameter hsync_end = 10'd95,
hdat_begin = 10'd143,
hdat_end = 10'd783,
hpixel_end = 10'd799,
vsync_end = 10'd1,
vdat_begin = 10'd34,
vdat_end = 10'd514,
vline_end = 10'd524;
// 4分频
always @(posedge clock) begin
if(cnt == 3) begin
cnt <= 1;
vga_clk <= ~vga_clk;
end else
cnt <= cnt + 1;
end
// 行扫描
always @(posedge vga_clk) begin
if(hcount_ov)
hcount <= 10'd0;
else
hcount <= hcount + 10'd1;
end
assign hcount_ov = (hcount == hpixel_end);
// 场扫描
always @(posedge vga_clk) begin
if(hcount_ov) begin
if(vcount_ov)
vcount <= 10'd0;
else
vcount <= vcount + 10'd1;
end
end
assign vcount_ov = (vcount == vline_end);
// 数据、同步信号输出
assign dat_act = ((hcount >= hdat_begin) && (hcount < hdat_end)) &&
((vcount >= vdat_begin) && (vcount < vdat_end));
assign hsync = (hcount > hsync_end);
assign vsync = (vcount > vsync_end);
assign disp_RGB = (dat_act) ? data : 3'h00;
// 显示数据处理
always @(posedge vga_clk) begin
case(switch[1:0])
2'd0: data <= h_dat; // 横彩条
2'd1: data <= v_dat; // 竖彩条
2'd2: data <= (v_dat ^ h_dat); // 棋盘格
2'd3: data <= (v_dat ~^ h_dat);// 棋盘格
endcase
end
// 竖彩条
always @(posedge vga_clk) begin
if(hcount < 223)
v_dat <= 3'h7; // 白
else if(hcount < 303)
v_dat <= 3'h6; // 黄
else if(hcount < 383)
v_dat <= 3'h5; // 青
else if(hcount < 463)
v_dat <= 3'h4; // 绿
else if(hcount < 543)
v_dat <= 3'h3; // 紫
else if(hcount < 623)
v_dat <= 3'h2; // 红
else if(hcount < 703)
v_dat <= 3'h1; // 蓝
else
v_dat <= 3'h0; // 黑
end
// 横彩条
always @(posedge vga_clk) begin
if(vcount < 94)
h_dat <= 3'h7; // 白
else if(vcount < 154)
h_dat <= 3'h6; // 黄
else if(vcount < 214)
h_dat <= 3'h5; // 青
else if(vcount < 274)
h_dat <= 3'h4; // 绿
else if(vcount < 334)
h_dat <= 3'h3; // 紫
else if(vcount < 394)
h_dat <= 3'h2; // 红
else if(vcount < 454)
h_dat <= 3'h1; // 蓝
else
h_dat <= 3'h0; // 黑
end
endmodule
Testbench仿真代码及仿真结果
module testbench();
reg clk;
reg [1:0] switch;
wire [2:0] disp_RGB;
wire hsync;
wire vsync;
vga uut(
.clock(clk),
.switch(switch),
.disp_RGB(disp_RGB),
.hsync(hsync),
.vsync(vsync)
);
initial begin
clk = 0;
switch = 2'b00;
repeat(10000) begin
#5 clk = ~clk;
end
$stop;
end
always @(posedge clk) begin
$display("switch=%b, hsync=%b, vsync=%b, disp_RGB=%b", switch, hsync, vsync, disp_RGB);
end
endmodule
XDC文件配置
set_property IOSTANDARD LVCMOS33 [get_ports {disp_RGB[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_RGB[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {disp_RGB[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {switch[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {switch[0]}]
set_property PACKAGE_PIN A4 [get_ports {disp_RGB[2]}]
set_property PACKAGE_PIN A6 [get_ports {disp_RGB[1]}]
set_property PACKAGE_PIN D8 [get_ports {disp_RGB[0]}]
set_property PACKAGE_PIN V10 [get_ports {switch[1]}]
set_property PACKAGE_PIN U11 [get_ports {switch[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports clock]
set_property IOSTANDARD LVCMOS33 [get_ports hsync]
set_property IOSTANDARD LVCMOS33 [get_ports vsync]
set_property PACKAGE_PIN E3 [get_ports clock]
set_property PACKAGE_PIN B11 [get_ports hsync]
set_property PACKAGE_PIN B12 [get_ports vsync]
下板测试
- Switch=00:显示横彩条
- Switch=01:显示竖彩条
- Switch=10:显示棋盘格(异或实现)
- Switch=11:显示棋盘格(同或实现)
实验体会
理清原理与整体流程
在实验过程中首当其冲的是搞清楚实验原理,这里有vga显示原理,信号传输原理以及行,场扫描,其次就是脑子里有个大概框架,要知道第一步实现什么,第二步实现什么,这样会使我们的代码更有条理性,而且在这个实验中养成了一个很好的习惯就是加一段长长的注释符,并写上下面这一段代码的作用,使得代码已读易懂,方便后面发现错误时改错。代码注释和模块化习惯
在遇到问题时多思考,本来我的打算是写两个实验来满足老师显示竖条纹和棋盘格,但是前面的时序功能都一样,所以就加一个选择信号Switch[1:0],来实现一个实验显示竖条纹和棋盘格。这里棋盘格的实现是用了异或。善用选择信号优化设计
遇到功能需求时,不必重复写多个实验,只需通过switch信号选择即可,如本实验用switch切换横条、竖条和棋盘格。基础功能需熟练掌握
计数器和分频是很基础和重要的功能,在FPGA开发中必不可少,需要熟练掌握分频器和计数器,在设计分频器时可以自己拿笔在纸上选取几个时钟进行分析。硬件代码无debug,思路和细节更重要
硬件描述代码没有debug功能,我们需要理清我们的思路,注意细节,尽量减少低级错误,以减少改代码的工作量。分析与优化分频器
多分析分频原理,第二种分频方法是通过纸面分析得到的,虽然一开始有些困难,但实践后更易理解。
主要是计数三个周期后赋值为1而不是0。
附:实验相关代码和配置见上方各小节,可直接用于开发板实现与仿真验证。