数字系统设计————打地鼠游戏设计

一、设计题目说明

此设计意在实现一个相对具有娱乐性的打地鼠游戏模块功能,能够产生随机出现的地鼠,并能对虚拟的敲击按键做出灵敏的识别与判断,从而进行必要的计分与计时行为。

二、实验平台

开发软件:

Quartus II 9.0sp2 Web Edition

开发板:

ALTERA FLEX EPF10K20TI144-4 CAA239743

三、总体设计思路

结构:

取八位晶体管的前四位数码管作为随机地鼠出现的显示区域,后四位对半分为前两位的倒计时显示模块和后两位的分数计数模块;八个按键脉冲开关取前四位作为地鼠的敲击按键;以数码管的动态化显示代表是否击中。

功能:

在游戏开始前,首先根据产生的伪随机数生成地鼠出现的位置信息,由指定的时钟脉冲信号控制地鼠跳动的频率,最终交由晶体管显示。重置倒计时与分数,待随机数已生成一段时间,拨动开始键,驱动游戏进行。此时倒计时与比较模块开始工作,将地鼠出现的位置信息与敲击按键的位置信息进行比对,如果一致,则分数加一,如不一致,分数保持不变,直到60s倒计时结束,各模块停止工作。按下重置键复位重新开始游戏。

四、详细模块设计

①分频模块:

将100,000Hz的时钟信号源分频为所需的1Hz时钟信号,使得时钟信号能够每秒产生一个时钟脉冲。

--分频模块

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity divclock is
port( oldclk: IN std_logic;
      currclk: buffer std_logic);
end;
architecture one of divclock is
 constant useHz:integer:=100000;--旧时钟频率为100000Hz
begin
    process(oldclk)
    variable count:integer range 0 to useHz-1;--设置计数器,保留旧时钟频率产生上升沿的次数
    begin
      if oldclk'event and oldclk='1' then
          if count=(useHz-1)/2 then--0.5s时,计数器置0,新时钟翻转
             count:=0;
             currclk<=NOT currclk;
          else
             count:=count+1;
         end if;
      end if;
    end process;
end one;
②随机数模块:

取m序列的每四位的后两位,产生一定数量的伪随机数,作为地鼠的位置信息。

--output 2bits random number
--利用m序列产生四位随机数,取每四位的后两位作为本次课设所需的随机数

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity rand is
port(Reset: IN std_logic;
     Clk: IN std_logic;
     Data_out: OUT std_logic_vector(1 downto 0));
end rand;

architecture rtl of rand is

signal Shift_Register:std_logic_vector(3 downto 0);

begin

process(Reset,Clk)
begin
if(Reset='1') then
   Shift_Register<="1000";
