视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
FPGA健身游戏机课程设计
2025-10-02 14:56:08 责编:小OO
文档
课程设计实验报告

   

基于Xilinx的FPGA的           健身游戏机设计

院    系:  电子与信息工程         

专    业:  电信                   

班    级:                   

姓    名:                  

学    号:            

指导教师:                 

●设计任务名称:基于Xilinx的FPGA的健身游戏机设计

●设计内容及要求:

1、基本功能:

用8个灯作目标,与之对应有8个按键进行控制。每一次8个灯中随机出现一个灯处于“亮”的状态,在灯亮的时间内要求“踩”到对应的按键,若踩到则加1分,且灯熄灭;否则失败扣一分。

设定初始命数为9,连续成功五次加1条命,分数不清0,连续失败5次扣一条命,命数为0时游戏结束。

游戏分四个难度级别,每个级别灯闪亮的速度不同,级别越高,速度越快,灯亮的时间越短。连续加两条命则速度加1.

设有暂停/继续和开始/停止功能,能记录和更新历史最高分数。控制液晶显示器进行相应的显示。命数最多显示为99条,分数最多显示为999分。

2、扩展功能:

每个难度级别对应产生不同的音乐,与灯闪的频率节奏相当。

●实验条件说明

Spartan-3E入门实验板:

自己设计外围电路:

提供芯片有:译码器74LS138,编码器74LS148,其余有,LED灯8个,按键8个,1k电阻8个,510Ω电阻1个,排线两根,导线一组,排针一组,设计好的外围电路如下:

●系统设计

⏹系统框图与说明

音乐模块

 

外接LED灯

外部按键输入

说明:

     外部按键输入:通过74LS148编码器实现8线—3线编码,实现对应按键输入,因为编码器特性,全部为高时输出为1111(其中最高位为状态为)而在其他状态下区间为(0000----0111),可以方便实现与随机数的比较从而实现分数计算。具体电路图及逻辑见外设部分。

     分数计算模块:实现外部按键与内部随机数的匹配比较,若匹配则分数加1,同时为命数模块提供一个win脉冲用来计数;若不匹配则分数减1,同时为命数模块提供一个lose脉冲用来计数。要求保留最高分数。这里要求对按键与随机数的比较次数进行识别,一个随机数只能比较一次,详见详细设计部分。

命数计算:通过分数计算模块说提供的win和lose信号进行计数,累计到5,则实现命数加减1,要求当命数连续加2后输出一个speed信号,此信号给音乐模块和随机数模块,进行音乐的变化和速度的升级。同时在命数减为0后输出一个over信号,告诉系统游戏结束。

     随机数生成模块:此模块主要实现伪随机数输出,并且根据speed信号进行生成速度的转换,同时要求在pause信号和over信号为1时停止随机数输出。随机数外接到外设部分,通过译码器控制LED灯的亮灭。

       外接LED 灯:根据随机数,通过74LS138译码器控制对应LED灯的随机闪烁。

       LCD显示模块:根据分数计算模块,命数模块所输入BCD码以及内部设定在LCD上显示控制信息和生命分数信息。

       音乐模块:通过speed信号的输入,控制音乐乐谱的变化,同时当over信号为高时停止音乐输出。

⏹状态转换图与说明

本实验涉及的状态转换较多,这里只详细介绍我所设计的模块的状态转换:

1:分数计算模块:

   

             状态说明:这里S0状态下,将随机数random赋给一个中间变量random-temp,

                      然后比较按键信号和随机信号,若按键信号和随机信号相等,转入S1,否则转入S2;在S1状态下,若按键和随机数相等且随机信号和中间变量random-temp相等,意味着随机数没变化,则在S1处循环,直到随机数与中间变量不相等,意味着随机数发生变化,则分数加1;另外若在S1状态下,按键和随机数不等,则意味着按键已经抬起,但此时属于正确情况,则在随机数变化后,分数加1,状态转到S0;在S2状态下,若按键信号为“1111”,则意味着没有任何按键按下,则在随机信号变化之前,处于在S2状态循环,若随机信号变化,仍为“1111”,意味着没来的及按下,分数减1,转到S0,若在S2状态下,按键信号等于随机信号,意味着按键正确,则转入S1,若在S2状态下,按键信号不等于随机信号,同时也不等于“1111”,则判断按错,扣一分,转入S3;在S3状态下,一直处于循环,直到随机数变化转到S0。

                      完成完整的循环,上述状态变化,实现了判断按键与随机数的具体逻辑。后文有具体代码。

             

            2:音乐模块:

