• 方案介紹
    • 1. 方案選擇
    • 2. 系統(tǒng)設(shè)計(jì)
    • 3. 模塊設(shè)計(jì)
    • 4. 代碼調(diào)試遇到的問題
  • 相關(guān)推薦
申請入駐 產(chǎn)業(yè)圖譜

吃豆人游戲VGA顯示VHDL代碼basys3開發(fā)板帶設(shè)計(jì)報告

加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

名稱:吃豆人游戲VGA顯示VHDL代碼basys3開發(fā)板設(shè)計(jì)報告(代碼在文末下載)

軟件:VIVADO

語言:VHDL

代碼功能:

本設(shè)計(jì)是一個基于VGA的吃豆人游戲,玩家可以控制屏幕上的吃豆人吃散落在屏幕各個方位的豆子,同時屏幕上還有2個魔鬼,如果吃豆人和魔鬼相遇,則游戲失敗。

設(shè)計(jì)的基本要求是魔鬼的移動方式固定,且用固定得到圓形或者方形來表示不同的對象??紤]到該實(shí)現(xiàn)方案較為簡單,為使顯示更加美觀,在屏幕上添加墻壁,劃分出不同的路線。吃豆人和魔鬼也不使用固定圓形或者方形,而是用較為形象的圖案,可以體現(xiàn)出眼睛嘴巴等特征。

同時為了記錄游戲得分,添加數(shù)碼管顯示部分。

系統(tǒng)控制魔鬼在所劃分的道路上巡邏,玩家通過Basys3板子上的上下左右按鍵控制吃豆人吃豆子以及規(guī)避魔鬼。

FPGA代碼Verilog/VHDL代碼資源下載:www.hdlcode.com

本代碼已在Basys3開發(fā)板驗(yàn)證,開發(fā)板如下,其他開發(fā)板可以修改管腳適配:

basys3開發(fā)板.png

1. 方案選擇

本設(shè)計(jì)是一個基于VGA的吃豆人游戲,玩家可以控制屏幕上的吃豆人吃散落在屏幕各個方位的豆子,同時屏幕上還有2個魔鬼,如果吃豆人和魔鬼相遇,則游戲失敗。

設(shè)計(jì)的基本要求是魔鬼的移動方式固定,且用固定得到圓形或者方形來表示不同的對象。

考慮到該實(shí)現(xiàn)方案較為簡單,為使顯示更加美觀,在屏幕上添加墻壁,劃分出不同的路線。

吃豆人和魔鬼也不使用固定圓形或者方形,而是用較為形象的圖案,可以體現(xiàn)出眼睛嘴巴等特征。

同時為了記錄游戲得分,添加數(shù)碼管顯示部分。

系統(tǒng)控制魔鬼在所劃分的道路上巡邏,玩家通過Basys3板子上的上下左右按鍵控制吃豆人吃豆子以及規(guī)避魔鬼。

2. 系統(tǒng)設(shè)計(jì)

系統(tǒng)的整體設(shè)計(jì)框圖如下圖所示,輸入端口包括時鐘、復(fù)位、四個上下左右按鍵。輸出端口包括VGA的HSYNC、VSYNC信號,顏色RGB信號以及用于數(shù)碼管控制的位選(bit_sel)和段選信號(semgnet)。

系統(tǒng)包括分頻模塊(clk_wizard)、按鍵模塊(io)、圖像控制模塊(picture_ctrl)、VGA時序控制模塊(vga_driver)和數(shù)碼管控制模塊(ssd_controller)。其中分頻模塊用于分頻產(chǎn)生其他模塊的工作時鐘,按鍵模塊實(shí)現(xiàn)按鍵消抖功能,并將按鍵信號輸出給圖像控制模塊。圖像控制模塊實(shí)現(xiàn)吃豆人圖像界面的生成功能,內(nèi)部程序描繪墻體、吃豆人、豆子、魔鬼等畫面,并可通過按鍵控制吃豆人移動。VGA時序控制模塊實(shí)現(xiàn)VGA控制時序,使圖像控制模塊生成的湖,面可以通過VGA顯示器顯示出來。數(shù)碼管控制模塊用于控制板子上的數(shù)碼管顯示,顯示內(nèi)容為所得分?jǐn)?shù)。

