您现在的位置是:首页 >其他 >基于DE2-115平台实现VGA显示器的显示实验网站首页其他
基于DE2-115平台实现VGA显示器的显示实验
什么是VGA协议
这一部分摘录自野火的征途Pro《FPGA Verilog开发实战指南——基于Altera EP4CE10》2021.7.10(上)
VGA,英文全称“Video Graphics Array”,译为视频图形阵列,是一种使用模拟信号进行视频传输的标准协议,由 IBM 公司于 1987 年推出,因其分辨率高、显示速度快、颜色丰富等优点,广泛应用于彩色显示器领域。
下图是野火书中的VGA插头图片:
下面是引脚定义,一样来自野火的书:
VGA显示原理
VGA显示屏显示图片时,是将图片的像素点在行同步信号与场同步信号的作用下,从上往下,从左往右扫描到屏幕上。
VGA显示器首先从最左上角的像素开始,向右进行扫描。每完成一行图像扫描就进行图像消隐,并将扫描坐标变为下一行最左边的像素。扫描完最后一行时,会完成一帧图像的扫描,扫描坐标重新回到左上角。
扫描的速度非常快,即使每次扫描的时候是显示一个像素点,对于人眼来说看到的是完整的一帧图像。
VGA时序图
VGA参数图
详细的原理笔者还没有弄清楚,做本次实验的时候更多的是在学长的作业上依葫芦画瓢。对于原理部分就写这些,下面是实验记录。
实验记录
本次实验主要参考的是这位学长(学姐)的博客,大家有兴趣可以看看:https://blog.csdn.net/qq_47281915/article/details/125134764
准备PLL
实验要使用到640×480 60HZ,所以需要一个25MHz的时钟,而DE2-115平台的fpga时钟频率是50MHz,因此要使用锁相环PLL来分频,得到25MHz时钟。
然后按照下面的图的指示配置PLL,注意我配置了两个时钟输出c0与c1,一个输出25MHz时钟,另一个输出50MHz时钟。
ROM
由于实验要求显示图片,因此要先将图片数据保存到fpga中。
因此,使用到了另外一个IP核:ROM。
但是在配置ROM之前,要先找到你要保存的图片,将它转化为mif文件。
比如我有这么一张64*64大小的bmp图片。
要把它保存到fpga中,先生成它的mif文件。
使用bmp2mif程序:
这个程序会默认在桌面生成mif文件。
然后配置ROM核:
改模块名称:
然后按照下图配置:
图片显示部分的相关工作到这里结束,下面是文字显示的准备工作。
取模
要在vga显示屏上显示字符,需要完成字符取模。
使用字符取模程序PCtoLCD2002:
位图图片保存好后,左上角重新将其导入。
点击选项,按下图配置:
点击生成字模,将其保存备用:
代码
下面是实验中各个模块的代码:
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
实验现象