Res

        

          

                 

                 状态说明:音乐模块比较简单,主要是在乐谱里有状态的转换,状态S0为第一个曲谱,以Res信号为准,直接进入此状态,在S0状态下,遇到speed脉冲信号,则转换为S1为第二个曲谱,以此类推,没遇到一个speed转换一个曲谱,知道S3状态为最后的曲谱。

⏹输入输出设计(按键,数码管,发光管,蜂鸣器)与说明

分数计算模块:

res:输入为复位键,设置分数初始值为0,但不影响最大分数

           clk:时钟输入,时钟触发,这里为了方便音乐模块选择1Mhz频率。

           random:随机数输入,为4位总线。

           button:按键输入,为4位总线。

           lose:扣分输出一个正脉冲。

           win:得分输出一个正脉冲。

           六个4位总线输出,代表着分数和最大分数的BCD码。

命数模块:

res:复位信号,设置初始命数为9。

             clk:时钟信号。

             win:信号输入,控制是否加命。

             lose:信号输入,控制是否减命。

             speed:信号输出,连续加两命一个正脉冲。

             Over:信号输出,命数为0则为1.

             四个4位总线输出,分别代表命数和最大命数的BCD码。

随机数生成模块:

res复位信号,设置初始状态。

           clk1m信号:时钟信号,做触发源。           

clka:最低频率时钟信号,0.5Hz。

clkb:次低频时钟信号,2/3Hz。

clkc:较高频时钟信号,1Hz。

clkd:最高频时钟信号,2Hz。

Speed:信号输入,改变速度。

Pause:暂停控制信号。

Over:输出信号,生命为0。

Random:随机数输出。

音乐模块:

Res复位信号,设置初始状态。

          Clk1m信号:时钟信号,触发源,分频后控制音节频率。

          Clk8:时钟信号,用来控制音节节拍。

          Over信号:命数为0时为高电平输入,此时音乐停止。

          Pause信号:为高时音乐停止。

          Mus信号:就是speed信号,控制曲谱的变化。

          M_output:输出至喇叭,通过频率的变化出现音乐。

LCD模块:

res复位信号,设置初始状态。

          最大生命;最大分数;当前分数;当前命数的BCD码输入。

           Clk信号:时钟信号,这里是500HZ

           Pause信号:为高时显示PAUSE

           Over信号:为高时显示GAMEOVER

           输出为液晶控制信号,有rs,rw,en和数据4位输出。

外设部分:

         电路原理图如下

                      

       上部的芯片是译码器74LS138,实现3位随机数对应随机的8个LED灯。

       下面的芯片是编码器74LS148,实现8个按键对应四位码值输出。

                对于74LS138比较熟悉,在我们的数电和电子设计的书上都有对其用法的介绍,这里就不详细介绍,只重点介绍74LS148编码器,首先看下面的真值表:

                   可以看出,当没有任何按键输入时,恒定输出为1111,符合分数计算要求的逻辑,不过这里有一个地方要说明,验收时老师问我如果都按下会是什么效果,我说以第一个按下的键位为准,这个说法现在看来是错误的,按照真值表可知,这个按键是有优先级的,都按下时,输出为0000。 

                 画出的PCB版图如下所示:

             

⏹详细设计关键代码及说明

1.分数计算模块:

端口设定代码如下

    entity maxscore is

    Port ( clk1m : in  STD_LOGIC;

           res : in  STD_LOGIC;

           random : in  STD_LOGIC_VECTOR (3 downto 0);

           button : in  STD_LOGIC_VECTOR (3 DOWNTO 0);

           win : out  STD_LOGIC;

           lose : out  STD_LOGIC;

              max100 : out  STD_LOGIC_VECTOR (3 downto 0);

           score100 : out  STD_LOGIC_VECTOR (3 downto 0);

           max10 : out  STD_LOGIC_VECTOR (3 downto 0);

           score10 : out  STD_LOGIC_VECTOR (3 downto 0);

           max1 : out  STD_LOGIC_VECTOR (3 downto 0);

           score1 : out  STD_LOGIC_VECTOR (3 downto 0));