3. 模塊設(shè)計(jì)

3.1 時鐘分頻模塊

Basys3板子上帶有100MHz的晶振,將該時鐘信號最為系統(tǒng)的外部輸入時鐘。本文設(shè)計(jì)的VGA顯示分辨率為800x600@60Hz,對應(yīng)的VGA時鐘為40MHz,因此選擇40MHz為本系統(tǒng)各個模塊的工作時鐘。時鐘分頻模塊實(shí)現(xiàn)將外部輸入的100MHz信號分頻為40MHz。分頻方法為調(diào)用Vivado自帶的時鐘分頻IP核,將IP核輸出頻率設(shè)置為40M,如下圖所示。

3.2 按鍵模塊

按鍵模塊實(shí)現(xiàn)按鍵消抖功能,并最終將按鍵信號轉(zhuǎn)換為對應(yīng)的移動信號和方向信號。Basys3板子上提供了5個機(jī)械回彈式的按鍵。機(jī)械式的按鍵都會有按鍵抖動的現(xiàn)象,為了不產(chǎn)生這種現(xiàn)象而作的措施就是按鍵消抖,按鍵模塊框圖如下圖所示。

代碼的設(shè)計(jì)過程為首先以40M時鐘信號不斷的檢測按鍵,當(dāng)檢測到鍵值變化后,開始計(jì)數(shù)器計(jì)數(shù),當(dāng)計(jì)數(shù)值滿足延遲要求后,重新檢測鍵值,并將鍵值的上升沿信號輸出,即最終效果為按下一次按鍵后,對應(yīng)輸出一個時鐘周期的高電平信號。

然后對4個消抖后的按鍵信號減小判斷,使用s_Direction信號記錄按鍵對應(yīng)的方向,當(dāng)上方向鍵按下時記為“1000”,下方向記為“0100”,左方向記為“0001”,有方向記為“0010”。并且每次有按鍵按下將s_Move信號拉高,表示需要移動。

3.3 數(shù)碼管控制模塊

數(shù)碼管控制模塊如下圖所示,該模塊用于顯示游戲分?jǐn)?shù)。

使用開發(fā)板的7段數(shù)碼管顯示,每個數(shù)碼管輸入為7位,對應(yīng)下圖中的abcdefg7段,當(dāng)輸入0時對應(yīng)的段點(diǎn)亮,當(dāng)輸入為1時,對應(yīng)的段滅。

根據(jù)上圖可以觀察到,若要顯示數(shù)字0,需要G滅,ABCDEF亮,也就是對應(yīng)編碼為“1000000”,其中從左到右依次對應(yīng)GFEDCBA。以此類推可以得到0~9的所有編碼。

3.4 VGA時序控制模塊

模塊實(shí)現(xiàn)VGA時序的控制,用于產(chǎn)生VGA的CLK信號,hsync信號和vsync信號,模塊框圖如下圖所示。

本文設(shè)計(jì)的VGA時序?yàn)?00x600刷新頻率為60Hz。每場對應(yīng)628個行周期(628=4+23+600+1),其中600為顯示行。下圖為VGA模塊實(shí)現(xiàn)的時序圖

HSYNC Signal 是用來控制“列填充”, 而一個HSYNC Signal 可以分為4個段,也就是 a (同步段) , b(后廊段),c(激活段),d(前廊段)。HSYNC Signal 的a 是拉低的128 個列像素,b是拉高的88個列像素,至于c 是拉高的 800 個列像素,而最后的 d 是拉高的 40 個列像素。 一列總共有1056 個列像素。VSYNC Signal 是用來控制“行掃描”。而一個 VSYNC Signal 同樣可以分為 4個段, 也是 o (同步段) , p(后廊段),q(激活段),r(前廊段)。VSYNC Signal 的o 是拉低的4個行像素 ,p是拉高的23個行像素,至于q 是拉高的 600 個行像素,而最后的 r 是拉高的 1 個行像素。

3.5 圖像控制模塊

