基于DE2-115平台的VGA显示

一.VGA协议

  • VGA协议,即Video Graphics Array(视频图形阵列),是由IBM公司在1987年推出的视频传输标准。该标准被广泛应用于彩色显示器领域,尤其在CRT显示器时代占据着重要地位。以下是对VGA协议的详细介绍:
  1. 接口特性:VGA接口是一个15针的D型接口,通过模拟信号传输视频数据。它主要传输红、绿、蓝三种颜色的模拟信号以及水平和垂直的同步信号[3]。
  2. 色彩原理:VGA基于红、绿、蓝三基色原理来合成不同的颜色。通过调整这三种基本色的强度,可以产生广泛的颜色范围[1]。
  3. 扫描方式:VGA采用逐行扫描的方式,从屏幕左上角开始,从左向右逐点扫描,每扫描完一行,电子束回到屏幕左边下一行的起始位置,然后进行场同步并使扫描回到屏幕左上方[1]。
  4. 时序控制:VGA显示要求精确的时序控制,包括行同步和场同步信号。这些信号确保图像数据在正确的时间被正确地传输到显示屏上。行同步信号负责水平同步,而场同步信号负责垂直同步[4]。
  5. 规格参数:VGA有多种分辨率和刷新率设置,常见的如640x480@60Hz等。每种模式都有其特定的时序参数,这些参数定义了有效图像区域的大小和位置,以及同步脉冲的长度和位置[2]。
  6. 应用领域:尽管数字接口技术如HDMI已逐渐取代VGA,但由于其结构简单、成本低廉,VGA仍然在许多老旧设备和一些特殊应用中使用[3]。

此外,对于希望深入了解或使用VGA的用户来说,了解其基本的工作原理和关键参数是非常重要的。例如,在进行VGA接口设计时,需要考虑的因素包括:

  1. 兼容性:确保VGA控制器能够与不同分辨率和刷新率的显示器兼容。
  2. 信号完整性:由于VGA是模拟信号传输,长距离传输可能会影响信号质量,因此可能需要使用高质量的电缆和连接器。
  3. 硬件设计:设计电路板时,应考虑到VGA信号的干扰问题,合理布局以减少干扰。

二.VGA显示原理

  • VGA显示原理是利用模拟信号进行视频传输,采用逐行扫描的方式将图像像素点依次显示在屏幕上

VGA(Video Graphics Array)技术自1987年由IBM公司推出以来,已成为视频显示领域广泛使用的标准之一。尽管现代显示技术如HDMI已逐渐占据主流,但了解VGA的工作原理对于理解传统显示技术仍具有重要意义。以下是对VGA显示原理的详细阐述:

  1. 色彩生成与信号转换:VGA通过红、绿、蓝三基色的组合来产生不同的颜色,这三种颜色的混合可以创造出人眼可见的几乎所有颜色。具体来说,VGA接口中的三个模拟信号分别对应于这三种基本颜色,通过调整这三种信号的强度,可以实现多种颜色和灰度级的显示[1]。
  2. 逐行扫描与同步信号:在显示过程中,VGA采用逐行扫描的方式,从屏幕左上角开始,逐个像素点向右扫描,完成一行后迅速返回到下一行的起始位置,并继续扫描,直到扫描完屏幕底部的最后一行。这一过程需要精确的时序控制,包括行同步和场同步信号。这些同步信号确保了图像数据能在正确的时间被正确地传输到显示屏上,从而避免了图像的扭曲或滚动[2]。
  3. 时序标准与兼容性:为了适应不同制造商的显示器,VGA有一套详细的时序标准,这保证了不同设备间的兼容性。例如,行同步和场同步信号的频率和持续时间都需要严格按照这些标准来设置,以确保图像能稳定连续地显示[2]。
  4. 硬件设计挑战:由于VGA传输的是模拟信号,因此容易受到电磁干扰的影响。设计师在使用VGA时需要考虑如何减少这种干扰,比如使用屏蔽电缆和合理的电路布局来保持信号的完整性。同时,数字到模拟的转换也是设计中的关键部分,通常需要高精度的数模转换器来实现高质量的图像输出[3]。