end maxscore;

分数计算代码段如下:

    (对应于上面所描述的此模块的状态图)

signal random1:std_logic_vector(3 downto 0);   --定义中间信号变量,用于寄存随机变量

signal s0,s1,s2,s3:std_logic;

begin

process(clk50m)

begin

if rising_edge(clk50m) then

if res='1' then

s0<='1';

s1<='0';

s2<='0';

s3<='0';

win<='0';

lose<='0';--res复位信号,状态转到S0,win信号和lose信号为0

elsif s0='1' then

random1<=random;--S0状态下,将随机数赋给中间变量

  if button = random then

s1<='1';

s2<='0';

s0<='0';

s3<='0';

win<='0';

lose<='0';

--S0状态下,在按键与随机数相匹配时转到S1状态

  else

s1<='0';

s2<='1';

s0<='0';

s3<='0';

win<='0';

lose<='0';--S0状态下,在按键与随机数不匹配时转到S2状态

  end if;

elsif s1='1' then

  if button = random then

    if random1=random then

s1<='1';

s2<='0';

s0<='0';

s3<='0';

     win<='0';

     lose<='0';--S1状态下,若按键和随机数相等

                                        且随机数没有变化,则在S1状态下循环

     else 

s1<='1';

s2<='0';

s0<='0';

s3<='0';

random1<=random;

     win<='1';

     lose<='0'; --S1状态下,若按键与随机数相等,

                                      随机数又发生变化,证明已经是第

                                      二次的随机数,则win信号给一个正脉冲

     end if;

  elsif random1=random then

s1<='1';

s2<='0';

s0<='0';

s3<='0';

     win<='0';

     lose<='0';--若在S1状态下按键与随机数不等

                                       证明按键抬起,此时若随机数未

                                       变,则仍在S1状态循环。

  else

s0<='1';

s1<='0';

s2<='0';

s3<='0';

     win<='1';

     lose<='0';--若S1下,按键与随机数不等,且

                                     随机数变化,根据上述分析,win

                                     给一个正脉冲。回到S0

  end if;

elsif s2='1' then

  if button = "1111" then

    if random1=random then

s1<='0';

s2<='1';

s0<='0';

s3<='0';

     win<='0';

     lose<='0';--在S2状态下,若按键为“1111”,

                                   且随机数未变,则在S2循环

     else

s0<='1';

s1<='0';

s2<='0';

s3<='0';

     win<='0';

     lose<='1';--若S2下,按键为“1111”。随机数

                                     变化,则回到状态S0,给lose一个

                                     正脉冲

     end if;

  elsif button = random then

s1<='1';

s2<='0';

s0<='0';

s3<='0';

     win<='0';

     lose<='0';--若S2下,按键符合随机数,转到

                                     状态S1。

    else

s1<='0';

s2<='0';

s0<='0';

s3<='1';

     win<='0';

     lose<='1';--若S2下,按键不符合随机数,且

                                      不是“1111”,则给lose一个正脉

                                      转到S3。

    end if;

elsif s3='1' then

  if random1=random then

s1<='0';

s2<='0';

s0<='0';

s3<='1';

win<='0';

lose<='0';--S3下,若随机数不变,则在S3循环。

  else 

s1<='0';

s2<='0';

s0<='1';

s3<='0';

win<='0';

lose<='0';--S3下,若随机数变化,则转到S0。

  end if;

end if;

end if;

end process;

最大值判断模块:

process(clk50m)

begin

if rising_edge(clk50m) then

if res='1' then

scoret1<="0000";

scoret10<="0000";

scoret100<="0000";

scorem1<="0000";

scorem10<="0000";

scorem100<="0000";--复位信号,给最大值和分数赋0初值。

elsif winx='1' then

if scoret100 = "1001" and scoret10 = "1001" and scoret1 = "1001" then

scoret100 <= "1001";

scoret10 <= "1001";

scoret1 <= "1001"; --保证分数不超过999。