圖像控制模塊實(shí)現(xiàn)吃豆人圖像界面的生成功能,內(nèi)部程序描繪墻體、吃豆人、豆子、魔鬼等畫面,并可通過按鍵控制吃豆人移動,模塊框圖如下:

為描繪較為復(fù)雜的吃豆人、魔鬼、豆子等圖案,本設(shè)計(jì)使用ROM IP核存儲對應(yīng)的圖案,即事先將所繪制的圖案轉(zhuǎn)換為對應(yīng)0和1數(shù)字,再將該數(shù)字圖案存儲在coe文件中,當(dāng)需要顯示該圖像時不需要再寫代碼,而只需要調(diào)用該圖像的IP核即可。下圖為魔鬼對應(yīng)的coe文件內(nèi)容。

上圖中,我將圖案的輪廓描繪出來了,數(shù)字1代表屏幕上顯示的內(nèi)容,數(shù)字0代表不顯示,因此上圖中魔鬼的眼睛和嘴巴出現(xiàn)了。其他的吃豆人、豆子等圖案也采用這種方法實(shí)現(xiàn)。圖中的墻壁由于形狀比較規(guī)范,直接使用代碼設(shè)計(jì)。設(shè)計(jì)方法為通過約束垂直方向的起始和結(jié)束位置以及水平方向的起始和結(jié)束位置,實(shí)現(xiàn)描繪出一個矩形的功能。

4. 代碼調(diào)試遇到的問題

在調(diào)試過程中,遇到了一些問題,首先在設(shè)計(jì)圖案時,原本的設(shè)計(jì)的都通過代碼直接描述,但是實(shí)現(xiàn)過程中由于不規(guī)范的圖形使用代碼描述時實(shí)在過于復(fù)雜,導(dǎo)致代碼可讀性差且任意出錯,后面通過查找資料,了解到使用coe文件的方法,就很方便的完成了異形圖形的設(shè)計(jì)。在使用數(shù)碼管顯示分?jǐn)?shù)時,一開始沒有區(qū)分顯示的個位和十位,導(dǎo)致最終在數(shù)碼管顯示時按十六進(jìn)制顯示了,不符合日常習(xí)慣,后面通過修改代碼,使分?jǐn)?shù)的十位和個位分別計(jì)數(shù),改成十進(jìn)制顯示,方便觀看。

部分代碼展示:

