原创 [原创]基于FSM的乒乓球游戏分析与实现

2009-9-15 10:17 2782 12 13 分类: FPGA/CPLD

点击开大图


一、分析


一个简单的乒乓球游戏系统可以分为上图中的10个位置。状态①~为接球的地方,⑦⑧为桌子上球弹一下的位置,⑨⑩为球落地的位置。


 


球落下的所有可能:


 


1.左边发球


S1->S7->S8


S2->S7->S8


S3->S7->S8


S8->S4,S5,S6 球可能飞向S4,S5,S6任意位置


S4->S10   球落地


S5->S10


S6->S10


 


2.右边发球


S4->S8->S7


S5->S8->S7


S6->S8->S7


S7->S1,S2,S3 球可能飞向S1,S2,S3任意位置


S1->S9


S2->S9


S3->S9


 

 


说明:


1~10位置放置10LED,可用来表示状态。另外,在1~6号位置再加6个按键,用来表示两边的接球。


 


规则:


开始由左边发球,发球准备的时候左边123LED同时亮起,等待左边选手按下123按键中任意一个,按下相应的按键的时候,对应的LED熄灭,同时7LED亮起,过一秒后,7LED和其余两个LED熄灭,对面8LED亮起,表示球已经飞过去。


球飞过去的时候,假设到达6号位置(可能性是任意的)6LED应该亮起(8LED应该熄灭),此时右边的选手应该按下6号按键来接球,如果在1秒按下按键,则6LED熄灭,1秒后,对方7LED亮起,表示球已经被接回去;否则,如果在1秒钟内没有按下按键,则10LED也亮起,表示接球失败,左方得一分。然后10LED闪两下,456LED亮起,表示右边准备重新发球。


然后按下456任意按键发球,相应LED熄灭,8LED亮起,1秒后7LED亮起,如此反复,直到某一方的得分达到设定值结束。


 


时间规定:


123号飞向8号——1


8号飞向456任意位置——1


接球有效时间——1


球落地后,延时——1


10LED闪两下——1


然后456LED亮起,等待发球时间——5秒(也可以不设,一直等到发球为止)


 


关于如何让球飞向456号(或者123号)中任意位置的实现


这是一个随机算法,需要设计一个随机种子,但考虑到设计的复杂性,可以做一个伪随机算法,或者更简单点的,直接规定球飞的方向。


例如下图,只要保证每个状态有一个进、一个出的方向即可实现。


点击开大图


当然,这个规定的方向应该被保密,只有设计者知道。


 


 


二、FSM实现(VHDL)


 


点击开大图


 


 


方向direction :


L2R  从左到右


R2L  从右到左


 


状态 states:


S1  对应9号位置


S2  对应123号位置


S3  对应7号位置


S4  对应8号位置


S5  对应456号位置


S6  对应10号位置


 


Key_left[0..2]  左方选手的3个按键


Key_right[0..2]  右方选手的3个按键


Key_buf    按键值缓存,也用作伪随机算法的随机因子。


 


VHDL代码:


library ieee;


use IEEE.std_logic_1164.all;


use IEEE.std_logic_unsigned.all;


 


entity pingpong is


port(


       clk : in std_logic;    --1KHz


       n_reset : in std_logic;


       key_left : in std_logic_vector(2 downto 0);


       key_right : in std_logic_vector(2 downto 0);


       led : out std_logic_vector(10 downto 1)


       );


end pingpong;


 


architecture arc of pingpong is


 


type state_direction is (L2R,R2L);


type state_location is (S1,S2,S3,S4,S5,S6);


 


signal direction : state_direction := L2R;


signal location : state_location := S2;


 


signal key_buf : std_logic_vector(2 downto 0);


signal score_left : std_logic_vector(7 downto 0);


signal score_right : std_logic_vector(7 downto 0);


signal count : std_logic_vector(7 downto 0);


signal delay : std_logic_vector(9 downto 0);


 


