实验三:VGA显示实验

发布于:2025-06-09 ⋅ 阅读:(15) ⋅ 点赞:(0)

实验三 VGA显示实验报告

目录

  1. 实验目的
  2. 实验内容
  3. 实验体会

实验目的

利用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位。

注意事项
  1. 行时序是“像素”为单位,场时序是“行”为单位。
  2. VGA工业标准要求同步信号为负极性(负脉冲)。
  3. 行、场时序有具体的同步、消隐、有效、前肩等规范。

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:显示棋盘格(同或实现)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

实验体会

  1. 理清原理与整体流程
    在实验过程中首当其冲的是搞清楚实验原理,这里有vga显示原理,信号传输原理以及行,场扫描,其次就是脑子里有个大概框架,要知道第一步实现什么,第二步实现什么,这样会使我们的代码更有条理性,而且在这个实验中养成了一个很好的习惯就是加一段长长的注释符,并写上下面这一段代码的作用,使得代码已读易懂,方便后面发现错误时改错。

  2. 代码注释和模块化习惯
    在遇到问题时多思考,本来我的打算是写两个实验来满足老师显示竖条纹和棋盘格,但是前面的时序功能都一样,所以就加一个选择信号Switch[1:0],来实现一个实验显示竖条纹和棋盘格。这里棋盘格的实现是用了异或。

  3. 善用选择信号优化设计
    遇到功能需求时,不必重复写多个实验,只需通过switch信号选择即可,如本实验用switch切换横条、竖条和棋盘格。

  4. 基础功能需熟练掌握
    计数器和分频是很基础和重要的功能,在FPGA开发中必不可少,需要熟练掌握分频器和计数器,在设计分频器时可以自己拿笔在纸上选取几个时钟进行分析。

  5. 硬件代码无debug,思路和细节更重要
    硬件描述代码没有debug功能,我们需要理清我们的思路,注意细节,尽量减少低级错误,以减少改代码的工作量。

  6. 分析与优化分频器
    多分析分频原理,第二种分频方法是通过纸面分析得到的,虽然一开始有些困难,但实践后更易理解。
    在这里插入图片描述
    主要是计数三个周期后赋值为1而不是0。


附:实验相关代码和配置见上方各小节,可直接用于开发板实现与仿真验证。