library?IEEE;
use?IEEE.STD_LOGIC_1164.ALL;
use?IEEE.NUMERIC_STD.ALL;
entity?vga_driver?is
Port(
pic_clk????:?in??std_logic;--628*1056*60?40MHz.
p_Reset????:?in??std_logic;
p_Color????:?in??std_logic_vector(2?downto?0);
H_position?????:?out?integer;
V_position?????:?out?integer;
VGA_hsync_o????:?out?std_logic;
VGA_vsync_o????:?out?std_logic;
VGA_R???:?out?std_logic_vector(3?downto?0);
VGA_G?:?out?std_logic_vector(3?downto?0);
VGA_B??:?out?std_logic_vector(3?downto?0)
);
end?vga_driver;
architecture?Behavioral?of?vga_driver?is
--?Timing?Constants
--?For?polarity?'0'?means?negative?polarity
--?Horizontal?Axis
constant?HD????????:?integer???:=?800;?--?Visiable?Area
constant?HFP???????:?integer???:=?40;?--?Front?Porch
constant?HSP???????:?integer???:=?128;?--?Sync?Pulse
constant?HBP???????:?integer???:=?88;?--?Back?porch
constant?HPOLARITY?:?std_logic?:=?'1';?--?Polartity
constant?HTOTAL????:?integer???:=?HD?+?HFP?+?HSP?+?HBP;?--?Whole?Line
--?Vertical?Axis
constant?VD????????:?integer???:=?600;?--?Visiable?Area
constant?VFP???????:?integer???:=?1;?--?Front?Porch
constant?VSP???????:?integer???:=?4;?--?Sync?Pulse
constant?VBP???????:?integer???:=?23;?--?Back?porch
constant?VPOLARITY?:?std_logic?:=?'1';?--?Polartity
constant?VTOTAL????:?integer???:=?VD?+?VFP?+?VSP?+?VBP;?--?Whole?Line
signal?s_HPos?????:?integer;
signal?s_VPos?????:?integer;
signal?s_videoOn??:?std_logic;
signal?s_VGARed???:?std_logic_vector(3?downto?0);
signal?s_VGAGreen?:?std_logic_vector(3?downto?0);
signal?s_VGABlue??:?std_logic_vector(3?downto?0);
begin
--?Horizontal?Position?Counter
HPCounter?:?process(pic_clk,?p_Reset)
begin
if?(p_Reset?=?'1')?then
s_HPos?<=?0;
elsif?(rising_edge(pic_clk))?then
if?(s_HPos?=?HTOTAL)?then
s_HPos?<=?0;
else
s_HPos?<=?s_HPos?+?1;
end?if;
end?if;
end?process;
H_position?<=?s_HPos;
--?Vertical?Position?Counter
VPCounter?:?process(pic_clk,?p_Reset)
begin
if?(p_Reset?=?'1')?then
s_VPos?<=?0;
elsif?(rising_edge(pic_clk))?then
if?(s_HPos?=?HTOTAL)?then
if?(s_VPos?=?VTOTAL)?then
s_VPos?<=?0;
else
s_VPos?<=?s_VPos?+?1;
end?if;
end?if;
end?if;
end?process;
V_position?<=?s_VPos;
--?Horizontal?Synchronisation
HSync?:?process(pic_clk,?p_Reset)
begin
if?(p_Reset?=?'1')?then
VGA_hsync_o?<=?HPOLARITY;
elsif?(rising_edge(pic_clk))?then
if?((s_HPos?<?HD?+?HFP)?OR?(s_HPos?>?HD?+?HFP?+?HSP))?then
VGA_hsync_o?<=?not?HPOLARITY;
else
VGA_hsync_o?<=?HPOLARITY;
end?if;
end?if;
end?process;
--?Vertical?Synchronisation
VSync?:?process(pic_clk,?p_Reset)
begin
if?(p_Reset?=?'1')?then
VGA_vsync_o?<=?VPOLARITY;
elsif?(rising_edge(pic_clk))?then
if?((s_VPos?<?VD?+?VFP)?OR?(s_VPos?>?VD?+?VFP?+?VSP))?then
VGA_vsync_o?<=?not?VPOLARITY;
else
VGA_vsync_o?<=?VPOLARITY;
end?if;
end?if;
end?process;
--?Video?On
videoOn?:?process(pic_clk,?p_Reset)
begin
if?(p_Reset?=?'1')?then
s_videoOn?<=?'0';
elsif?(rising_edge(pic_clk))?then
if?(s_HPos?<=?HD?and?s_VPos?<=?VD)?then
s_videoOn?<=?'1';
else
s_videoOn?<=?'0';
end?if;
end?if;
end?process;
colorOutput?:?process(pic_clk,?p_Reset)
begin
if?(p_Reset?=?'1')?then
s_VGARed???<=?(others?=>?'0');
s_VGAGreen?<=?(others?=>?'0');
s_VGABlue??<=?(others?=>?'0');
elsif?(rising_edge(pic_clk))?then
if?(s_VideoOn?=?'1')?then
s_VGARed???<=?p_Color(2)?&?p_Color(2)?&?p_Color(2)?&?p_Color(2);
s_VGAGreen?<=?p_Color(1)?&?p_Color(1)?&?p_Color(1)?&?p_Color(1);
s_VGABlue??<=?p_Color(0)?&?p_Color(0)?&?p_Color(0)?&?p_Color(0);
else
s_VGARed???<=?(others?=>?'0');
s_VGAGreen?<=?(others?=>?'0');
s_VGABlue??<=?(others?=>?'0');
end?if;
end?if;
end?process;
VGA_R???<=?s_VGARed;
VGA_G?<=?s_VGAGreen;
VGA_B??<=?s_VGABlue;
end?Behavioral;

點(diǎn)擊鏈接獲取代碼文件:http://www.hdlcode.com/index.php?m=home&c=View&a=index&aid=288

相關(guān)推薦