begin


 


       process(n_reset,clk)


       begin


       if (n_reset = '0') then


              location <= S2;


              direction <= L2R;


              score_left <= "00000000";


              score_right <= "00000000";


              count <= "00000000";


              delay <= "0000000000";


       elsif (clk'event and clk = '1') then


      


              case direction is


              when L2R =>


             


                     case location is


                     when S1 =>


                            if (count = "01100100") then


                                   location <= S2;


                                   score_right <= score_right + '1';


                                   count <= "00000000";


                                   led(9) <= '0';


                                   direction <= L2R;


                            else


                                   count <= count + '1';


                                   led(9) <= '1';


                            end if;


                           


                     when S2 =>


                            if (key_left = "100" or key_left = "010" or key_left = "001") then


                                   if (count = "00011110") then


                                          key_buf <= key_left(1 downto 0) & key_left(2); -- 伪随机算法


                                          led(3 downto 1) <= key_left;


                                          location <= S3;


                                          count <= "00000000";


                                          direction <= L2R;


                                   else


                                          count <= count + '1';


                                   end if;


                            else


                                   led(3 downto 1) <= "111";


                            end if;           


                                                       


                     when S3 =>


                            led(3 downto 1) <= "000";


                            if (count = "00110010") then


                                   led(7) <= '0';


                                   location <= S4;


                                   count <= "00000000";


                            else


                                   led(7) <= '1';


                                   count <= count + '1';


                            end if;


                           


                     when S4 =>


                            if (count = "00110010") then


                                   led(8) <= '0';


                                   location <= S5;


                                   count <= "00000000";


                            else


                                   led(8) <= '1';


                                   count <= count + '1';


                            end if;


                           


                     when S5 =>


                            if (key_right = key_buf ) then


                                   if (count = "00011110") then


                                          location <= S3;


                                          key_buf <= key_buf(1 downto 0) & key_buf(2); --伪随机算法


                                          direction <= R2L;


                                          count <= "00000000";


                                          led(6 downto 4) <= "000";


                                   else


                                          count <= count + '1';


                                   end if;


                            elsif (delay = "0100000000" )then


                                   location <= S6;


                                   delay <= "0000000000";


                            else


                                   delay <= delay + '1';


                                   led(6 downto 4) <= key_buf;


                            end if;


                           


                     when S6 =>


                            if (count = "01100100") then


                                   location <= S5;


                                   score_left <= score_left + '1';


                                   count <= "00000000";


                                   led(10) <= '0';


                                   direction <= R2L;


                                   led(6 downto 4) <= "000";


                            else


                                   count <= count + '1';


                                   led(10) <= '1';


                            end if;


                     end case;


                    


              when R2L =>


                     case location is


                     when S1 =>


                            if (count = "01100100") then


                                   location <= S2;


                                   score_right <= score_right + '1';


                                   count <= "00000000";


                                   led(9) <= '0';


                                   direction <= L2R;


                            else


                                   count <= count + '1';


                                   led(9) <= '1';


                            end if;


                           


                     when S2 =>


                            if (key_left = key_buf ) then


                                   if (count = "00011110") then


                                          location <= S4;


                                          key_buf <= key_buf(1 downto 0) & key_buf(2); --伪随机算法


                                          direction <= L2R;


                                          count <= "00000000";


                                          led(3 downto 1) <= "000";


                                   else


                                          count <= count + '1';


                                   end if;


                            elsif (delay = "0100000000" )then


                                   location <= S1;


                                   delay <= "0000000000";


                            else


                                   delay <= delay + '1';


                                   led(3 downto 1) <= key_buf;


                            end if;


                           


                     when S3 =>


                            if (count = "00110010") then


                                   led(7) <= '0';


                                   location <= S2;


                                   count <= "00000000";


                            else


                                   led(7) <= '1';


                                   count <= count + '1';


                            end if;


                           


                     when S4 =>


                            led(6 downto 4) <= "000";


                            if (count = "00110010") then


                                   led(8) <= '0';


                                   location <= S3;


                                   count <= "00000000";


                            else


                                   led(8) <= '1';


                                   count <= count + '1';


                            end if;


                           


                     when S5 =>


                            if (key_right = "100" or key_right = "010" or key_right = "001") then


                                   if (count = "00011110") then


                                          key_buf <= key_right(1 downto 0) & key_right(2);--伪随机算法


                                          led(6 downto 4) <= key_right;


                                          location <= S4;


                                          count <= "00000000";


                                          direction <= R2L;


                                   else


                                          count <= count + '1';


                                   end if;


                            else


                                   led(6 downto 4) <= "111";


                            end if;


                           


                     when S6 =>


                            if (count = "01100100") then


                                   location <= S5;


                                   score_left <= score_left + '1';


                                   count <= "00000000";


                                   led(10) <= '0';


                                   direction <= R2L;


                            else


                                   count <= count + '1';


                                   led(10) <= '1';


                            end if;


                     end case;


              end case;


       end if;


       end process;


 


end arc;


 


仿真图:


 


左方发球,右方没有接到


点击开大图


左方发球,右方接到


点击开大图


右方发球,左方没接到


点击开大图


右方发球,左方接到


点击开大图


 


 


视频:


 


左边发球,开始后两边自动接球的情况:


http://v.youku.com/v_show/id_XMTE5MTM2MjM2.html







文章评论1条评论)

登录后参与讨论

用户1584993 2009-9-15 11:01

已经很久没有看到up兄的博客了,期待有更多的出来
相关推荐阅读
用户124183 2010-10-04 18:48
[Craftor原创]基于Verilog的I2C总线驱动设计
摘要:此版本的设计中,笔者将协议里对总线的操作细分为4个,即起始(Start)、写(Write)、读(Read)、停止(Stop),并给对应的操作编码:起始(1000)、写(0100)、读(0010)...
用户124183 2010-09-03 10:42
4/8/16/32/64位乘法器的设计
4/8/16/32/64位乘法器的设计,单个时钟周期运算出结果。思路如下:4位乘法器a,b输入,y输出。使用case语句,对于输入a,y输出是b输入的16种可能。单个周期内可以输出结果。8位乘法器a,...
用户124183 2010-09-02 15:32
除法器的设计与仿真(Verilog&VHDL)
最近在做算法,要用到除法。本来想使用除法器的IP核,但发现Xilinx的除法器IP核是流水线的,如果是批量的数做除法,自然是很快,也很方便。而我的算法中需要将前一次的结果算出来之后,再到下一次运算里做...
用户124183 2010-08-06 09:58
Modelsim中添加Xilinx仿真库
不少朋友在刚接触Xilinx的FPGA时,对仿真库的编译和使用不是很了解,而官方的说明也不是很详细,而且看起来有些费劲,这里Craftor给出在Modelsim中编译和使用Xilinx库的详细教程,P...
用户124183 2010-08-02 22:51
周末写了个51单片机软核
为了弥补这段时间的罪过,这个周末决定做宅男,写程序。其实酝酿51软核已经有好几个月时间了,之前是因为在一个地方卡住了,中间停止了。上周五上班的时候突然来了灵感,一下子想通了,呵呵代码不长,1000多行...
用户124183 2010-06-19 15:41
深入研究Modelsim之使用do文件仿真(1)
Modelsim的仿真功能非常强大,本文介绍使用do脚本仿真单个Verilog或者VHDL文件的操作过程,希望对大家有用!以带时钟和复位信号的计数器为例,代码如下:module counter (  ...
我要评论
1
12
关闭 站长推荐上一条 /2 下一条