elsif scoret1="1001" then

scoret1<="0000" ;

scoret10<=scoret10+1;

elsif scoret10="1001"+1 then

scoret10<="0000";

scoret100<=scoret100+1;    

else

scoret1<=scoret1+1; --实现分数在win信号下累加。

end if;

elsif losex='1' then

if scoret100 = "0000" and scoret10 = "0000" and scoret1 = "0000" then

scoret100 <= "0000";

scoret10 <= "0000";

scoret1 <= "0000";--保证分数不小于000

elsif scoret1="0000" then  

scoret1<="1001" ;

scoret10<=scoret10-1;

elsif scoret10="0000"-1 then

scoret10<="1001" ;

scoret100<=scoret100-1;

else 

scoret1<=scoret1-1;--实现分数在lose信号下递减。

end if;

end if;

if scorem100scorem100<=scoret100;

scorem10<=scoret10;

scorem1<=scoret1;--若最高位当前分数大于最大分数,则对最大值进行刷新

elsif scorem100=scoret100 and scorem10scorem100<=scoret100;

scorem10<=scoret10;

scorem1<=scoret1;--若最高为相等,十位当前分数大于最大分数,对最大值刷新。

elsif scorem100=scoret100 and scorem10=scoret10 and scorem1scorem100<=scoret100;

scorem10<=scoret10;

scorem1<=scoret1; --若最高位和十位都相等,个位的当前分数大于最大值,对最大值进行刷新。

else

scorem100<=scorem100;

scorem10<=scorem10;

scorem1<=scorem1; --其余情况下最大值不变

end if;

end if;

end process; 

2.音乐模块

     首先对音乐模块进行简单介绍:乐曲都是有音符组成的,而音符由频率节拍数组成,音符的频率由pinpu模块实现,这里通过网络查到,各个音节的频率,在fenpin模块进行1mhz时钟输入,然后调用各个音节对应的初值,进行分频,由于直接分频得到的脉冲信号脉宽极窄,所以需另加一个D触发器以均衡其占空比,但得到的频率将变为原来的1/2。

在qupu模块中,存储该乐曲的音符的时长【即节拍数】。TONETABS的CLK输入的是8HZ的脉冲,即0.125S相当于7音符的持续时间为1S。

Pinpu模块