2.1实验环境

软件:Quartus (Quartus Prime 18.0) Standard Edition Visual Studio Code
硬件:DE2-115FPGA开发板,显示屏

2.2 字符取模

请添加图片描述
在这里插入图片描述

2.3实验代码

data_drive.v

module data_drive (input			wire						vga_clk,
                   input			wire						rst_n,
                   input			wire		[ 11:0 ]		addr_h,
                   input			wire		[ 11:0 ]		addr_v,
                   input			wire		[ 2:0 ]		 key,
                   output			reg		[ 15:0 ]				rgb_data);

localparam	red    = 16'd63488;
localparam	orange = 16'd64384;
localparam	yellow = 16'd65472;
localparam	green  = 16'd1024;
localparam	blue   = 16'd31;
localparam	indigo = 16'd18448;
localparam	purple = 16'd32784;
localparam	white  = 16'd65503;
localparam	black  = 16'd0;
reg [ 383:0 ] char_line[ 64:0 ];

localparam	states_1 = 1; // 彩条
localparam	states_2 = 2; // 字符
localparam	states_3 = 3; // 图片

parameter	height = 78; // 图片高度
parameter	width  = 128; // 图片宽度
reg			[ 1:0 ]			states_current			; // 当前状态
reg			[ 1:0 ]			states_next			    ; // 下个状态
reg			[ 13:0 ]		rom_address				; // ROM地址
wire			[ 15:0 ]		rom_data				; // 图片数据

wire							flag_enable_out1			; // 文字有效区域
wire							flag_enable_out2			; // 图片有效区域
wire							flag_clear_rom_address		; // 地址清零
wire							flag_begin_h			    ; // 图片显示行
wire							flag_begin_v			    ; // 图片显示列

//状态转移
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        states_current <= states_1;
    end
    else begin
        states_current <= states_next;
    end
end

//状态判断
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        states_next <= states_1;
    end
    else if ( key[ 0 ] ) begin
        states_next <= states_1;
    end
        else if ( key[ 1 ] ) begin
        states_next <= states_2;
        end
        else if ( key[ 2 ] ) begin
        states_next <= states_3;
        end
    else begin
        states_next <= states_next;
    end
end

//状态输出
always @( * ) begin
    case ( states_current )
        states_1 : begin
            if ( addr_h == 0 ) begin
                rgb_data = black;
            end
            else if ( addr_h >0 && addr_h <81 ) begin
                rgb_data = red;
            end
            else if ( addr_h >80 && addr_h <161 ) begin
                rgb_data = orange;
            end
            else if ( addr_h >160 && addr_h <241 ) begin
                rgb_data = yellow;
            end
            else if ( addr_h >240 && addr_h <321 ) begin
                rgb_data = green;
            end
            else if ( addr_h >320 && addr_h <401 ) begin
                rgb_data = blue;
            end
            else if ( addr_h >400 && addr_h <481 ) begin
                rgb_data = indigo;
            end
            else if ( addr_h >480 && addr_h <561 ) begin
                rgb_data = purple;
            end
            else if ( addr_h >560 && addr_h <641 ) begin
                rgb_data = white;
            end
            else begin
                rgb_data = black;
            end
            
        end
        states_2 : begin
            if ( flag_enable_out1 ) begin
                rgb_data = char_line[ addr_v-208 ][ 532 - addr_h ]? white:black;
            end
            else begin
                rgb_data = black;
            end
        end
        states_3 : begin
            if ( flag_enable_out2 ) begin
                rgb_data = rom_data;
            end
            else begin
                rgb_data = black;
            end
            
        end
        default: begin
            case ( addr_h )
                0 : rgb_data      = black;
                1 : rgb_data      = red;
                81 : rgb_data     = orange;
                161: rgb_data     = yellow;
                241: rgb_data     = green;
                321: rgb_data     = blue;
                401: rgb_data     = indigo;
                481: rgb_data     = purple;
                561: rgb_data     = white;
                default: rgb_data = rgb_data;
            endcase
        end
    endcase
