数字电路与逻辑设计实验报告两人乒乓球游戏机.doc
.数字电路与逻辑设计实验实验报告姓 名:XXX班 级:xxxxxxxx学 号:xxxxxxxx一、设计课题的任务要求 两人乒乓球游戏机是以8*8点阵作为场地,中间的6*6共36个点作为球台,最外围的一圈点作为球拍移动的轨道,并通过数码管显示双方的局数和比分。双方个通过3个按钮控制球拍的上下移动及发球(场上无球时)。球接触到球拍后会自动改变方向和速度(在一定范围内)。当球在甲方的半场移动出球台范围后,乙方得分,然后重新发球。直到达到规定比分后,比赛结束。(1) 以8*8点阵作为场地,中间的6*6共36个点作为球台,最外围的一圈点作为球拍移动的轨道,通过两个按键控制球拍的移动;(2) 球的移动速度:在x,y方向上均为0.2s/点0.6s/点(可为0),会在击球时按一定规则自动改变;(3) 通过按钮移动球拍,球拍不能移出自己的半场(8*4);(4) 球出界后,自动判定得分,球从球场中消失,等待下一次发球;(5) 用数码管显示局数和比分,参考正式比赛规则,采用7局4胜制:当一方得分超过11分,并超过对方两分时,本局比赛结束,当一方率先赢得4局时,比赛结束,此时数码管保持最终比分。(6) 按下复位键,比分清零,双方重新开始比赛;(7) 双方按乒乓球比赛规则获得发球权,没有发球权的一方,发球开关无效。二、系统设计1、设计思路用x,y两坐标表示8*8点的每个点。分别用一组信号表示球和两球拍的坐标,以及球的移动速度。以一定周期(0.1s),改变球的坐标,以达到移动球的目的,用一组信号(xm、ym)记录球经过几个周期(0.1s)在想x或y方向上移动一个点,通过改变这两个信号的大小,即可控制球移动的速度和方向。球拍的移动由按钮控制,鉴于球拍只在最外圈移动,只需要上下两个按钮即可。当球拍在y方向上移动到边缘时,会自动转为在x方向上移动。球拍长度为3个点,只需记录中间点的位置即可。当球与球拍接触时(球的坐标与球拍中心的坐标在x,y两个方向的差均不大于1),根据球与球拍中心的相对位置,改变xm、ym,从而将球击回。当球位于边缘部分时,自动更新比分,并将球的坐标更改为特殊值(x=0),使球在台面上消失。此时发球按钮生效,按下发球按钮后,会将球的坐标及球速按一定规则重置,球再次开始移动。当比分符合一定规则时,将自动清零,并更新局数,有一方局数为4时,时分频器不再提供时钟信号。所有功能停止,系统保持在最后状态,直到复位。系统时钟为50MHz,通过两级分频器分别产生1kHz和10Hz的时钟信号供各模块使用。数码管和8*8点钟使用1kHz的时钟信号,以扫描方式输出,其中球拍和球台与球在不同周期交替显示,以简化系统。1kHz的时钟信号同时用于按键防抖动。10Hz时钟信号用于球的坐标更新以及出界、击球等状态的判定。2、总体框图3、分块设计图4、流程图注:图中梯形表示按键输入5、状态转移图三、波形仿真及波形分析1、分频器 本设计中用到1000Hz和10Hz的时钟信号,采用两级分频器,由50MHz的主时钟信号产生。分频器1:输入50MHz时钟信号,产生1000Hz时钟信号(占空比为调节,为1/50000)分频器2:输入1000Hz时钟信号(分频器1产生),产生10Hz时钟信号(占空比为调节,为1/100)2、球拍移动 本模块集成了按键防抖动功能。lf为向上移动,ri为向下移动,reset重置;1、2表示两名球员。球拍(racket)的坐标(rx1,ry1为球拍1的横纵坐标,rx2,ry2为球拍2的横纵坐标)表示其位置。球拍在8*8场地的最外圈移动,却不会超出各自半场。Reset键按下时,坐标复位3、球台显示 根据输入的球坐标(x,y)球拍坐标(racketx,rackety)显示球,球台和球拍。row,colg和colr为控制矩阵显示的输出,输出为扫描方式。 特别要指出的是,所有坐标的有效范围均不超过为1-8(特别的x为0不显示球),而球拍只能在8*8矩阵的最外围显示。波形中超出此范围的赋值不予考虑。4、数码管输出 数码管采用扫描输出,cat1-6(共阴极)分别对应,球员1的局数(innings1),比分的十位、个位(score11,score10),球员2比分的十位、个位(score21,score20),局数(innings2)。app为数码管输出,cat为共阴极,0电平选通。5、球移动 由于情况过多,顾不采用枚举法,而通过仿真依次验证其功能。 发球后球在两板的中间点间反弹,速度逐渐上升(范围0-5,到达5后不再上升)racketx、y分别为板的横纵坐标,xmo、ymo为两方向上的移动速度,球的坐标以xmo、ymo为速度,按一定周期改变。xo、yo为球的横纵坐标。球从板的边缘反弹后,会改变y方向上的速度,达到最外圈(本例中为x=8)后判断为出界,x设为0以记录球在场外,等待下一次发球交换发球权:发球时,将球的坐标设置在板的中间点之前(x=racketx1+1或racketx2-1,y=rackety1或y2),按乒乓球比赛规则,发两次球后交换发球权(此时另一方的发球键无效)开局时,只有player1有发球权。此为第三次发球,为player2发球。6、计分模块当球在球台最外围(x,y中有至少一个等于1或8)时判断为出界,并自动更改比分,按乒乓球比赛规则,得分率先超过11分,切高于对方2分时,赢得一局。如始终无法超出对方2分,则率先得到21分者赢得本局。赢得四局后比赛结束。系统停止在最后状态(保持比分),知道按下reset键后方重新运行。score11、score21为十位,score10、score20为个位,innings1、2为局数取值范围x为0到8,y为1到8。超过这个范围的情况不予考虑。赢得4局后系统停止,等待reset复位。注:1、上述5、球移动和6、计分模块因多次仿真,故无法提供直接可用的波形文件,如需仿真,请在:报告分块仿真 下找到相应的工程自行按上图设置仿真条件并仿真,以上波形图均为作者如此仿真操作后生成。2、因本设计较为复杂,采用总体仿真难以设计全面的仿真条件(要考虑球在台上的各种反弹情况),同时也无法直观地观察实验结果以及检查程序中出现的问题(输出为数码管以及8*8点阵的坐标,并且为扫描输出方式,不以观察),故在各模块仿真正确的情况下,不再进行整体仿真四、源程序-filename : table_tennis-author : ShenKewei-time : 2011-10-10-library ieee;use ieee.std_logic_1164.all;entity table_tennis isport(lf1,lf2,ri1,ri2,serve1,serve2 : in std_logic;-1,2 : two player ; lf: move left ; ri :move right ; hit : hit the ball ;reset : in std_logic;row : out std_logic_vector(7 downto 0); colg,colr : out std_logic_vector(0 to 7); - row,colg,colr : 8*8 outputcat : out std_logic_vector(1 to 6); -digitron chioceaap : out std_logic_vector(0 to 7); -digitronclk : in std_logic);end table_tennis;architecture a of table_tennis is signal cl_1000: std_logic ; -1000Hz clocksignal cl_10 : std_logic ; -10Hz clocksignal x : integer range 0 to 8 ;signal y : integer range 1 to 8 ; -x,y : coordinatesignal xm : integer range 0 to 5 ;signal ym : integer range 0 to 5 ; -xm,ym:the length ball move at once in the directionsignal xmd ,ymd : integer range 0 to 1 ; -the direction in which the ball movessignal score10,score11 : integer range 0 to 9;signal score20,score21 : integer range 0 to 9; -different digitals of both players' scoressignal innings1,innings2 : integer range 0 to 4; -players' innings signal rackety1,rackety2 : integer range 1 to 8; signal racketx1 : integer range 1 to 4; signal racketx2 : integer range 5 to 8; -rackets'coordinatessignal serve_flag1,serve_flag2 : integer range 0 to 2; -flag of the right to servesignal hit_flag1,hit_flag2 : integer range 0 to 1 ; - right to hitconstant speed : integer := 5 ;procedure dig (signal num: in integer range 0 to 9; signal out1 : out std_logic_vector(0 to 7) is -output of digital tubesbegincase num iswhen 0 => out1 <="11111100"when 1 => out1 <="01100000"when 2 => out1 <="11011010"when 3 => out1 <="11110010"when 4 => out1 <="01100110"when 5 => out1 <="10110110"when 6 => out1 <="00111110"when 7 => out1 <="11100000"when 8 => out1 <="11111110"when 9 => out1 <="11100110"end case;end procedure dig;beginp1 : process(clk)-get 1000Hz clock-variable count1 : integer range 1 to 50000 ; beginif clk'event and clk ='1' then if count1=50000 then count1 := 1; cl_1000<='1' else count1 :=count1+1; cl_1000<='0' end if; end if; end process p1;P2 : process(cl_1000)-get 10Hz clock-variable count2 : integer range 1 to 100 ; beginif cl_1000'event and cl_1000 ='1' then if count2=100 then cl_10 <='1' count2 := 1; else cl_10 <='0' count2 :=count2+1; end if;end if; end process p2;p3 : process(cl_1000)-8*8 output-variable count3 : integer range 1 to 8 ;variable countf : std_logic ; -flag of whet to showbeginif cl_1000'event and cl_1000='1' then if countf='1' then -show the table and racket countf:='0' if count3=8 then count3:=1; else count3:=count3+1; end if; case count3 is - scanning when 1 => row <="11111110" when 2 => row <="11111101" when 3 => row <="11111011" when 4 => row <="11110111" when 5 => row <="11101111" when 6 => row <="11011111" when 7 => row <="10111111" when 8 => row <="01111111" end case; if (count3=1 or count3=8) then -upside/downside colg<="00000000" if rackety1=count3 then case racketx1 is when 1 => colr(1 to 3) <="100" when 2 => colr(1 to 3) <="110" when 3 => colr(1 to 3) <="111" when 4 => colr(1 to 3) <="011" end case; else colr(1 to 3) <="000" end if; if rackety2=count3 then case racketx2 is when 5 => colr(4 to 6) <="110" when 6 => colr(4 to 6) <="111" when 7 => colr(4 to 6) <="011" when 8 => colr(4 to 6) <="001" end case; else colr(4 to 6) <="000" end if; else colr(1 to 6)<="000000" colg(0 to 7)<="01111110" end if; if (rackety1=count3 and racketx1<=2) or (rackety1-count3=1 or rackety1-count3=-1) and racketx1=1) then -racket of player1 colr(0) <='1' else colr(0) <='0' end if; if (rackety2=count3 and racketx2>=7) or (rackety2-count3=1 or rackety2-count3=-1) and racketx2=8) then -racket of player2 colr(7) <='1' else colr(7) <='0' end if; elsif countf='0' then -show the ball countf:='1' if y/=count3 then colr<="00000000" else case x is when 0 => colr <="00000000" when 1 => colr <="10000000" when 2 => colr <="01000000" when 3 => colr <="00100000" when 4 => colr <="00010000" when 5 => colr <="00001000" when 6 => colr <="00000100" when 7 => colr <="00000010" when 8 => colr <="00000001" end case; end if; end if;end if;end process p3;p4 : process(cl_10)-move the ball-if ball move out of the table ,renew the score and innings-variable countx,county : integer range 0 to speed ; - countersbeginif cl_10'event and cl_10='1' and (innings1/=4 and innings2/=4) or reset='1') thenif x/=0 thenif xm/=0 thenif countx+xm=6 then -the ball moves at xm*0.1 secondscase xmd iswhen 0 => x<=x-1;when 1 => x<=x+1;end case;countx:=0;else countx:=countx+1;end if;else countx:=0;end if;if ym/=0 thenif county+ym=6 then -the ball moves at ym*0.1 secondscase ymd iswhen 0 => y<=y-1;when 1 => y<=y+1;end case;county:=0;else county:=county+1;end if;else county:=0;end if;end if; if x=0 and serve1='1' then -serve the ball if serve_flag1/=0 then x<=racketx1+1;y<=rackety1; -put the ball hit_flag1<=0;hit_flag2<=1; -give right to hit xmd<=1;xm<=1;ym<=0; -reset the speed serve_flag1<=serve_flag1-1; if serve_flag1=1 then serve_flag2<=2; end if; end if; end if; if x=0 and serve2='1' then if serve_flag2/=0 then x<=racketx2-1;y<=rackety2; hit_flag1<=1;hit_flag2<=0; xmd<=0;xm<=1;ym<=0; serve_flag2<=serve_flag2-1; if serve_flag2=1 then serve_flag1<=2; end if; end if; end if; -renew the xm, ym-(hit the ball)- if hit_flag1=1 and xmd=0 then - plarer 1 has right to hit and ball move to him if rackety1>=2 and rackety1<=7 and x=2 then - ball moves into the racket if rackety1=y then xmd<=1; - ball moves backwards in the direction of x hit_flag1<=0; hit_flag2<=1; - change the right to hit if xm/=speed then xm<=xm+1; -renew the speed end if; if ym/=speed and ym/=0 then ym<=ym+1; end if; elsif rackety1-y=1 then xmd<=1; hit_flag1<=0; hit_flag2<=1; if ym=0 then ym<=1; ymd<=0; else case ymd is when 1 => ym<=ym-1; when 0 => if ym/=speed then ym<=ym+1; end if; end case; end if; elsif rackety1-y=-1 then xmd<=1; hit_flag1<=0; hit_flag2<=1; if ym=0 then ym<=1; ymd<=1; else case ymd is when 0 => ym<=ym-1; when 1 => if ym/=speed then ym<=ym+1; end if; end case; end if; end if; elsif (rackety1-y=1 or rackety1-y=-1) and (rackety1=1 or rackety1=8) and ym /=0 then if racketx1-x=-1 then xmd<=1; ymd<=1-ymd; hit_flag1<=0; hit_flag2<=1; if xm/=speed then xm<=xm+1; end if; if ym/=speed then ym<=ym+1; end if; elsif racketx1=x then xmd<=1; ymd<=1-ymd; hit_flag1<=0; hit_flag2<=1; xm<=xm-1; elsif racketx1-x=-2 then xmd<=1; ymd<=1-ymd; hit_flag1<=0; hit_flag2<=1; if xm/=speed then xm<=xm+1; end if; end if; elsif x=2 and racketx1=1 and (rackety1=1 and y=2) and ym=0 then xmd<=1; ymd<=1; hit_flag1<=0; hit_flag2<=1; ym<=1; elsif x=2 and racketx1=1 and (y=7 and rackety1=8) and ym=0 then xmd<=1; ymd<=0; hit_flag1<=0; hit_flag2<=1; ym<=1; end if; end if; if hit_flag2=1 and xmd=1 then - plarer 2 has right to hit and ball move to him if rackety2>=2 and rackety2<=7 and x=7 then if rackety2=y then xmd<=0; hit_flag1<=1; hit_flag2<=0; if xm/=speed then xm<=xm+1; end if; if ym/=speed and ym/=0 then ym<=ym+1; end if; elsif rackety2-y=1 then xmd<=0; hit_flag1<=1; hit_flag2<=0; if ym=0 then ym<=1; ymd<=0; else case ymd is when 1 => ym<=ym-1; when 0 => if ym/=speed then ym<=ym+1; end if; end case; end if; elsif rackety2-y=-1 then xmd<=0; hit_flag1<=1; hit_flag2<=0; if ym=0 then ym<=1; ymd<=1; else case ymd is when 0 => ym<=ym-1; when 1 => if ym/=speed then ym<=ym+1; end if; end case; end if; end if; elsif (rackety2-y=1 or rackety2-y=-1) and (rackety2=1 or rackety2=8) and ym/=0 then if racketx2-x=1 then xmd<=0; ymd<=1-ymd; hit_flag1<=1; hit_flag2<=0; if xm/=speed then xm<=xm+1; end if; if ym/=speed then ym<=ym+1; end if; elsif racketx2-x=2 then xmd<=0; ymd<=1-ymd; hit_flag1<=1; hit_flag2<=0; if xm/=speed then xm<=xm+1; end if; elsif racketx2=x then xmd<=0; ymd<=1-ymd; hit_flag1<=1; hit_flag2<=0; xm<=xm-1; end if; elsif x=7 and racketx2=8 and (rackety2=1 and y=2) and ym=0 then xmd<=0; ymd<=1; hit_flag1<=1; hit_flag2<=0; ym<=1; elsif x=7 and racketx2=8 and (y=7 and rackety2=8) and ym=0 then xmd<=0; ymd<=0; hit_flag1<=1; hit_flag2<=0; ym<=1; end if; end if; if x=1 then - out of the table x<=0; - the mark of time-out if score20=9 then score21<=score21+1; score20<=0; else score20<=score20+1; end if; elsif x=8 then x<=0; if score10=9 then score11<=score11+1; score10<=0; else score10<=score10+1; end if; elsif (y=1 or y=8) and x/=0 then x<=0; if x<=4 then if score20=9 then score21<=score21+1; score20<=0; else score20<=score20+1; end if; else if score10=9 then score11<=score11+