吃豆人游戏VGA显示VHDL代码basys3开发板带设计报告

名称:吃豆人游戏VGA显示VHDL代码basys3开发板设计报告

软件:VIVADO

语言:VHDL

代码功能:

本设计是一个基于VGA的吃豆人游戏,玩家可以控制屏幕上的吃豆人吃散落在屏幕各个方位的豆子,同时屏幕上还有2个魔鬼,如果吃豆人和魔鬼相遇,则游戏失败。

设计的基本要求是魔鬼的移动方式固定,且用固定得到圆形或者方形来表示不同的对象。考虑到该实现方案较为简单,为使显示更加美观,在屏幕上添加墙壁,划分出不同的路线。吃豆人和魔鬼也不使用固定圆形或者方形,而是用较为形象的图案,可以体现出眼睛嘴巴等特征。

同时为了记录游戏得分,添加数码管显示部分。

系统控制魔鬼在所划分的道路上巡逻,玩家通过Basys3板子上的上下左右按键控制吃豆人吃豆子以及规避魔鬼。

FPGA代码Verilog/VHDL代码资源下载:www.hdlcode.com

本代码已在Basys3开发板验证,开发板如下,其他开发板可以修改管脚适配:

basys3开发板.png

代码下载:吃豆人游戏VGA显示VHDL代码basys3开发板带设计报告名称:吃豆人游戏VGA显示VHDL代码basys3开发板设计报告(代码在文末下载)软件:VIVADO语言:VHDL代码功能:本设计是一个基于VGA的吃豆人游戏,玩家可以控制屏幕上的吃豆人吃散落在屏幕各个方位的豆子,同时屏幕上还有2个魔鬼,如果吃豆人和魔鬼相遇,则游戏失败。设计的基本要求是魔鬼的移动方式固定,且用固定得到圆形或者方形来表示不同的对象。考虑到该实现方案较为简单,为使显示更加美观,在屏幕icon-default.png?t=N7T8http://www.hdlcode.com/index.php?m=home&c=View&a=index&aid=288

1. 方案选择

本设计是一个基于VGA的吃豆人游戏,玩家可以控制屏幕上的吃豆人吃散落在屏幕各个方位的豆子,同时屏幕上还有2个魔鬼,如果吃豆人和魔鬼相遇,则游戏失败。设计的基本要求是魔鬼的移动方式固定,且用固定得到圆形或者方形来表示不同的对象。考虑到该实现方案较为简单,为使显示更加美观,在屏幕上添加墙壁,划分出不同的路线。吃豆人和魔鬼也不使用固定圆形或者方形,而是用较为形象的图案,可以体现出眼睛嘴巴等特征。同时为了记录游戏得分,添加数码管显示部分。系统控制魔鬼在所划分的道路上巡逻,玩家通过Basys3板子上的上下左右按键控制吃豆人吃豆子以及规避魔鬼。

2. 系统设计

系统的整体设计框图如下图所示,输入端口包括时钟、复位、四个上下左右按键。输出端口包括VGA的HSYNC、VSYNC信号,颜色RGB信号以及用于数码管控制的位选(bit_sel)和段选信号(semgnet)。

系统包括分频模块(clk_wizard)、按键模块(io)、图像控制模块(picture_ctrl)、VGA时序控制模块(vga_driver)和数码管控制模块(ssd_controller)。其中分频模块用于分频产生其他模块的工作时钟,按键模块实现按键消抖功能,并将按键信号输出给图像控制模块。图像控制模块实现吃豆人图像界面的生成功能,内部程序描绘墙体、吃豆人、豆子、魔鬼等画面,并可通过按键控制吃豆人移动。VGA时序控制模块实现VGA控制时序,使图像控制模块生成的湖,面可以通过VGA显示器显示出来。数码管控制模块用于控制板子上的数码管显示,显示内容为所得分数。

3. 模块设计

3.1 时钟分频模块

Basys3板子上带有100MHz的晶振,将该时钟信号最为系统的外部输入时钟。本文设计的VGA显示分辨率为800x600@60Hz,对应的VGA时钟为40MHz,因此选择40MHz为本系统各个模块的工作时钟。时钟分频模块实现将外部输入的100MHz信号分频为40MHz。分频方法为调用Vivado自带的时钟分频IP核,将IP核输出频率设置为40M,如下图所示。

3.2 按键模块

按键模块实现按键消抖功能,并最终将按键信号转换为对应的移动信号和方向信号。Basys3板子上提供了5个机械回弹式的按键。机械式的按键都会有按键抖动的现象,为了不产生这种现象而作的措施就是按键消抖,按键模块框图如下图所示。

代码的设计过程为首先以40M时钟信号不断的检测按键,当检测到键值变化后,开始计数器计数,当计数值满足延迟要求后,重新检测键值,并将键值的上升沿信号输出,即最终效果为按下一次按键后,对应输出一个时钟周期的高电平信号。

然后对4个消抖后的按键信号减小判断,使用s_Direction信号记录按键对应的方向,当上方向键按下时记为“1000”,下方向记为“0100”,左方向记为“0001”,有方向记为“0010”。并且每次有按键按下将s_Move信号拉高,表示需要移动。

3.3 数码管控制模块

数码管控制模块如下图所示,该模块用于显示游戏分数。

使用开发板的7段数码管显示,每个数码管输入为7位,对应下图中的abcdefg7段,当输入0时对应的段点亮,当输入为1时,对应的段灭。

根据上图可以观察到,若要显示数字0,需要G灭,ABCDEF亮,也就是对应编码为“1000000”,其中从左到右依次对应GFEDCBA。以此类推可以得到0~9的所有编码。

3.4 VGA时序控制模块

模块实现VGA时序的控制,用于产生VGA的CLK信号,hsync信号和vsync信号,模块框图如下图所示。

本文设计的VGA时序为800x600刷新频率为60Hz。每场对应628个行周期(628=4+23+600+1),其中600为显示行。下图为VGA模块实现的时序图:

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 图像控制模块

图像控制模块实现吃豆人图像界面的生成功能,内部程序描绘墙体、吃豆人、豆子、魔鬼等画面,并可通过按键控制吃豆人移动,模块框图如下:

为描绘较为复杂的吃豆人、魔鬼、豆子等图案,本设计使用ROM IP核存储对应的图案,即事先将所绘制的图案转换为对应0和1数字,再将该数字图案存储在coe文件中,当需要显示该图像时不需要再写代码,而只需要调用该图像的IP核即可。下图为魔鬼对应的coe文件内容。

上图中,我将图案的轮廓描绘出来了,数字1代表屏幕上显示的内容,数字0代表不显示,因此上图中魔鬼的眼睛和嘴巴出现了。其他的吃豆人、豆子等图案也采用这种方法实现。图中的墙壁由于形状比较规范,直接使用代码设计。设计方法为通过约束垂直方向的起始和结束位置以及水平方向的起始和结束位置,实现描绘出一个矩形的功能。

4. 代码调试遇到的问题

在调试过程中,遇到了一些问题,首先在设计图案时,原本的设计的都通过代码直接描述,但是实现过程中由于不规范的图形使用代码描述时实在过于复杂,导致代码可读性差且任意出错,后面通过查找资料,了解到使用coe文件的方法,就很方便的完成了异形图形的设计。在使用数码管显示分数时,一开始没有区分显示的个位和十位,导致最终在数码管显示时按十六进制显示了,不符合日常习惯,后面通过修改代码,使分数的十位和个位分别计数,改成十进制显示,方便观看。

部分代码展示:

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;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值