文章目錄
- 一、VGA介紹
- 1.1 VGA原理
- 1.2VGA電路
- 二、配置
- 三、實現
- 3.1 字符顯示
- 3.2圖片顯示
- 四、代碼
- 4.1.vga驅動模塊
- 4.2數據模塊
- 4.3按鍵消抖模塊
- 4.4頂層模塊
- 4.5TCL引腳綁定
- 參考
一、VGA介紹
1.1 VGA原理
VGA接口
最主要的幾根線:
VGA其實就是相當于一塊芯片,跟單片機驅動IC一樣,滿足一定的時序,便能驅動起來。VGA的掃描其實很簡單,大致軌跡如下所示:
每掃描完一行,從新開始下一行;每掃完一場,重新開始下一場。
以下是行掃描,場掃描HS,VS時序圖
VS時序如下所示:
可見時序的循環,可被劃分為a,b,c,d4個時期。這四個時期定義如下:
A~B:場消隱期 即同步,相當于還原掃描坐標吧
B~C:場消隱后肩 相當于準備開始掃描吧
C~D:場顯示期 掃描中,數據有效區域
D~E:場消隱前肩 完成掃描,相當于準備同步
HS時序深入分析
可見時序的循環,可被劃分為a,b,c,d4個時期。這四個時期定義如下:
A~B:行消隱期 即同步,相當于還原掃描坐標吧
B~C:行消隱后肩 相當于準備開始掃描吧
C~D:行顯示期 掃描中,數據有效區域
D~E:行消隱前肩 完成掃描,相當于準備同步
綜上描述,我們只要知道每個時期的時間,便可以表示出VGA的時序。而FPGA的工作是由固定頻率的時鐘觸發的,因此某固定時間可以用n次觸發來表示。因此我們很容易就想到了FPGA常用的計數方法:比如說行掃描,我們計數0~H_total-1。用另一個進程將其劃分為4個時期,安標注分配。其實這相當于狀態機。
1.2VGA電路
VGA接口:R,G,B三通道,直接賦給數字信號,RGB,最多產生8種色彩。這是最基本的。電路如下所示:
二、配置
打開Quartus,選擇IP核
命名之后,將基礎時鐘改為50M
點擊next后,取消該勾選
默認next,直到該界面,c0默認輸出50M即可,c1分頻到25M,如需其他時鐘頻率可以自己進行設置
勾選,finish
三、實現
3.1 字符顯示
字模軟件
百度網盤:
https://pan.baidu.com/s/1542q14FRzCawo8WNp8J-Kg
提取碼: jdzg
在子模提取工具里面輸入需要顯示的字符并設置字符大小為64*64
然后點擊文件-另存為,把圖片保存為BMP圖片,再點擊文件-打開,把保存的BMP圖片打開得到整體的字符。
參數設置
保存為.txt格式
將得到的字模替換。
3.2圖片顯示
想要顯示的圖片,但是圖片的大小超過了芯片的內存,無法把圖片保存進去,故采用一張100*100的圖片進行顯示。
使用工具把圖片轉為HEX文件
工具鏈接: https://pan.baidu.com/s/1o8ii9ei密碼:62uv
圖片數據太多需要使用ROM來存儲數據
打開quartus,找到ROM
取消勾選下列選項
剛才生成的,hex
finish
四、代碼
4.1.vga驅動模塊
module vga_dirve (input wire clk, //系統時鐘input wire rst_n, //復位input wire [ 15:0 ] rgb_data, //16位RGB對應值output wire vga_clk, //vga時鐘 25Moutput 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 ) beginif ( !rst_n ) begincnt_h <= 0;endelse if ( flag_enable_cnt_h ) beginif ( flag_clear_cnt_h ) begincnt_h <= 0;endelse begincnt_h <= cnt_h + 1;endendelse begincnt_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 ) beginif ( !rst_n ) beginh_sync <= 0;endelse if ( cnt_h == H_SYNC - 1 ) begin // 同步周期時為1h_sync <= 1;endelse if ( flag_clear_cnt_h ) begin // 其余為0h_sync <= 0;endelse beginh_sync <= h_sync;end
end// 場計數
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) begincnt_v <= 0;endelse if ( flag_enable_cnt_v ) beginif ( flag_clear_cnt_v ) begincnt_v <= 0;endelse if ( flag_add_cnt_v ) begincnt_v <= cnt_v + 1;endelse begincnt_v <= cnt_v;endendelse begincnt_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 ) beginif ( !rst_n ) beginv_sync <= 0;endelse if ( cnt_v == V_SYNC - 1 ) beginv_sync <= 1;endelse if ( flag_clear_cnt_v ) beginv_sync <= 0;endelse beginv_sync <= v_sync;end
end// 對應有效區域行地址 1-640
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) beginaddr_h <= 0;endelse if ( valid_area ) beginaddr_h <= cnt_h - H_SYNC - H_BLACK + 1;endelse beginaddr_h <= 0;end
end
// 對應有效區域列地址 1-480
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) beginaddr_v <= 0;endelse if ( valid_area ) beginaddr_v <= cnt_v -V_SYNC - V_BLACK + 1;endelse beginaddr_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 ) beginif ( !rst_n ) beginrgb <= 16'h0;endelse if ( valid_area ) beginrgb <= rgb_data;endelse beginrgb <= 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
4.2數據模塊
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[ 89: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 ) beginif ( !rst_n ) beginstates_current <= states_1;endelse beginstates_current <= states_next;end
end//狀態判斷
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) beginstates_next <= states_1;endelse if ( key[ 0 ] ) beginstates_next <= states_1;endelse if ( key[ 1 ] ) beginstates_next <= states_2;endelse if ( key[ 2 ] ) beginstates_next <= states_3;endelse beginstates_next <= states_next;end
end//狀態輸出
always @( * ) begincase ( states_current )states_1 : beginif ( addr_h == 0 ) beginrgb_data = black;endelse if ( addr_h >0 && addr_h <81 ) beginrgb_data = red;endelse if ( addr_h >80 && addr_h <161 ) beginrgb_data = orange;endelse if ( addr_h >160 && addr_h <241 ) beginrgb_data = yellow;endelse if ( addr_h >240 && addr_h <321 ) beginrgb_data = green;endelse if ( addr_h >320 && addr_h <401 ) beginrgb_data = blue;endelse if ( addr_h >400 && addr_h <481 ) beginrgb_data = indigo;endelse if ( addr_h >480 && addr_h <561 ) beginrgb_data = purple;endelse if ( addr_h >560 && addr_h <641 ) beginrgb_data = white;endelse beginrgb_data = black;endendstates_2 : beginif ( flag_enable_out1 ) beginrgb_data = char_line[ addr_v-208 ][ 532 - addr_h ]? white:black;endelse beginrgb_data = black;endendstates_3 : beginif ( flag_enable_out2 ) beginrgb_data = rom_data;endelse beginrgb_data = black;endenddefault: begincase ( 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;endcaseendendcase
endassign 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 ) beginif ( !rst_n ) beginrom_address <= 0;endelse if ( flag_clear_rom_address ) begin //計數滿清零rom_address <= 0;endelse if ( flag_enable_out2 ) begin //在有效區域內+1rom_address <= rom_address + 1;endelse 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 ) beginif ( !rst_n ) beginchar_line[0]= 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;char_line[1]= 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;char_line[2]= 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;char_line[3]= 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;char_line[4]= 384'h000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000;char_line[5]= 384'h0000000000000000000000000000000000000000000000000000000000000000000000000E0000000000000400000000;char_line[6]= 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;char_line[7]= 384'h00000000000004000F8000000100000E0000080000000000000000000000000000000000000000000000000000000000;char_line[8]= 384'h00000000000000000000000000000000000000000000000003000E000F8000000180001F0C001C000000000000000000;char_line[9]= 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003FFFF00;char_line[10]= 384'h0F00000001FFFFFF0FFFFF00000000000000000000000000000000000000000000000000000000000000000000000000;char_line[11]= 384'h0000000000000000000000000000000003FFFF001F00000001FFFFFF8FFFFF0000000000000000000000000000000000;char_line[12]= 384'h00000000000000000000000000000000000000000000000000000000000000000000000003C01E001E00000001E00F00;char_line[13]= 384'h0F001C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;char_line[14]= 384'h000000000000000003C01C001E00000001E00F000F001C00000000000000000000000000000000000000000000000000;char_line[15]= 384'h0000000000000000000000000000000000000000000000000000000003C03C003C00030001E00F000F001C0000000000;char_line[16]= 384'h0001FC00000FE000000FF000000040000007E00003FFFFF00007E0000001FC000007E00000000E00000FE00000004000;char_line[17]= 384'h03C038003C00078001E00F000F001C00000000000007FF00007FF800003FFE000000C000001FF80007FFFFF0001FF800;char_line[18]= 384'h0007FF00001FF80000000E00007FF8000000C00003C039FFFFFFFFC001E00F000F001C0000000000001E078000E07C00;char_line[19]= 384'h00F81F000001C000003C1E0007FFFFF0003C1E00001E0780003C1E0000001E0000E07C000001C00003C070FFFFFFFFE0;char_line[20]= 384'h01E00F000F001C0000000000003803C001801E0001E007800007C00000700F0007FFFFE000700F00003803C000700F00;char_line[21]= 384'h00003E0001801E000007C00003C070407800000001E00F080F001C0000000000007003E003000F0003C003C001FFC000;char_line[22]= 384'h00E0070007C000C000E00700007003E000E0070000003E0003000F0001FFC00003C060007000000001E30F1C0F001C00;char_line[23]= 384'h0000000000E003E003000780078001E001FFC00001E00380070000C001E0038000E003E001E0038000007E0003000780;char_line[24]= 384'h01FFC00003C0E000F000000001E3FFFE0F001C000000000001C003E007000780070001E00007C00003C003C006000180;char_line[25]= 384'h03C003C001C003E003C003C00000FE00070007800007C00003C0E000E000000001E3FFFE0F001C0000000000038003E0;char_line[26]= 384'h070007C0070000F00003C00003C001C00600018003C001C0038003E003C001C00000DE00070007C00003C00003C0C001;char_line[27]= 384'hE000000001E3C01C0F001C0000000000038001C0078003C00F0000F00003C000078001E00C000300078001E0038001C0;char_line[28]= 384'h078001E000019E00078003C00003C00003C0C001C0E0000001E3C01C0F001C000000000007000000078003C00F8000F0;char_line[29]= 384'h0003C000078000E00C000300078000E007000000078000E000039E00078003C00003C00003C18003C0F8000001E3C01C;char_line[30]= 384'h0FFFFC000000000007000000078003C00F8000F00003C000070000E00C000600070000E007000000070000E000031E00;char_line[31]= 384'h078003C00003C00003C1800380F8000001E3C01C0FFFFC000000000007000000030003C00FC000F00003C0000F0000F0;char_line[32]= 384'h000006000F0000F0070000000F0000F000071E00030003C00003C00003C1000380F0000001E3C01C0F001C0000000000;char_line[33]= 384'h0F000000000003C00FC000F00003C0000F0000F000000C000F0000F00F0000000F0000F000061E00000003C00003C000;char_line[34]= 384'h03C3000780F0000001E3C01C0F001C00000000000F000000000003C00FC000F00003C0000F0000F000001C000F0000F0;char_line[35]= 384'h0F0000000F0000F0000C1E00000003C00003C00003C1000700F0000001E3C01C0F001800000000000E00000000000780;char_line[36]= 384'h078001E00003C0000F000070000018000F0000700E0000000F000070001C1E00000007800003C00003C0800F00F00000;char_line[37]= 384'h01E3C01C0F000000000000000E00000000000780000001E00003C0001E000078000038001E0000780E0000001E000078;char_line[38]= 384'h00181E00000007800003C00003C0C00E00F0000001E3FFFC0F000000000000000E03F80000000F00000001E00003C000;char_line[39]= 384'h1E000078000038001E0000780E03F8001E00007800301E0000000F000003C00003C0601E00F0010001E3FFFC0F000000;char_line[40]= 384'h000000001E0FFF0000000E00000003C00003C0001E000078000030001E0000781E0FFF001E00007800701E0000000E00;char_line[41]= 384'h0003C00003C0301C00F0030001E3CF1C0F000000000000001E3FFF8000003C00000003C00003C0001E00007800007000;char_line[42]= 384'h1E0000781E3FFF801E00007800601E0000003C000003C00003C0383C00F0078001E38F180F0001803FFFFFFC1E7C0FC0;char_line[43]= 384'h0000F800000007800003C0001E000078000070001E0000781E7C0FC01E00007800C01E000000F8000003C00003C01C7F;char_line[44]= 384'hFFFFFFC001E20F000F0001803FFFFFFC1EF003E0000FE00000000F000003C0001E0000780000E0001E0000781EF003E0;char_line[45]= 384'h1E00007801C01E00000FE0000003C00003C01CFFFFFFFFE001E00F000F000180000000001EE001E0000FF80000000E00;char_line[46]= 384'h0003C0001E0000780000E0001E0000781EE001E01E00007801801E00000FF8000003C00003C01E7800F0000001E00F00;char_line[47]= 384'h0F000180000000001FC001F000007C0000001C000003C0001E0000780001E0001E0000781FC001F01E00007803001E00;char_line[48]= 384'h00007C000003C00003C00E3000F0000001E00F000F000180000000001F8000F000000F00000038000003C0001E000078;char_line[49]= 384'h0001C0001E0000781F8000F01E00007803001E0000000F000003C00003C00E0000F0000001E00F000F00018000000000;char_line[50]= 384'h1F0000F000000780000070000003C0001E0000780003C0001E0000781F0000F01E00007806001E00000007800003C000;char_line[51]= 384'h03C00E0000F0000001E00F000F000180000000001F000078000003C00000E0000003C0001E0000780003C0001E000078;char_line[52]= 384'h1F0000781E0000780E001E00000003C00003C00003C00F0080F0000001E00F000F0001C0000000001E000078000001C0;char_line[53]= 384'h0001C0000003C0001E000078000380001E0000781E0000781E0000780C001E00000001C00003C00003C00F01E0F00000;char_line[54]= 384'h01E00F030F8003E0000000001E000078000001E0000380000003C0001E000078000780001E0000781E0000781E000078;char_line[55]= 384'h18001E00000001E00003C00003C00F01F0F1000001E00F0787FFFFE0000000001E000078000000E0000700000003C000;char_line[56]= 384'h1E000078000780001E0000781E0000781E00007838001E00000000E00003C00003C00E03F8F0C00003FFFFFFC7FFFFE0;char_line[57]= 384'h000000001E000078000000F0000E00000003C0000F000070000780000F0000701E0000780F0000703FFFFFFC000000F0;char_line[58]= 384'h0003C00003E01E03E0F0600001FFFFFFE1FFFF80000000001E000078000000F0001C00000003C0000F0000F0000F8000;char_line[59]= 384'h0F0000F01E0000780F0000F03FFFFFFC000000F00003C00003DFFE07C0F0380000C0000000000000000000000E000078;char_line[60]= 384'h000000F0003800000003C0000F0000F0000F80000F0000F00E0000780F0000F000001E00000000F00003C00003C7FC07;char_line[61]= 384'h80F01C000000000000000000000000000F000078038000F0007000000003C0000F0000F0000F80000F0000F00F000078;char_line[62]= 384'h0F0000F000001E00038000F00003C00003C3F80F00F00E000000000000000000000000000F00007807C000F000E00030;char_line[63]= 384'h0003C000070000E0000F8000070000E00F000078070000E000001E0007C000F00003C00003C1F01E00F00F8000000000;char_line[64]= 384'h00000000000000000F0000700FC000F001C000300003C000078001E0000F8000078001E00F000070078001E000001E00;char_line[65]= 384'h0FC000F00003C00003C0C01E00F007C0000000002000C00000000000070000F00FC000F0038000300003C000078001E0;char_line[66]= 384'h001F8000078001E0070000F0078001E000001E000FC000F00003C00003C0003C00F003C000180C003000700000000000;char_line[67]= 384'h078000F00FC001E0078000300003C00003C001C0001F800003C001C0078000F003C001C000001E000FC001E00003C000;char_line[68]= 384'h03C0007800F003E0001806001C0038000000000003C000E00F8001E0070000600003C00003C003C0001F800003C003C0;char_line[69]= 384'h03C000E003C003C000001E000F8001E00003C00003C000F000F001E0001807000E003C000000000003C001E0078003C0;char_line[70]= 384'h0E0000E00003C00001E00380001F800001E0038003C001E001E0038000001E00078003C00003C00003C000E000F001F0;char_line[71]= 384'h003803800F001E000000000001E001C0078003801C0001E00003C00000E00700001F800000E0070001E001C000E00700;char_line[72]= 384'h00001E00078003800003C00003C001C000F000F0003803C007801F000000000000F0038003C007001FFFFFE00007E000;char_line[73]= 384'h00700F00001F800000700F0000F0038000700F0000001E0003C007000007E00003C0038000F000E0007803E007800F00;char_line[74]= 384'h00000000007C0F0001F01E001FFFFFE0000FF000003C1E00001F8000003C1E00007C0F00003C1E0000003F0001F01E00;char_line[75]= 384'h000FF00003C0070000F0006000F001E007C00F8000000000003FFE00007FFC001FFFFFE001FFFF80001FF800001F8000;char_line[76]= 384'h001FF800003FFE00001FF800000FFFF8007FFC0001FFFF8003C00C0000F0000000F001E003C00F80000000000007F000;char_line[77]= 384'h001FE0001FFFFFE001FFFF800007E000000F00000007E0000007F0000007E000000FFFF8001FE00001FFFF8003C01801;char_line[78]= 384'hF0F0000001F001E003C00780000000000000000000000000000000000000000000000000000000000000000000000000;char_line[79]= 384'h0000000000000000000000000000000003C020007FF0000007E001E00380078000000000000000000000000000000000;char_line[80]= 384'h00000000000000000000000000000000000000000000000000000000000000000000000003C000001FE0000007E000C0;char_line[81]= 384'h030007000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;char_line[82]= 384'h000000000000000003C0000007E000000380008000000200000000000000000000000000000000000000000000000000;char_line[83]= 384'h0000000000000000000000000000000000000000000000000000000003C0000003C00000000000000000000000000000;char_line[84]= 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;char_line[85]= 384'h038000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000;char_line[86]= 384'h000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000;char_line[87]= 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;char_line[88]= 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;char_line[89]= 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;end
end//實例化ROM
rom rom_inst (
.address ( rom_address ),
.clock ( vga_clk ),
.q ( rom_data )
);
endmodule // data_drive
4.3按鍵消抖模塊
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_000reg key_reg;//key上一次的值always @(posedge clk or negedge rst_n) beginif(!rst_n) beginkey_reg <= 1;delay_cnt <= 0;endelse beginkey_reg <= key;//當key為1 key 為0 表示按下抖動,開始計時if(key_reg != key ) begin delay_cnt <= MAX_NUM ;endelse beginif(delay_cnt > 0)delay_cnt <= delay_cnt -1;elsedelay_cnt <= 0;endend
end//當計時完成,獲取key的值
always @(posedge clk or negedge rst_n) beginif(!rst_n) beginflag <= 0;key_value <= 1;endelse begin// 計時完成 處于穩定狀態,進行賦值if(delay_cnt == 1) beginflag <= 1;key_value <= key;endelse beginflag <= 0;key_value <= key_value;endend
endendmodule
4.4頂層模塊
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 ) beginif ( !rst_n ) begincnt <= 0;endelse if ( cnt == 50_000_000 - 1 ) begincnt <= 0;endelse begincnt <= cnt + 1;end
end
always @( posedge clk or negedge rst_n ) beginif ( !rst_n ) beginled <= 4'b0000;endelse if ( cnt == 50_000_000 -1 )beginled <= ~led;endelse beginled <= led;end
end
endmodule // vga_top
4.5TCL引腳綁定
package require ::quartus::projectset_location_assignment PIN_E1 -to clk
set_location_assignment PIN_E15 -to rst_n
set_location_assignment PIN_C16 -to h_sync
set_location_assignment PIN_D15 -to v_syncset_location_assignment PIN_E16 -to key[0]
set_location_assignment PIN_M16 -to key[1]
set_location_assignment PIN_M15 -to key[2]set_location_assignment PIN_G15 -to led[0]
set_location_assignment PIN_F16 -to led[1]
set_location_assignment PIN_F15 -to led[2]
set_location_assignment PIN_D16 -to led[3]set_location_assignment PIN_A14 -to rgb_b[4]
set_location_assignment PIN_B14 -to rgb_b[3]
set_location_assignment PIN_A15 -to rgb_b[2]
set_location_assignment PIN_B16 -to rgb_b[1]
set_location_assignment PIN_C15 -to rgb_b[0]set_location_assignment PIN_A11 -to rgb_g[5]
set_location_assignment PIN_B11 -to rgb_g[4]
set_location_assignment PIN_A12 -to rgb_g[3]
set_location_assignment PIN_B12 -to rgb_g[2]
set_location_assignment PIN_A13 -to rgb_g[1]
set_location_assignment PIN_B13 -to rgb_g[0]set_location_assignment PIN_C8 -to rgb_r[4]
set_location_assignment PIN_A9 -to rgb_r[3]
set_location_assignment PIN_B9 -to rgb_r[2]
set_location_assignment PIN_A10 -to rgb_r[1]
set_location_assignment PIN_B10 -to rgb_r[0]
參考
``
https://blog.csdn.net/weixin_51755670/article/details/118076488
https://blog.csdn.net/qq_45659777/article/details/124834294