entity pinpu is

    Port ( INDEX : IN INTEGER RANGE 0 TO 20;

            TONE: OUT INTEGER RANGE 0 TO 16#7FF#);

end pinpu;

architecture Behavioral of pinpu is

begin

PROCESS( INDEX )

BEGIN

CASE INDEX IS

WHEN 0 =>TONE<=2047;       --CODE <=0; HIGH<='0';

WHEN 1 =>TONE<=139;        -- CODE <=1; HIGH<= -1;

WHEN 2 =>TONE<=348;        --CODE <=2; HIGH<= -1;

WHEN 3 =>TONE<=532;       --CODE <=3; HIGH<= -1;

WHEN 4 =>TONE<=614; -- CODE <=4; HIGH<= -1;

WHEN 5 =>TONE<=771; --CODE <=5; HIGH<= -1;

WHEN 6 =>TONE<=911; --CODE <=6; HIGH<= -1;

    WHEN 7 =>TONE<=1035; -- CODE <=7; HIGH<= -1;

WHEN 8 =>TONE<=1091;       -- CODE <=1; HIGH<= '0';

WHEN 9 =>TONE<=1182;       --CODE <=2; HIGH<= '0';

WHEN 10 =>TONE<=1288;       --CODE <=3; HIGH<= '0';

WHEN 11 =>TONE<=1324;      --CODE <=4; HIGH<= '0';

WHEN 12 =>TONE<=1409;       -- CODE <=5; HIGH<= '0';

WHEN 13 =>TONE<=1479;      --CODE <=6; HIGH<= '0';

WHEN 14 =>TONE<=1541;       --CODE <=7; HIGH<= '0';

WHEN 15 =>TONE<=1569;       --CODE <=1; HIGH<= '1';

WHEN 16 =>TONE<=1622;       --CODE <=2; HIGH<= '1';

WHEN 17 =>TONE<=1668;       --CODE <=3; HIGH<= '1';

WHEN 18 =>TONE<=16;       --CODE <=4; HIGH<= '1';

WHEN 19 =>TONE<=1728;       --CODE <=5; HIGH<= '1';

WHEN 20 =>TONE<=1763;       --CODE <=6; HIGH<= '1';

WHEN OTHERS=>NULL;

    END CASE;

END PROCESS;

用2047减去每个音节的初值,就是实现此音节的分频数。

Fenpin模块

entity fenpin is

      Port ( res :in std_logic;

            over :in std_logic;

              pause:in std_logic;

            CLK1M : in  STD_LOGIC;

            TONE: IN INTEGER RANGE 0 TO 16#7FF# ;

           SPKS : out  STD_LOGIC);

end fenpin;

architecture Behavioral of fenpin is

SIGNAL FULLSPKS: STD_LOGIC;

SIGNAL COUNT11: INTEGER RANGE 0 TO 16#7FF#;

SIGNAL COUNT2: STD_LOGIC:='0';

begin

PROCESS( CLK1M, TONE)

BEGIN

IF CLK1M'EVENT AND CLK1M='1' THEN

    IF res = '1' or over='1' or pause ='1' then  

COUNT11<=16#7FF#;          --在复位,结束,暂停模式下,

                                      无音频信号输出

    elsif COUNT11=16#7FF# THEN

COUNT11<= TONE;

FULLSPKS<='1';               --每个音节对应自己的分频数,

                                       进行分频

ELSE COUNT11<=COUNT11+1;

FULLSPKS <='0';

    END IF;

END IF;

END PROCESS;

PROCESS( FULLSPKS )

BEGIN

IF FULLSPKS'EVENT AND FULLSPKS='1' THEN

COUNT2<=NOT COUNT2;

IF COUNT2='1' THEN SPKS <='1';

ELSE SPKS <='0';

    END IF;                       --D触发器,对每个音节已经分的频率再次2分频。

END IF;

END PROCESS;

qupu模块

Signal COUNTER : INTEGER RANGE 0 TO 215;

signal s0,s1,s2,s3: std_logic:='0';

begin

process(clk1m)

begin

if rising_edge(clk1m) then 

if res='1' then

s0<='1';

s1<='0';

s2<='0';

s3<='0';                         --复位时设置状态为S0

elsif s0='1' then

  if music='1' then

s0<='0';

s1<='1';

s2<='0';

s3<='0';                    --S0状态时music有脉冲,则转到S1

                                 否则S0循环

  else

s0<='1';

s1<='0';

s2<='0';

s3<='0';

  end if;

elsif s1='1' then

  if music='1' then

s0<='0';

s1<='0';

s2<='1';

s3<='0';

  else

s0<='0';

s1<='1';

s2<='0';

s3<='0';                    --S1状态时music有脉冲,则转到S2

                                 否则S1循环

  end if;

elsif s2='1' then

  if music='1' then

s0<='0';

s1<='0';

s2<='0';

s3<='1';

  else

s0<='0';

s1<='0';

s2<='1';

s3<='0';                   --S2状态时music有脉冲,则转到S3

                                 否则S2循环

  end if;

end if;

end if;

end process;

process(CLK8,music)

 Begin

   If COUNTER=213 or music='1' then 

     COUNTER<=0;

   Elsif(CLK8'EVENT AND CLK8='1')then 

COUNTER<=COUNTER+1;            

   End if;                      --对曲谱的自动递增循环

End process;

PROCESS(COUNTER)

begin

if s0='1' then

CASE COUNTER IS

WHEN 0 =>TONEINDEX <=3;

WHEN 1 =>TONEINDEX <=3;

WHEN 2 =>TONEINDEX <=3;

WHEN 3 =>TONEINDEX <=3;

……………………………………………………………

以下是对不同状态下不同曲谱的描述,原理简单,这里不赘述。

6. LCD 模块

           entity lcd is

    Port ( res : in  STD_LOGIC;

           clk500 : in  STD_LOGIC;

           mlife10 : in  STD_LOGIC_VECTOR (3 downto 0);

           mscore100 : in  STD_LOGIC_VECTOR (3 downto 0);

           life10 : in  STD_LOGIC_VECTOR (3 downto 0);

           score100 : in  STD_LOGIC_VECTOR (3 downto 0);

           mlife1 : in  STD_LOGIC_VECTOR (3 downto 0);

           mscore10 : in  STD_LOGIC_VECTOR (3 downto 0);

           life1 : in  STD_LOGIC_VECTOR (3 downto 0);

           score10 : in  STD_LOGIC_VECTOR (3 downto 0);

           mscore1 : in  STD_LOGIC_VECTOR (3 downto 0);

           score1 : in  STD_LOGIC_VECTOR (3 downto 0);

           pause : in  STD_LOGIC;

              over:in  STD_LOGIC;

           output : out  STD_LOGIC_VECTOR (3 downto 0);

            lcd_en : out  STD_LOGIC;

            lcd_rs : out  STD_LOGIC;

            lcd_rw : out  STD_LOGIC);

end lcd;

architecture Behavioral of lcd is

type   my_state 

is(A,B,C,D,E,G,H,I,J,K,L,M,O,ra,rc,rd,re,rf,rg,rh,rj,rk,rm,rn,ro,rp,rs,rx,ry,                                                  sa,sc,sd,se,sf,sg,sh,sj,sk,sm,sn,so,sp,sx,sy);

signal state,next_state : my_state;

signal count: integer range 0 to 4:=0;

begin

lcd_en <= clk;              --对en使能的设置,使其等于500hz的时钟

lcd_rw<='0';                --设置rw为0

process(clk,res)

begin

 if res='1' then

state<=A;               --初始状态为A

 elsif rising_edge (clk) then

state <= next_state;

 end if;

end process;

process(state,next_state)

begin

lcd_rs<='0';

  case (state) is

when A=>

output<="0011";

     next_state<=B;

when B=>

output<="0011";

     next_state<=C;

when C=>

output<="0011";

     next_state<=D;

when D=>

output<="0010";

     next_state<=E;

when E=>

output<="0010";

     next_state<=G;

when G=>

output<="1000";

     next_state<=H;

when H=>

output<="0000";

     next_state<=I;

when I=>

output<="0110";

     next_state<=J;

when J=>

output<="0000";

     next_state<=K;

when K=>

output<="1100";

     next_state<=L;

when L=>

output<="0000";

     next_state<=M;

when M=>

output<="0001";

     next_state<=O;      --上面是对液晶的初始设置

when O=>

output<="1000";

     next_state<=ra;

when ra=>

output<="0000";

     next_state<=rc;       --液晶显示的地址

    when rc=>

lcd_rs<='1';

output<="0101";

next_state<=ps1;

when ps1=>

lcd_rs<='1';

      if pause = '1' then

output<="0000";

     next_state<=ps2;    --若PAUSE信号为高则显示P,否则显示S

        else

     output<="0011";

     next_state<=ps2;  

        end if;

when ps2=>

lcd_rs<='1';

        if pause = '1' then

output<="0100";

     next_state<=ps3;

        else

     output<="0101";

     next_state<=ps3;

        end if;

when ps3=>

lcd_rs<='1';

       if pause = '1' then

output<="0001";

     next_state<=ps4;

        else

     output<="0100";

     next_state<=ps4;    --若PAUSE信号为高则显示A,否则显示T

        end if;

when ps4=>

lcd_rs<='1';

       if pause = '1' then

output<="0101";

     next_state<=ps5;

        else

     output<="0100";

     next_state<=ps5;

        end if;

when ps5=>

lcd_rs<='1';

       if pause = '1' then

output<="0101";

     next_state<=ps6;

        else

     output<="0001";

     next_state<=ps6;     --若PAUSE信号为高则显示U,否则显示A

        end if;

when ps6=>

lcd_rs<='1';

       if pause = '1' then

output<="0101";

     next_state<=ps7;

        else

     output<="0101";

     next_state<=ps7;

        end if;

when ps7=>

lcd_rs<='1';

       if pause = '1' then

output<="0011";

     next_state<=ps8;

        else

     output<="0010";

     next_state<=ps8;     --若PAUSE信号为高则显示S,否则显示R

        end if;

when ps8=>

lcd_rs<='1';

       if pause = '1' then

output<="0100";

     next_state<=ps9;

        else

     output<="0101";

     next_state<=ps9;

        end if;

when ps9=>

lcd_rs<='1';

       if pause = '1' then

output<="0101";

     next_state<=rd;

        else

     output<="0100";

     next_state<=rd;      --若PAUSE信号为高则显示E,否则显示T

        end if;

when rd=>

output<="1000";

     next_state<=rd1;

when rd1=>

output<="0111";

     next_state<=mh1;    --液晶显示地址

when mh1=>

lcd_rs<='1';

output<="0100";

     next_state<=mh2;

when mh2=>

lcd_rs<='1';

output<="1101";

     next_state<=mh3;    --显示M

when mh3=>

lcd_rs<='1';

output<="0101";

     next_state<=mh4;

when mh4=>

lcd_rs<='1';

output<="0011";

     next_state<=mh5;    --显示S

when mh5=>

lcd_rs<='1';

output<="0011";

     next_state<=mh6;

when mh6=>

lcd_rs<='1';

output<=mscore100;

     next_state<=mh7;

when mh7=>

lcd_rs<='1';

output<="0011";

     next_state<=mh8;

when mh8=>

lcd_rs<='1';

output<=mscore10;

     next_state<=mh9;

when mh9=>

lcd_rs<='1';

output<="0011";

     next_state<=mh10;

when mh10=>

lcd_rs<='1';

output<=mscore1;

     next_state<=mh11;     --以上显示最大分数

when mh11=>

lcd_rs<='1';

output<="0100";

     next_state<=mh12;

when mh12=>

lcd_rs<='1';

output<="1101";

     next_state<=mh13;    --显示M

when mh13=>

lcd_rs<='1';

output<="0100";

     next_state<=mh14;

when mh14=>

lcd_rs<='1';

output<="1100";

     next_state<=mh15;     --显示L

when mh15=>

lcd_rs<='1';

output<="0011";

     next_state<=mh16;

when mh16=>

lcd_rs<='1';

output<=mlife10;

     next_state<=mh17;

when mh17=>

lcd_rs<='1';

output<="0011";

     next_state<=mh18;

when mh18=>

lcd_rs<='1';

output<=mlife1;

     next_state<=rj;     --以上显示最大生命值

when rj=>

output<="1100";

     next_state<=rk;

when rk=>

output<="0000";

     next_state<=rx;     --选择液晶显示地址

when rx=>

lcd_rs<='1';

        if over='1' then

     output<="0100";

        else

     output<="0101";

        end if;

     next_state<=ry;

when ry=>

lcd_rs<='1';

       if over='1' then

     output<="0111";

        else

     output<="0011";

        end if;

     next_state<=rm;   --若OVER为1,显示G,否则显示S

when rm=>

lcd_rs<='1';

       if over='1' then

     output<="0100";

        else

     output<="0011";

        end if;

     next_state<=rn;

when rn=>

lcd_rs<='1';

       if over='1' then

     output<="0001";

        else

     output<=score100;

        end if;

     next_state<=rn1;   --若OVER为1,显示A,否则显示分数的百位

when rn1=>

lcd_rs<='1';

       if over='1' then

     output<="0100";

        else

     output<="0011";

        end if;

     next_state<=ro;

when ro=>

lcd_rs<='1';

       if over='1' then

     output<="1101";

        else

     output<=score10;

        end if;

     next_state<=rp;  --若OVER为1,显示M,否则显示分数的十位

when rp=>

lcd_rs<='1';

       if over='1' then

     output<="0100";

        else

     output<="0011";

        end if;

     next_state<=rs;

        

when rs=>

lcd_rs<='1';

       if over='1' then

     output<="0101";

        else

     output<=score1;

        end if;

     next_state<=sa;     --若OVER为1,显示E,否则显示分数的个位

when sa=>

lcd_rs<='1';

       if over='1' then

     output<="0100";

        else

     output<="0010";

        end if;

     next_state<=sc;

when sc=>

lcd_rs<='1';

        if over='1' then

     output<="1111";

        else

     output<="0000";

        end if;

     next_state<=sd;  --若OVER为1,显示O,否则显示空格

when sd=>

lcd_rs<='1';

         if over='1' then

     output<="0101";

        else

     output<="0100";

        end if;

     next_state<=se;

when se=>

lcd_rs<='1';

        if over='1' then

     output<="0110";

        else

     output<="1100";

        end if;

     next_state<=sf;      --若OVER为1,显示V,否则显示L

when sf=>

lcd_rs<='1';

       if over='1' then

     output<="0100";

        else

     output<="0011";

        end if;

     next_state<=sg;

when sg=>

lcd_rs<='1';

       if over='1' then

     output<="0101";

        else

     output<=life10;

        end if;

     next_state<=sh;   --若OVER为1,显示E,否则显示生命的十位

when sh=>

lcd_rs<='1';

       if over='1' then

     output<="0101";

        else

     output<="0011";

        end if;

     next_state<=go1;

    

when go1=>

lcd_rs<='1';

       if over='1' then

     output<="0010";

        else

     output<=life1;  --若OVER为1,显示R,否则显示生命的个位

        end if;

     next_state<=O;  --回到O状态循环检测数值的变化

   end case;

●系统仿真

1.分数计算模块

包括了几乎所有可能的按键取值,通过仿真可以看出各种情况都满足要求,同时最分数和最大生命数满足要求。不随复位键更改。

2.其余模块

我做的另外两个模块都无法通过仿真验证,所以是在板子上验证的。

其中LCD模块验证结果如下

●实验总结:

这次的实验在难度上要比上次所作的交通灯要大很多,不过可能是因为在交通灯中学到了不少经验,对于整个流程有了一个比较正确的方向性,所以在软件这一块感觉很轻松,其中比较有难度的一个是分数与按键的匹配判定,还有一个就是音乐的生成,通过画状态图,还有上网查资料,一切都还顺利。

最有难度,也是花了最多时间的反而是硬件,本来觉得这个外接电路并不复杂,PCB应该不难设计,可是真正设计来才发现它的难度,多次的返工几乎让我们放弃,可是当时的感觉就是已经花了这么多的时间,放弃实在是不忍心,骑虎难下啊!终于把PCB设计完,在制作过程中仍旧是一波多折,因为对流程的不熟悉,还有操作的不灵活,导致印制的板子失败了三次,整整两天,终于把板子做好,以为可以放心的焊接上电,新的问题接踵而来,因为设计的失误,导致铜线过细,焊接上一个不小心就造成短路,焊完后才发现这个问题,此时近百的焊点一个一个排查,着实是个大工程,可怜我和潘峰,一个拿万用表,一个拿着电路板,一个姿势就是几个小时,问题出现就要解决,解决短路的问题又引出新的问题,因为铜线过细,一个不小心,铜线就断掉了,用焊锡接,又一个不小心,短路了……如此重复,等到最终作完,才发现,除去前期的思考和学习,真正的制作过程有6天,其中4天竟然都是在做硬件……

虽然困难重重,但却深刻的感觉到学到了很多东西,前路慢慢,仍需努力啊!

最后很感谢杨老师给我的帮助,没有您的指导,我必然要走更多的弯路,没有上过您的FPGA的课,我也不可能完成的这么轻松!

谢谢您!!

●附录(管脚分配)

NET "button<0>" LOC = "D7" ;

NET "button<1>" LOC = "C7" ;

NET "button<2>" LOC = "F8" ;

NET "button<3>" LOC = "E8" ;

NET "clk50m"  LOC = "C9"  ; 

NET "lcd_en"  LOC = "M18"  ; 

NET "lcd_rs"  LOC = "L18"  ; 

NET "lcd_rw"  LOC = "L17"  ; 

NET "music_out"  LOC = "A6"  ;

NET "output<0>" LOC = "R15" ;

NET "output<1>" LOC = "R16" ;

NET "output<2>" LOC = "P17" ;

NET "output<3>" LOC = "M15" ;

NET "pause"  LOC = "L13"  ; 

NET "random<0>" LOC = "B4" ;

NET "random<1>" LOC = "A4" ;

NET "random<2>" LOC = "D5" ;

NET "random<3>" LOC = "C5" ;

NET "res"  LOC = "L14"  ;

 下载本文

显示全文
专题