else if(Clk'event and Clk='1') then
  Data_Out<=Shift_Register(1 downto 0);
  Shift_Register(0)<=Shift_Register(1);
  Shift_Register(1)<=Shift_Register(2);
  Shift_Register(2)<=Shift_Register(3);
  Shift_Register(3)<=Shift_Register(3) xor Shift_Register(0);
end if;
end if;
end process;

end rtl;
③按键模块:

通过转码,将按键的位置信息转化为对应位置上地鼠的位置信息。

--按键模块

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity button_decode is
  port(a,b,c,d: IN std_logic;--定义4个按键
       --clk: IN std_logic;
       result: OUT std_logic_vector(1 downto 0));
end button_decode;

architecture one of button_decode is
begin
  process(a,b,c,d)
    begin--对按键进行位置信息的转换
      --if(clk'event and clk='1') then
        if a='0' then
          result<="11";
        elsif b='0' then
          result<="10";
        elsif c='0' then
          result<="01";
        elsif d='0' then
          result<="00";
        else
          result<=NULL;
        end if;
      --end if;
  end process;
end;
④倒计时模块:

利用分频得到1Hz的时钟频率设置倒计时,每当经过一个时钟脉冲,模块中的计时器减一,直至设定的时间结束为0或者通过reset重置。

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity timedown is
  port(start: IN std_logic;
       clk: IN std_logic;
       reset: IN std_logic;
       S: OUT std_logic_vector(3 downto 0);--十位
       F: OUT std_logic_vector(3 downto 0);--个位
       accomplish: OUT std_logic);   --倒计时状态的输出信号,如果倒计时结束,则输出1
end timedown;

architecture one of timedown is
begin
  process(clk,start,reset)
  variable s2:std_logic_vector(3 downto 0);--十位
  variable f2:std_logic_vector(3 downto 0);--个位
  begin
    if(clk'event and clk='1') then
      if(reset='1') then     --重置
        s2:="0110";--6
        f2:="0000";--0
      elsif start='1' then
        if f2="0000" then   --如果个位等于0而十位不等于0,则将个位置为9,十位减一
           if s2/="0000" then
             f2:="1001";
             s2:=s2-1;
             accomplish<='0';
           else             --如二者都为0,则倒计时保持“00”不变,同时将倒计时状态置为1               
             accomplish<='1';
             f2:=f2;
             s2:=s2;
           end if;
        else                --其他情况下,个位减一,倒计时状态置0
          f2:=f2-1;
          accomplish<='0';
        end if;
      end if;
       S<=s2;
       F<=f2;
     end if;
     
  end process;
end one;
⑤比较模块:

将按键模块和随机数模块传入的位置信息进行比较,如果相同,则传送信号‘1’给计分模块,否则传送信号‘0’。

--compare

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity compare is
  port(Data_out,button: IN std_logic_vector(1 downto 0);
       clk: IN std_logic;
       accomplish: IN std_logic;
       true: OUT std_logic;
       start: IN std_logic);
end compare;

architecture one of compare is
begin
  process(clk)
  begin
    if(start='1') then--如果游戏开始且尚未结束,则进行判断
      if(accomplish='0') then
        if(Data_out=button) then--如果位置信息相同,则置信号为高电平
           true<='1';
        else
           true<='0';
        end if;
      end if;
    end if;
  end process;
end;
⑥计分模块:

判断比较模块传递的信号,如果位置信息相同则分数加一,否则分数保持不变。

--score

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity score is
  port(clk: IN std_logic;
       start: IN std_logic;
       true: IN std_logic;
       accomplish: IN std_logic;
       reset: IN std_logic;
       G: OUT std_logic_vector(7 downto 0));--分数
end score;

architecture one of score is
begin
  process(clk,start,true)
  variable temp1,temp2: std_logic_vector(3 downto 0);--分数的十位与个位
    begin
      if(clk'event and clk='1') then
        if reset='1' then--重置分数
           temp1:="0000";--十位
           temp2:="0000";--个位
        else
        if start='1' and true='1' then--如果游戏开始,且命中地鼠
          if accomplish='0' then      --如果倒计时没有结束
            temp2:=temp2+1;           --个位+1
            if(temp2="1010")then      --如果个位等于10,则十位加一,个位置0
               temp1:=temp1+1;
               temp2:="0000";
            end if;
          end if;
        elsif start='1' and true='0' then--如果游戏开始,地鼠未被命中,则分数保持不变
          if accomplish='1' then
             temp2:=temp2;
             temp1:=temp1;
          end if;
        elsif start='0' then  --如果拨下开始键,则分数清零
          temp2:="0000";
          temp1:="0000";
        end if;
        G(7 downto 4)<=temp1;
        G(3 downto 0)<=temp2;
      end if;
     end if;
end process;
end one;
⑦显示模块:

根据各模块传送的数据,通过动态扫描技术实现相应内容的显示。

--显示模块

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity transform is--定义多个接收端用来接收其他模块的信息,从而向晶体管输出对应的信息
  port(Data_out: IN std_logic_vector(1 downto 0);--地鼠位置信息
       S: IN std_logic_vector(3 downto 0);       --倒计时十位
       F: IN std_logic_vector(3 downto 0);       --倒计时个位
       G: IN std_logic_vector(7 downto 0);       --分数
       clk: IN std_logic;                        --动态扫描时钟信号
       true: IN std_logic;                       --比较模块传来的位置比较结果
       sel: OUT std_logic_vector(7 downto 0);    --位选信号
       led: OUT std_logic_vector(6 downto 0));   --晶体管显示
end transform;

architecture one of transform is

begin
  process(clk,true)
  variable m: integer range 0 to 4:=0;--定义变量m,以区分不同时间片下晶体管的显示区域
    begin
      if(clk'event and clk='1') then
        if(m=0) then                  --m=0,以LED形式呈现地鼠(m=others时情况类似)
          m:=m+1;
          if(data_out="00") then
            sel<="11101111";
            led<="1111110";
            if(true='1') then         --如果命中,则地鼠呈现被打扁状
               led<="0001000";
            end if;
          elsif(data_out="01") then
            sel<="11011111";
            led<="1111110";
            if(true='1') then
               led<="0001000";
            end if;
          elsif(data_out="10") then
            sel<="10111111";
            led<="1111110";
            if(true='1') then
               led<="0001000";
            end if;
          elsif(data_out="11") then
            sel<="01111111";
            led<="1111110";
            if(true='1') then
               led<="0001000";
            end if;
          end if;
        elsif(m=1) then     --如果 m=1,切换显示倒计时的十位
          m:=m+1;
          sel<="11110111";
          case S is
            when "0000" => led<="0111111";--0
            when "0001" => led<="0000110";--1
            when "0010" => led<="1011011";--2
            when "0011" => led<="1001111";--3
            when "0100" => led<="1100110";--4
            when "0101" => led<="1101101";--5
            when "0110" => led<="1111101";--6
            when others => led<="0000000";
          end case;
        elsif(m=2) then     --如果 m=2,切换显示倒计时的个位
          m:=m+1;
          sel<="11111011";
          case F is
            when "0000" => led<="0111111";--0
            when "0001" => led<="0000110";--1
            when "0010" => led<="1011011";--2
            when "0011" => led<="1001111";--3
            when "0100" => led<="1100110";--4
            when "0101" => led<="1101101";--5
            when "0110" => led<="1111101";--6
            when "0111" => led<="0000111";--7
            when "1000" => led<="1111111";--8
            when "1001" => led<="1101111";--9
            when others => led<="0000000";
          end case;
        elsif(m=3) then     --如果 m=3,切换显示分数的十位
          m:=m+1;
          sel<="11111101";
          case G(7 downto 4) is
            when "0000" => led<="0111111";--0
            when "0001" => led<="0000110";--1
            when "0010" => led<="1011011";--2
            when "0011" => led<="1001111";--3
            when "0100" => led<="1100110";--4
            when "0101" => led<="1101101";--5
            when "0110" => led<="1111101";--6
            when "0111" => led<="0000111";--7
            when "1000" => led<="1111111";--8
            when "1001" => led<="1101111";--9
            when others => led<="0000000";
          end case;
        elsif(m=4) then     --如果 m=4,切换显示分数的个位
          m:=0;
          sel<="11111110";
          case G(3 downto 0) is
            when "0000" => led<="0111111";--0
            when "0001" => led<="0000110";--1
            when "0010" => led<="1011011";--2
            when "0011" => led<="1001111";--3
            when "0100" => led<="1100110";--4
            when "0101" => led<="1101101";--5
            when "0110" => led<="1111101";--6
            when "0111" => led<="0000111";--7
            when "1000" => led<="1111111";--8
            when "1001" => led<="1101111";--9
            when others => led<="0000000";
          end case;
        end if;
      end if;
    end process;
end one;

之后将编译好的子模块导入新项目中,将各模块生成各个单独的元器件,创建原理图文件,将各模块元器件导入,连线。在这里插入图片描述

仿真

在这里插入图片描述

五、板载测试

①通电下载后,随机数生成模块首先开始运作,前四位数码管显示随机出现的虚拟地鼠模型
在这里插入图片描述
②拨动reset键重置倒计时,进入游戏准备阶段。

在这里插入图片描述
③拨动选择游戏难度。
在这里插入图片描述
④拨动start键开始游戏,倒计时开始,比较和按键模块开始运行。
在这里插入图片描述
⑤如果击中地鼠,地鼠呈现被打扁状,分数+1,指示灯闪亮。
在这里插入图片描述
⑥倒计时未结束拨动reset键使置1,由于游戏期间不允许暂停,故倒计时重置,分数暂留,直至reset键置0,分数清零。
在这里插入图片描述
在这里插入图片描述
⑦倒计时结束后,分数保持不变,按键和比较模块停止工作,直至start置0,分数清零。

在这里插入图片描述
在这里插入图片描述

六、不足之处

地鼠一次只能出现一只且器械老化存在一定的干扰(时间紧迫,按键抖动未加)。

七、心得体会

通过这次实验设计,我真真正正地从实践中学到了很多。经历了无数的困难,我被给予了更多的经验与教训,让我有足够的能力去力图改进和应对下一次可能出现的艰难险阻。
在一开始的尝试过程中,我尝试以一个大文件的形式,写出一个极具整体性的VHDL代码,奈何能力不足,在实现上遇到了不少的困难,给自己增加了不少不必要的负担。在经过一段时间的考虑后,我选择将整体拆分成多个不同的小模块逐一实现,最后以原理图的方式连线实现。在新一轮的实践中,我试图将显示模块嵌入在其他各个小模块中,实践中发现这种方法存在诸多不便,最终确立将各模块完全剥离,得到了现阶段的最优的方案。在接下来的实现过程中,常常遇到因为考虑不周而使得部分模块超时执行的不正常现象,也有遇到不熟悉VHDL部分语句而出现的逻辑错误,在查阅资料并多次实验尝试各种不同的方法后,问题渐渐得以解决,最终实现了基本的打地鼠功能。
在板载测试成功后,此时距离提交成果的最后期限还有很多时间,在这段时间里,我开始考虑如何去完善和美化它,在之后,我陆陆续续修正了其中的一些不足之处,完善了部分代码,同时加入了地鼠的第二阶段形态以及游戏模式选择控件,使得游戏整体更加符合现实生活中真实用户的需求,最终得到了现在相对成熟的成果。
在这次的课程设计中,我不仅仅提高了自己的动手能力,更为重要的是理解了EDA融入于我们生活的真谛,我们真正学习技术,不应只会浅薄的纸上谈兵,更应该把技术应用于实践,用“死”的代码赋予现实生活丰富多彩。EDA是,又不是简简单单的一种技术,它是我们链接数字世界与三维世界的一把钥匙,是我们人与机械器件沟通的纽带与桥梁。我们要时时刻刻记住自己身为一名工科生的责任与担当,化静为动,化“死”为生。

源文件下载地址
盘+1234

  • 19
    点赞
  • 126
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值