end

assign flag_enable_out1 = states_current == states_2 && addr_h > 148 && addr_h < 533 && addr_v > 208  && addr_v < 273 ;
assign flag_begin_h     = addr_h > ( ( 640 - width ) / 2 ) && addr_h < ( ( 640 - width ) / 2 ) + width + 1;
assign flag_begin_v     = addr_v > ( ( 480 - height )/2 ) && addr_v <( ( 480 - height )/2 ) + height + 1;
assign flag_enable_out2 = states_current == states_3 && flag_begin_h && flag_begin_v;

//ROM地址计数器
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        rom_address <= 0;
    end
    else if ( flag_clear_rom_address ) begin //计数满清零
        rom_address <= 0;
    end
        else if ( flag_enable_out2 ) begin  //在有效区域内+1
        rom_address <= rom_address + 1;
        end
    else begin  //无效区域保持
        rom_address <= rom_address;
    end
end
assign flag_clear_rom_address = rom_address == height * width - 1;

//初始化显示文字
always@( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        char_line[0] = 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
        char_line[1] = 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
        char_line[2] = 384'h000000000000000000000002000000000000003000000000000000000000000000000004000000000000000000000000;
        char_line[3] = 384'h000000000003000000000003800000000000001C00000000000000000000200000000007000000000000000000020000;
        char_line[4] = 384'h00000000001F000000000001E00000000000000F00000000000000000000700000000007E00000000000001000030000;
        char_line[5] = 384'h0000000000FF800000000001F00000000000000F80000000000001FFFFFFF80000000007C00000000006001C0007C000;
        char_line[6] = 384'h000000001FFFC00000000000F800000000000007C000000000C000FFFFFFFC0000000007800000000003000E0007E000;
        char_line[7] = 384'h0000000FFFFC600000000000F800000000000003E000000000F000400000FE0000000007800000000003C00F0007C000;
        char_line[8] = 384'h00001FFFF8000000000000007800060000000003E0000000007800000003F00000000007800000000001E00F800F8000;
        char_line[9] = 384'h001FFFE3800000000020000078000F0000000001E0000000003C00000007800000000007800000000000F007C00F0000;
        char_line[10] = 384'h00000003800000000038000070001F8000000001E0000300003E0000E00E000000000007800000000000F807C01E0000;
        char_line[11] = 384'h0000000380000000003FFFFFFFFFFFC000000000C0000780001E00003C180000000000078000000000007C07C01C0000;
        char_line[12] = 384'h0000000380000400003FFFFFFFFFFFE00000000080000FC0001E00001F600000000000078000000000007C03E01C0000;
        char_line[13] = 384'h0000000380000E00003C0000000000000FFFFFFFFFFFFFE0001E00000FC00000000000078000000000007C03C0380000;
        char_line[14] = 384'h0000000380001F00003C00008000000007FFFFFFFFFFFFF0000E000007C00000000000078000000000003C03C0300000;
        char_line[15] = 384'h03FFFFFFFFFFFF80003C0000600000000200000000000000000C010007C00400000000078000010000003C03C0700000;
        char_line[16] = 384'h01FFFFFFFFFFFFC0003C00007800000000000400000000000000018003800F00000000078000038000603C0100600000;
        char_line[17] = 384'h0080000380000000003C00007C0000000000060000000000000001FFFFFFFF8000000007800007C00060180000C00180;
        char_line[18] = 384'h0000000380000000003C00007800000000000F0001800000000001FFFFFFFF800000000780000FE000600000008003C0;
        char_line[19] = 384'h0000000380000000003C00007800000000000F8000F00000000001C007800F000FFFFFFFFFFFFFF0007FFFFFFFFFFFE0;
        char_line[20] = 384'h0000000380010000003C00007800000000001FC0007C0000000001C007800F0007FFFFFFFFFFFFF8007FFFFFFFFFFFF0;
        char_line[21] = 384'h0003000380038000003C00007800000000003E00001E0000000001C007800F00000000078000000000E00000000007F8;
        char_line[22] = 384'h0003FFFFFFFFC000003C00007800000000007C00000F8000000401C007800F00000000078000000000E00000000007C0;
        char_line[23] = 384'h0003FFFFFFFFC000003C0000780000000000F8000007E000000701C007800F00000000078000000000E0000000000F00;
        char_line[24] = 384'h0003C00380038000003C0000700000000001F0000003F0003FFF81C007800F00000000078000000001E0000000000E00;
        char_line[25] = 384'h0003C00380038000003C0000700001000003E0000001FC001FFF81C007800F0000000007C000000001E0000000001800;
        char_line[26] = 384'h0003C00380038000003C000070000380000784000180FC000C0F01FFFFFFFF0000000007C000000003E0000000081000;
        char_line[27] = 384'h0003C00380038000003C0000700007C0000F040001E07E00000F01FFFFFFFF00000000074000000007E00000001C2000;
        char_line[28] = 384'h0003C00380038000003DFFFFFFFFFFE0001E040001F83E00000F01C007800F000000000F6000000007C7FFFFFFFE2000;
        char_line[29] = 384'h0003C00380038000003CFFFFFFFFFFF00038060001F81E00000F01C007800F000000000F600000000003FFFFFFFF0000;
        char_line[30] = 384'h0003FFFFFFFF8000003C4000740000000070020003E00E00000F01C007800F000000000F3000000000018000003F8000;
        char_line[31] = 384'h0003FFFFFFFF8000003C00007400000001C0030003C00C00000F01C007800F000000000F300000000000000000FC0000;
        char_line[32] = 384'h0003C00380038000003C0000F60000000300030003C00400000F01C007800F000000000E380000000000000001F00000;
        char_line[33] = 384'h0003C00380038000003C0000F60000000E00018007800000000F01C007800F000000001E180000000000000003C00000;
        char_line[34] = 384'h0003C0038003800000380000F20000000000018007800000000F01C007800F000000001E1C0000000000000007000000;
        char_line[35] = 384'h0003C0038003800000380000F3000000000000C00F000000000F01FFFFFFFF000000001E0C000000000000000C000000;
        char_line[36] = 384'h0003C0038003800000380000E3000000000000C00F000000000F01FFFFFFFF000000001C0E0000000000000138000000;
        char_line[37] = 384'h0003C0038003800000380000E3800000000000601E000000000F01C007800F000000003C0600000000000001E0000000;
        char_line[38] = 384'h0003C0038003800000780001E1800000000000701E000000000F01C007800F000000003C0700000000000001E0000300;
        char_line[39] = 384'h0003FFFFFFFF800000780001E1C00000000000303C000000000F01C007800F00000000780380000000000001F0000780;
        char_line[40] = 384'h0003FFFFFFFF800000780001C1C00000000000383C000000000F01C007800F00000000780380000000000001E0000FC0;
        char_line[41] = 384'h0003C0038003800000780003C0E000000000001C78000000000F01C007800F000000007001C000000FFFFFFFFFFFFFE0;
        char_line[42] = 384'h0003C0038003800000700003C0E000000000001C70000000000F01C007800F00000000F001E0000007FFFFFFFFFFFFF0;
        char_line[43] = 384'h000200038002000000700003807000000000000EF0000000000F01C007800F00000001E000E0000002000001E0000000;
        char_line[44] = 384'h000000038000000000700007807800000000000FE0000000000F01C007800F00000001E00070000000000001E0000000;
        char_line[45] = 384'h000000038000600000F00007803C000000000007C0000000000F01C007800F00000003C00078000000000001E0000000;
        char_line[46] = 384'h000000038000F00000E0000F001E000000000007C0000000000F01C007801F0000000780003C000000000001E0000000;
        char_line[47] = 384'h007FFFFFFFFFF80000E0000E001F00000000000FE0000000000F01C0078FFE0000000780001E000000000001E0000000;
        char_line[48] = 384'h003FFFFFFFFFFC0000E0001E000F80000000001FF0000000003F81C00700FE0000000F00000F000000000001E0000000;
        char_line[49] = 384'h001000038000000001C0003C0007C0000000003CF800000000F0C18004007E0000001E00000FC00000000001E0000000;
        char_line[50] = 384'h000000038000000001C000780003E000000000F83E00000001E0700000003C0000003C000007E00000000001E0000000;
        char_line[51] = 384'h0000000380000000018000F00003F800000001E01F80000007C0380000001000000078000003F80000000001E0000000;
        char_line[52] = 384'h0000000380000000038001E00001FC00000007C00FE000000F801E00000000000000F0000001FE0000000001E0000000;
        char_line[53] = 384'h0000000380000180030003C00000FF0000001F0007FC00001F800FE0000000040003C0000000FF8000000001E0000000;
        char_line[54] = 384'h00000003800003C00700070000007FE000003C0001FFC0001F0003FFE0007FFC0007800000007FF000000403E0000000;
        char_line[55] = 384'h00000003800007E006001E0000003FF80000F800007FFFF80E0000FFFFFFFFE0000E000000003FF8000007FFC0000000;
        char_line[56] = 384'h1FFFFFFFFFFFFFF00C00380000000FC00007C000001FFFF00600003FFFFFFFC0003C000000000FC0000001FFC0000000;
        char_line[57] = 384'h0FFFFFFFFFFFFFF80C00E00000000780001F00000003FFE000000003FFFFFF8000F00000000007000000003FC0000000;
        char_line[58] = 384'h0400000000000000180380000000030000F8000000007FC00000000003FFFF8003C00000000001000000001F80000000;
        char_line[59] = 384'h0000000000000000100E00000000000003C000000000078000000000000000000F000000000000000000000F00000000;
        char_line[60] = 384'h000000000000000020300000000000000C00000000000000000000000000000018000000000000000000000400000000;
        char_line[61] = 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
        char_line[62] = 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
        char_line[63] = 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
    end
end

//实例化ROM
rom	rom_inst (
.address ( rom_address ),
.clock ( vga_clk ),
.q ( rom_data )
);
endmodule // data_drive



key_debounce.v

module key_debounce(
	input 	wire	clk,
	input 	wire 	rst_n,
	input 	wire 	key,
	
	output 	reg 	flag,// 0抖动, 1抖动结束
	output 	reg	key_value//key抖动结束后的值
);

parameter MAX_NUM = 20'd1_000_000;

reg [19:0] delay_cnt;//1_000_000

reg key_reg;//key上一次的值

always @(posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		key_reg <= 1;
		delay_cnt <= 0;
	end
	
	else begin
		key_reg <= key;
		//当key为1 key 为0 表示按下抖动,开始计时
		if(key_reg  != key  ) begin 
		   delay_cnt <= MAX_NUM ;
		end
		else begin
		    if(delay_cnt > 0)
				delay_cnt <= delay_cnt -1;
			else
				delay_cnt <= 0;
		end
	end
end


//当计时完成,获取key的值
always @(posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		flag <= 0;
		key_value <= 1;
	end

	else begin
		
		// 计时完成 处于稳定状态,进行赋值
		if(delay_cnt == 1) begin
			flag <= 1;
			key_value <= key;
		end
		else begin
			flag <= 0;
			key_value <= key_value;
		end
	end
end
endmodule


vga_drive.v

module vga_dirve (input			wire						clk,            //系统时钟
                  input			wire						rst_n,          //复位
                  input			wire		[ 15:0 ]		rgb_data,       //16位RGB对应值
                  output			wire							vga_clk,    //vga时钟 25M
                  output			reg							h_sync,     //行同步信号
                  output			reg							v_sync,     //场同步信号
                  output			reg		[ 11:0 ]				addr_h, //行地址
                  output			reg		[ 11:0 ]				addr_v,  //列地址
                  output			wire		[ 4:0 ]				rgb_r,  //红基色
                  output			wire		[ 5:0 ]				rgb_g,  //绿基色
                  output			wire		[ 4:0 ]				rgb_b  //蓝基色
);

// 640 * 480 60HZ
localparam	 H_FRONT = 16; // 行同步前沿信号周期长
localparam	 H_SYNC  = 96; // 行同步信号周期长
localparam	 H_BLACK = 48; // 行同步后沿信号周期长
localparam	 H_ACT   = 640; // 行显示周期长
localparam	 V_FRONT = 11; // 场同步前沿信号周期长
localparam	 V_SYNC  = 2; // 场同步信号周期长
localparam	 V_BLACK = 31; // 场同步后沿信号周期长
localparam	 V_ACT   = 480; // 场显示周期长

// 800 * 600 72HZ
// localparam	 H_FRONT = 40; // 行同步前沿信号周期长
// localparam	 H_SYNC  = 120; // 行同步信号周期长
// localparam	 H_BLACK = 88; // 行同步后沿信号周期长
// localparam	 H_ACT   = 800; // 行显示周期长
// localparam	 V_FRONT = 37; // 场同步前沿信号周期长
// localparam	 V_SYNC  = 6; // 场同步信号周期长
// localparam	 V_BLACK = 23; // 场同步后沿信号周期长
// localparam	 V_ACT   = 600; // 场显示周期长


localparam	H_TOTAL = H_FRONT + H_SYNC + H_BLACK + H_ACT; // 行周期
localparam	V_TOTAL = V_FRONT + V_SYNC + V_BLACK + V_ACT; // 列周期

reg			[ 11:0 ]			cnt_h			; // 行计数器
reg			[ 11:0 ]			cnt_v			; // 场计数器
reg			[ 15:0 ]			rgb			; // 对应显示颜色值

// 对应计数器开始、结束、计数信号
wire							flag_enable_cnt_h			;
wire							flag_clear_cnt_h			;
wire							flag_enable_cnt_v			;
wire							flag_clear_cnt_v			;
wire							flag_add_cnt_v  			;
wire							valid_area      			;


// 25M时钟 行周期*场周期*刷新率 = 800 * 525* 60
wire							clk_25			;
// 50M时钟 1040 * 666 * 72
wire							clk_50			;
//PLL
pll	pll_inst (
	.areset ( ~rst_n ),
	.inclk0 ( clk ),
	.c0 ( clk_50 ), //50M
	.c1 ( clk_25 ) //25M
	);
//根据不同分配率选择不同频率时钟
assign vga_clk = clk_25;


// 行计数
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        cnt_h <= 0;
    end
    else if ( flag_enable_cnt_h ) begin
        if ( flag_clear_cnt_h ) begin
            cnt_h <= 0;
        end
        else begin
            cnt_h <= cnt_h + 1;
        end
    end
    else begin
        cnt_h <= 0;
    end
end
assign flag_enable_cnt_h = 1;
assign flag_clear_cnt_h  = cnt_h == H_TOTAL - 1;

// 行同步信号
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        h_sync <= 0;
    end
    else if ( cnt_h == H_SYNC - 1 ) begin // 同步周期时为1
        h_sync <= 1;
    end
        else if ( flag_clear_cnt_h ) begin // 其余为0
        h_sync <= 0;
        end
    else begin
        h_sync <= h_sync;
    end
end

// 场计数
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        cnt_v <= 0;
    end
    else if ( flag_enable_cnt_v ) begin
        if ( flag_clear_cnt_v ) begin
            cnt_v <= 0;
        end
        else if ( flag_add_cnt_v ) begin
            cnt_v <= cnt_v + 1;
        end
        else begin
            cnt_v <= cnt_v;
        end
    end
    else begin
        cnt_v <= 0;
    end
end
assign flag_enable_cnt_v = flag_enable_cnt_h;
assign flag_clear_cnt_v  = cnt_v == V_TOTAL - 1;
assign flag_add_cnt_v    = flag_clear_cnt_h;

// 场同步信号
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        v_sync <= 0;
    end
    else if ( cnt_v == V_SYNC - 1 ) begin
        v_sync <= 1;
    end
        else if ( flag_clear_cnt_v ) begin
        v_sync <= 0;
        end
    else begin
        v_sync <= v_sync;
    end
end

// 对应有效区域行地址 1-640
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        addr_h <= 0;
    end
    else if ( valid_area ) begin
        addr_h <= cnt_h - H_SYNC - H_BLACK + 1;
    end
    else begin
        addr_h <= 0;
    end
end
// 对应有效区域列地址 1-480
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        addr_v <= 0;
    end
    else if ( valid_area ) begin
        addr_v <= cnt_v -V_SYNC - V_BLACK + 1;
    end
    else begin
        addr_v <= 0;
    end
end
// 有效显示区域
assign valid_area = cnt_h >= H_SYNC + H_BLACK && cnt_h <= H_SYNC + H_BLACK + H_ACT && cnt_v >= V_SYNC + V_BLACK && cnt_v <= V_SYNC + V_BLACK + V_ACT;


// 显示颜色
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        rgb <= 16'h0;
    end
    else if ( valid_area ) begin
        rgb <= rgb_data;
    end
    else begin
        rgb <= 16'b0;
    end
end
assign rgb_r = rgb[ 15:11 ];
assign rgb_g = rgb[ 10:5 ];
assign rgb_b = rgb[ 4:0 ];

endmodule // vga_dirve

vga_top.v

module vga_top (input			wire						clk,
                input			wire						rst_n,
                input			wire		[ 2:0 ]		    key,
                output			wire						vga_clk,
                output			wire						h_sync,
                output			wire						v_sync,
                output			wire		[ 4:0 ]			rgb_r,
                output			wire		[ 5:0 ]			rgb_g,
                output			wire		[ 4:0 ]			rgb_b,
                output			reg		    [ 3:0 ]			led);

reg			[ 27:0 ]			cnt			        ;
wire		[ 11:0 ]		    addr_h              ;
wire		[ 11:0 ]		    addr_v              ;
wire		[ 15:0 ]			rgb_data			;
wire		[ 2:0 ]			    key_flag			;
wire		[ 2:0 ]			    key_value			;

//vga模块
vga_dirve u_vga_dirve(
.clk      ( clk ),
.rst_n    ( rst_n ),
.rgb_data ( rgb_data ),
.vga_clk  ( vga_clk ),
.h_sync   ( h_sync ),
.v_sync   ( v_sync ),
.rgb_r    ( rgb_r ),
.rgb_g    ( rgb_g ),
.rgb_b    ( rgb_b ),
.addr_h   ( addr_h ),
.addr_v   ( addr_v )
);

//数据模块
data_drive u_data_drive(
.vga_clk ( vga_clk ),
.rst_n   ( rst_n ),
.addr_h  ( addr_h ),
.addr_v  ( addr_v ),
.key     ( {key_value[ 2 ] && key_flag[ 2 ], key_value[ 1 ] && key_flag[ 1 ], key_value[ 0 ] && key_flag[ 0 ] } ),
.rgb_data  ( rgb_data )
);


//按键消抖
key_debounce u_key_debounce0(
.clk   ( vga_clk ),
.rst_n ( rst_n ),
.key   ( key[ 0 ] ),
.flag  ( key_flag[ 0 ] ),
.key_value  ( key_value[ 0 ] )
);

key_debounce u_key_debounce1(
.clk   ( vga_clk ),
.rst_n ( rst_n ),
.key   ( key[ 1 ] ),
.flag  ( key_flag[ 1 ] ),
.key_value  ( key_value[ 1 ] )
);

key_debounce u_key_debounce2(
.clk   ( vga_clk ),
.rst_n ( rst_n ),
.key   ( key[ 2 ] ),
.flag  ( key_flag[ 2 ] ),
.key_value  ( key_value[ 2 ] )
);

// led
always @( posedge clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        cnt <= 0;
    end
    else if ( cnt == 50_000_000 - 1 ) begin
        cnt <= 0;
    end
    else begin
        cnt <= cnt + 1;
    end
end
always @( posedge clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        led <= 4'b0000;
    end
    else if ( cnt == 50_000_000 -1 )begin
        led <= ~led;
    end
    else begin
        led <= led;
    end
end
endmodule // vga_top


三.实验结果

请添加图片描述

  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是基于DE2-115平台VGA显示图片的详细步骤: 1. 打开Quartus II软件,创建一个新工程。 2. 在工程中添加一个VHDL文件,用于实现VGA控制器。下面是一个简单的VGA控制器代码示例: ``` library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity VGA_Controller is Port ( clk : in STD_LOGIC; h_sync : out STD_LOGIC; v_sync : out STD_LOGIC; red : out STD_LOGIC_VECTOR (3 downto 0); green : out STD_LOGIC_VECTOR (3 downto 0); blue : out STD_LOGIC_VECTOR (3 downto 0); x : out STD_LOGIC_VECTOR (9 downto 0); y : out STD_LOGIC_VECTOR (9 downto 0)); end VGA_Controller; architecture Behavioral of VGA_Controller is signal vga_clk : std_logic; signal h_count : integer range 0 to 799 := 0; signal v_count : integer range 0 to 524 := 0; begin vga_clk <= clk; process(vga_clk) begin if rising_edge(vga_clk) then if h_count = 799 then h_count <= 0; if v_count = 524 then v_count <= 0; else v_count <= v_count + 1; end if; else h_count <= h_count + 1; end if; end if; end process; h_sync <= '1' when (h_count >= 656 and h_count <= 752) else '0'; v_sync <= '1' when (v_count >= 490 and v_count <= 492) else '0'; red <= "1111"; green <= "0000"; blue <= "0000"; x <= std_logic_vector(to_unsigned(h_count, 10)); y <= std_logic_vector(to_unsigned(v_count, 10)); end Behavioral; ``` 这个VGA控制器代码示例中,使用了默认的640x480分辨率和60Hz刷新率。其中,h_sync和v_sync分别表示水平同步信号和垂直同步信号,red、green和blue分别表示红、绿、蓝三个颜色通道,x和y表示当前像素的坐标。 3. 在工程中添加一个图片文件,将其转换为灰度图像并调整分辨率为640x480。可以使用Matlab等工具进行图像处理和转换。 4. 在VGA控制器代码中添加一个ROM模块,用于存储转换后的图像数据。下面是一个简单的ROM模块代码示例: ``` library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity ROM is Port ( clk : in STD_LOGIC; address : in STD_LOGIC_VECTOR (17 downto 0); data : out STD_LOGIC_VECTOR (7 downto 0)); end ROM; architecture Behavioral of ROM is type ROM_array is array (0 to 307199) of std_logic_vector(7 downto 0); constant ROM_data : ROM_array := ( -- 图像数据 ); begin process(clk) begin if rising_edge(clk) then data <= ROM_data(to_integer(unsigned(address))); end if; end process; end Behavioral; ``` 在ROM模块中,使用一个ROM_array类型的常量存储转换后的图像数据,通过address输入读取对应的像素数据。 5. 在VGA控制器代码中,将ROM模块的输出与红、绿、蓝三个颜色通道连接起来,实现将像素数据输出到VGA显示器。 6. 在Quartus II软件中,进行引脚分配,将VGA控制器的输出信号与DE2-115板子上的VGA接口相连。 7. 编译工程生成.sof文件,并将其下载到DE2-115板子中。 完成以上步骤后,即可在DE2-115VGA显示器上看到输出的图像。需要注意的是,因为DE2-115FPGA资源有限,可能无法一次性显示完整的640x480分辨率的图像。可以将图像分成若干个区域分别输出,或者降低分辨率以适应FPGA资源。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值