一、分析
一个简单的乒乓球游戏系统可以分为上图中的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位置放置10个LED,可用来表示状态。另外,在1~6号位置再加6个按键,用来表示两边的接球。
规则:
开始由左边发球,发球准备的时候左边1,2,3号LED同时亮起,等待左边选手按下1,2,3按键中任意一个,按下相应的按键的时候,对应的LED熄灭,同时7号LED亮起,过一秒后,7号LED和其余两个LED熄灭,对面8号LED亮起,表示球已经飞过去。
球飞过去的时候,假设到达6号位置(可能性是任意的),6号LED应该亮起(8号LED应该熄灭),此时右边的选手应该按下6号按键来接球,如果在1秒按下按键,则6号LED熄灭,1秒后,对方7号LED亮起,表示球已经被接回去;否则,如果在1秒钟内没有按下按键,则10号LED也亮起,表示接球失败,左方得一分。然后10号LED闪两下,4,5,6号LED亮起,表示右边准备重新发球。
然后按下4,5,6任意按键发球,相应LED熄灭,8号LED亮起,1秒后7号LED亮起,如此反复,直到某一方的得分达到设定值结束。
时间规定:
从1,2,3号飞向8号——1秒
8号飞向4,5,6任意位置——1秒
接球有效时间——1秒
球落地后,延时——1秒
10号LED闪两下——1秒
然后4,5,6号LED亮起,等待发球时间——5秒(也可以不设,一直等到发球为止)
关于如何让球飞向4,5,6号(或者1,2,3号)中任意位置的实现
这是一个随机算法,需要设计一个随机种子,但考虑到设计的复杂性,可以做一个伪随机算法,或者更简单点的,直接规定球飞的方向。
例如下图,只要保证每个状态有一个进、一个出的方向即可实现。
当然,这个规定的方向应该被保密,只有设计者知道。
二、FSM实现(VHDL)
方向direction :
L2R 从左到右
R2L 从右到左
状态 states:
S1 对应9号位置
S2 对应1,2,3号位置
S3 对应7号位置
S4 对应8号位置
S5 对应4,5,6号位置
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
用户1584993 2009-9-15 11:01