数字电路与逻辑设计综合实验掷骰子游戏.docx
《数字电路与逻辑设计综合实验掷骰子游戏.docx》由会员分享,可在线阅读,更多相关《数字电路与逻辑设计综合实验掷骰子游戏.docx(61页珍藏版)》请在冰豆网上搜索。
数字电路与逻辑设计综合实验掷骰子游戏
数字电路与逻辑设计综合实验
掷骰子游戏电路的设计与实现
学院:
信息与通信工程学院
班级:
2012XXXXXX
学号:
2012XXXXXX
姓名:
学渣
班内序号:
XX
目录:
一、设计课题的任务要求……3
二、系统设计……3
1、设计思路……3
2、总体框图……4
(1)ASM图……4
(2)MDS图……6
3、分块设计……6
(1)分频器模块……6
(2)状态机控制模块(主功能模块)……7
(3)数码管显示模块……13
(4)点阵显示模块……13
三、仿真波形及波形分析……15
四、源程序及注释……17
五、功能说明及资源利用情况……39
六、实现效果图……40
七、故障及问题分析……43
八、总结和结论……44
一、设计课题的任务要求:
设计并实现一个掷骰子游戏电路。
基本要求:
1、电路可供甲乙二人游戏,游戏者甲使用的按键为BTN0,游戏者乙使用的按键为BTN1。
2、每按一次按键,代表掷一次骰子,可随机得到1~6范围内的两个数字。
3、甲乙按键产生的随机数字分别用数码管DISP0-DISP1、DISP2-DISP3显示,并用DISP7显示比赛局数,比赛结束用8×8点阵显示获胜方,并伴有声音效果。
4、具体游戏规则如下:
(1)第一局比赛,甲乙依次各按一次按键,按键所得两数之和为7或11者胜;若无人取胜,则进行第二局比赛;
(2)第二局比赛,甲乙每人各按一次按键,按键所得二数之和与第一局比赛相同者获胜,若无人获胜,则进行第三局比赛,重复进行步骤
(2),直到出现胜者为止。
(3)游戏局数最多进行六局。
在第六局比赛时,若重复进行步骤
(2)仍未出现胜者,以按键所得两数之和最大者为获胜方。
提高要求:
1、增加多人游戏的功能,数码管可分时记录显示每个游戏者的骰子点数。
2、点阵显示增加游戏开机动画、结束动画,并伴有乐曲播放。
3、自拟其它功能。
二、系统设计
1、设计思路:
系统结构框图如下:
由系统框图可以看出,该系统的核心部分是游戏控制模块,也即状态机部分。
游戏控制模块以外部输入的随机数生成信号、游戏控制信号以及时钟信号为依据,实现了甲乙随机数的产生,也即完成了甲乙掷骰子的效果;实现了每一局的比较,判别比赛的胜负;以及状态之间的转换。
最后,游戏控制模块输出的信号将分别给到数码管显示模块、点阵显示模块以及蜂鸣器播放模块,将游戏的结果以可视可听的效果呈现给玩家,实现优质的用户体验。
随机数生成信号由按键输入,游戏控制信号由拨码开关输入,时钟信号由实验板给出,数码管扫描显示、点阵扫描显示以及蜂鸣器的鸣响的频率则由各个不同的分频器给出。
为了更加方便的实现状态机、实现状态之间的跳转以及各个模块之间的连接,我采用了整体编写代码的方式,即将所有的程序代码都写在一个VHDL文件当中,其中以不同的进程来划分不同的模块。
2、总体框图:
ASM图:
游戏控制及状态转移部分的MDS图:
游戏控制模块有9个状态,athrow和bthrow分别是甲和乙掷骰子的状态,athrow是游戏启动的第一个状态,该状态下按下按键才会跳到bthrow状态,否则将保持在本状态。
在bthrow状态也是只有按下按键才会跳到s1~s6状态中,否则将会保持在本状态。
s0是过渡状态,在这个状态将所有的信号都初始化为原始的状态。
s1~s6是六个局数的状态。
转换到s1~s6之中的哪一个状态,是由next_state信号决定的。
3、分块设计:
分频器模块(以用于产生随机数两个分频器为例):
FENPINONE:
PROCESS(clk)
BEGIN
IFclk'eventANDclk='1'THEN
IFtmp1=6THEN
tmp1<=1;
clktmp1<=notclktmp1;
ELSE
tmp1<=tmp1+1;
ENDIF;
ENDIF;
ENDPROCESSFENPINONE;
FENPINTWO:
PROCESS(clktmp1)
BEGIN
IFclktmp1'eventANDclktmp1='1'THEN
IFtmp2=6THEN
tmp2<=1;
clktmp2<=notclktmp2;
ELSE
tmp2<=tmp2+1;
ENDIF;
ENDIF;
ENDPROCESSFENPINTWO;
这两个分频器实现了两个功能:
首先,tmp1和tmp2信号在整型数1至6之间进行计数,当按键按下时,随机数产生,也即tmp1信号将分别赋值给甲的disp0信号和乙的disp2信号,tmp2信号将分别赋值给甲的disp1信号和乙的disp3信号,用于数码管显示随机数,同时tmp1和tmp2还用于两个随机数的相加,以完成之后的比较判断,即如下所示:
disp0<=tmp1;
disp1<=tmp2;
jiaadd<=tmp1+tmp2;
disp2<=tmp1;
disp3<=tmp2;
yiadd<=tmp1+tmp2;
由于两个分频器所检测的时钟边缘不一样,并且甲乙游戏过程中按键的时刻不相同,所以随机性得以保证。
其次,这两个分频器结合,实现了对原始时钟信号的196分频。
其余的分频器与上述两个分频器的实现相同,由于数码管、点阵都需要扫描显示,并且点阵需要完成动画效果,蜂鸣器需要实现开机音乐,所以总共设置了八个分频器,分得的不同频率信号clktmp和计数信号tmp用于以上功能的实现。
状态机控制模块(主功能模块):
该模块用于实现随机数的产生、比较随机数的和、判断胜负关系、进行状态转移,以及实现胜利的声音效果和开机声音效果。
该模块主要用CASE-WHEN语句实现,关键分析如下:
(1)甲掷骰子的状态。
当CASE语句检测到athrow这个游戏状态时,将进入这个WHEN语句中。
在该状态下,如果甲按键,即btn0=‘1’,则将当前时刻分频器中的两个计数信号tmp1和tmp2赋值给数码管显示信号;将tmp
1和tmp2进行相加成为随机数之和,用于后续比较;将游戏状态gamestate转换为bthrow状态;由于这是掷骰子阶段,所以将游戏结果gameresult赋值为3,表示是过渡的状态。
如果甲没有按键,则游戏状态一直保持athrow这个状态。
由于这些都是对信号SIGNAL的赋值操作,只有当控制模块这个进程结束的时候信号赋值才会生效(其实这个时间很短,人看起来是近乎同时的),所以为了在一个人按键按下之后,而不是两个人按键都按下之后,数码管显示出当前比赛局数,我用一个register_disp7来事先存储局数,在甲按下按键的时候赋给disp7信号,实现上述功能。
(2)s0状态。
s0是某一方胜利之后将会跳转进入的状态,在这个状态中,实现对所有信号的初始化或者清零,避免进入下一场比赛后影响比赛的比较判断。
(3)s1状态。
s1表示的是第一局比赛的状态,在第一局比赛中,甲乙双方只要有某一方的随机数合数等于7或者11,那么那一方将获胜,否则将进入下一局。
若甲乙双方都满足以上条件,则产生平局,然后进入下一局。
在这个状态中,next_state信号也想当于一个寄存器,存储了该局比赛结束后的下一个状态,这样在掷骰子的时候才能判断该跳转进入哪一个状态。
tmpj和tmpy两个信号分别用于存储第一局甲乙两人投掷出的随机数之和,用于第二局至第六局的比较判断。
(4)s2~s5状态。
这四个状态分别代表了第二局至第五局的比赛状态,这四局比赛的比较判断标准都是一样的,只有当甲乙中的某一方的随机数合数等于他们自身的第一局随机数合数时,才能获胜。
若甲乙双方都满足以上条件,则产生平局,然后进入下一局。
(5)s6状态。
s6状态代表第六局比赛的状态,该局比赛下,先进行与前四局相同的比较判断,如果还没有胜利的一方出现,则随机数合数较大的一方胜利。
若甲乙双方都满足以上条件,则产生平局。
不论结果怎么样,游戏都将结束,状态跳转进入s0状态,将所有的信号初始化或者清零。
(6)甲乙胜利之后的声音效果。
为了区别甲胜或者乙胜,还分别使用了不同的时钟,在时钟信号等于’1’的时候,让蜂鸣器鸣响,时钟信号等于’0’的时候,蜂鸣器不鸣响。
(7)开机音乐模块。
以上部分(因为太长没有完全截图,详细请见源代码)实现的是开机音乐的播放功能,当复位信号reset为0的时候,CASE语句检测tmp8信号,tmp8信号的频率接近1Hz,因此音乐的每个音符的间隔大约为1秒。
当时钟信号为’1’时,蜂鸣器鸣响,不同的时钟信号,对应于不同的频率,频率不同则蜂鸣器发出的声音的音调也就有所不同。
所以,通过计算可以得出一首歌中音符对应的频率,然后通过分频器分出相应的频率,最终可以实现一首歌的播放功能。
数码管显示模块:
数码管的显示是通过扫描实现的,在扫描的过程中,每次扫描点亮一个数码管,同时将之前在控制模块接收随机数赋值的disp信号赋值给变量NUM,由于NUM是变量,赋值之后立即生效,所以可以在一个进程中的下一个CASE语句中立刻检测,然后让当前点亮的数码管显示出相应的随机数。
当扫描频率大于(30*6)Hz时,由于人眼暂留效应,玩家将看到五个数码管上的数字持续显示(有一个数码管没有用上,禁止其显示)。
但是,频率不能取得太高,否则会出现数码管亮度不够的情况。
点阵显示模块(只截取部分作解释):
点阵显示模块有两种模式,其一,是显示游戏的胜负平以及一个过渡状态,所以由CASE语句通过检测游戏结果gameresult这个信号来完成。
其二,是显示开机动画,用CASE语句检测tmp8信号,动画的每个画面停留的时间间隔大约为1秒,不同画面之间的跳转变换,组合成游戏的开机动画。
点阵的显示也是通过扫描实现的,行列信号各是8位信号,当点阵中的某一个点对应的行信号的位为0、列信号的位为1时,该点将被点亮。
这里实现的方案是运用了行扫描,即每隔一个时间间隔扫描一行,此时这行对应的行信号的位为0,再看列信号,列信号为1的位对应的该行的列就会被点亮。
根据这个原理,就可以一个一个将开机动画的图案在稿纸上确定下来,然后用程序实现。
三、仿真波形及波形分析:
Ø上图是乙按下按键之后的状态转移波形图。
可见,乙按下按键之前(btn1为低电平),游戏状态gamestate保持在bthrow状态,乙按下按键之后经过一个时钟周期,游戏状态转移到s1状态,即进入第一局进行比较判断,又经过一个时钟周期之后,比较判断结束,游戏状态转移到athrow状态,等待甲下一次按键。
Ø上图是点阵显示的仿真波形。
可见,点阵行信号一直在扫描,每次使能一行点阵,在行信号为0的时刻,对应的列信号的位为1时,则该行的对应列将被点亮。
波形分析如下:
(1)在甲掷骰子之后、乙掷骰子之前,点阵将显示绿色的过渡图案,即一个笑脸图案;
(2)甲乙第一次掷出骰子后,程序将进行比较判断,由图可以看出,仿真中出现的结果是平局,在点阵上将显示一个红色的“平”字样;
(3)甲乙第二次掷出骰子后,仿真中出现的结果是乙胜,在点阵上将显示绿色的“乙胜”字样,在下一次按键按下之前,可以看到,扫描会重复进行;
(4)甲乙第三次掷出骰子后,点阵将显示红色的“平”字样。
Ø上图左边和右边分别是甲、乙第一次按键之前之后的数码管信号的仿真波形图。
由图可见,不论甲乙按键与否,数码管使能信号SMGCAT都在逐个定时扫描,其中SMGCAT[1]一直设置为1,也即禁止其显示。
首先看左图,由于是第一次按键,甲按键之前的各种状态都是初始状态,所以SMGOUT信号为”0000001”,也即显示中间的一条横杆。
当甲按键按下产生两个随机数之后,SMGCAT[5]和SMGCAT[4]为0时,也即前两个数码管可以显示的时候,对应的SMGOUT信号的值变为”0110000”和”1011011”,分别对应数字1和5。
然后看右图,乙按键之前的状态一直保持不变,乙按键之后,SMGCAT[3]和SMGCAT[2]为0时,也即中间两个数码管可以显示的时候,对应的SMGOUT信号的值变为”0110000”和”0110000”,分别对应数字1和1。
此时,对应于甲掷出骰子的随机数显示SMGOUT信号没有变化,也即甲乙投掷骰子产生的随机数互相不影响。
四、源程序及注释:
--掷骰子游戏——信通XXXXXXX——2012XXXXXX
LIBRARYIEEE;
USEIEEE.STD_LOGIC_1164.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITYtouziIS
PORT(
clk:
INSTD_LOGIC;--时钟输入信号
reset:
INSTD_LOGIC;--开机动画开启关闭输入信号
start:
INSTD_LOGIC;--开始游戏按键
bnt0,bnt1:
INSTD_LOGIC;--按键信号输入
SMGCAT:
OUTSTD_LOGIC_VECTOR(5DOWNTO0);--数码管使能端输出信号
SMGOUT:
OUTSTD_LOGIC_VECTOR(6DOWNTO0);--数码管显示输出信号
-------------------------------------------------
clkout1,clkout2,clkout3,clkout4:
OUTSTD_LOGIC;--分频器输出时钟信号,为了分析的方便,仅此而已
-------------------------------------------------
row,col1,col2:
outstd_logic_vector(7downto0);--点阵行列输出信号,col1是红,col2是绿(行0列1时点阵亮)
beep_out:
OUTSTD_LOGIC--蜂鸣器输出信号
);
ENDtouzi;
ARCHITECTUREtouzisignalOFtouziIS
TYPEstate_typeIS(athrow,bthrow,s0,s1,s2,s3,s4,s5,s6);--游戏状态(甲掷乙掷&1~6局&s0过渡态用于复位)
SIGNALgamestate,next_state:
state_type;--游戏状态信号
--分频器中的计数标志
SIGNALtmp1:
INTEGERRANGE1TO6;--只取1~6避免出现异常情况
SIGNALtmp2:
INTEGERRANGE1TO6;
SIGNALtmp3:
INTEGERRANGE0TO49;
SIGNALtmp4:
INTEGERRANGE0TO49;
SIGNALtmp5:
INTEGERRANGE0TO49;
SIGNALtmp6:
INTEGERRANGE0TO12;
SIGNALtmp7:
INTEGERRANGE0TO5;
SIGNALtmp8:
INTEGERRANGE0TO24;
--分频后的时钟信号
SIGNALclktmp1:
STD_LOGIC;
SIGNALclktmp2:
STD_LOGIC;
SIGNALclktmp3:
STD_LOGIC;
SIGNALclktmp4:
STD_LOGIC;
SIGNALclktmp5:
STD_LOGIC;
SIGNALclktmp6:
STD_LOGIC;
SIGNALclktmp7:
STD_LOGIC;
SIGNALclktmp8:
STD_LOGIC;
SIGNALgameresult:
INTEGERRANGE0TO3;--游戏输赢结果(胜平&过渡状态),用于判断游戏状态走向&点阵显示
--SIGNALwinorlose:
STD_LOGIC;--胜利OR平局
SIGNALdisp0:
INTEGERRANGE0TO6;--D0~D3数码管信号的传递信号,显示随机数
SIGNALdisp1:
INTEGERRANGE0TO6;
SIGNALdisp2:
INTEGERRANGE0TO6;
SIGNALdisp3:
INTEGERRANGE0TO6;
SIGNALdisp7:
INTEGERRANGE0TO6;--显示局数
SIGNALregister_disp7:
INTEGERRANGE0TO6;--用于在上一个状态寄存局数信号
SIGNALjiaadd:
INTEGERRANGE0TO12;--甲两数和
SIGNALyiadd:
INTEGERRANGE0TO12;--乙两数和
SIGNALtmpj:
INTEGERRANGE0TO12;--甲的第一次两数和,用于判断前后合数是否相等
SIGNALtmpy:
INTEGERRANGE0TO12;--同上,为乙的
SIGNALcount:
INTEGERRANGE0TO5;--计数,用在SMG扫描显示中
--SIGNALkeybeep:
STD_LOGIC;
--SIGNALbeepcount:
INTEGERRANGE0TO40000;
--SIGNALbeeptmp:
STD_LOGIC;
SIGNALbeepstart:
STD_LOGIC;
--------------------------
--SIGNALmusic_state:
INTEGERRANGE0TO35;--音乐的状态
--SIGNALmcount1:
INTEGERRANGE0TO1000;
--SIGNALtone:
INTEGERRANGE0TO100000;
--SIGNALmspk_count:
INTEGERRANGE0TO100000;
------------------------
BEGIN
--分频器组
FENPINONE:
PROCESS(clk)--tmp1,tmp2用于产生随机数1~6
BEGIN
IFclk'eventANDclk='1'THEN
IFtmp1=6THEN
tmp1<=1;
clktmp1<=notclktmp1;
ELSE
tmp1<=tmp1+1;
ENDIF;
ENDIF;
ENDPROCESSFENPINONE;
FENPINTWO:
PROCESS(clktmp1)
BEGIN
IFclktmp1'eventANDclktmp1='1'THEN
IFtmp2=6THEN
tmp2<=1;
clktmp2<=notclktmp2;
ELSE
tmp2<=tmp2+1;
ENDIF;
ENDIF;
ENDPROCESSFENPINTWO;
FENPINTHREE:
PROCESS(clktmp2)
BEGIN
IFclktmp2'eventANDclktmp2='1'THEN
IFtmp3=7THEN
tmp3<=0;
clktmp3<=notclktmp3;
ELSE
tmp3<=tmp3+1;
ENDIF;
ENDIF;
ENDPROCESSFENPINTHREE;
FENPINFOURE:
PROCESS(clktmp3)
BEGIN
IFclktmp3'eventANDclktmp3='1'THEN
IFtmp4=1THEN
tmp4<=0;
clktmp4<=notclktmp4;
ELSE
tmp4<=tmp4+1;
ENDIF;
ENDIF;
ENDPROCESSFENPINFOURE;
FENPINFIVE:
PROCESS(clktmp4)--用tmp5来控制点阵扫描显示单个图案所以0~7
BEGIN
IFclktmp4'eventANDclktmp4='1'THEN
IFtmp5=7THEN
tmp5<=0;
clktmp5<=notclktmp5;
ELSE
tmp5<=tmp5+1;
ENDIF;
ENDIF;
ENDPROCESSFENPINFIVE;
FENPINJIASOUND:
PROCESS(clktmp5)--用其中的clktmp6信号来控制甲胜之后的声音效果
BEGIN
IFclktmp5'eventANDclktmp5='1'THEN
IFtmp6=12THEN
tmp6<=0;
clktmp6<=notclktmp6;
ELSE
tmp6<=tmp6+1;
ENDIF;
ENDIF;
ENDPROCESSFENPINJIASOUND;
FENPINYISOUND:
PROCESS(clktmp6)--用其中的clktmp7信号来控制乙胜之后的声音效果
BEGIN
IFclktmp6'eventANDclktmp6='1'THEN
IFtmp7=2THEN
tmp7<=0;
clktmp7<=notclktmp7;
ELSE
tmp7<=tmp7+1;
ENDIF;
ENDIF;
ENDPROCESSFENPINYISOUND;
FENPINDONGHUA:
PROCESS(clktmp7)--用tmp8信号控制点阵动画
BEGIN
IFclktmp7'eventANDclktmp7='1'THEN
IFtmp8=24THEN
tmp8<=0;
clktmp8<=notclktmp8;
ELSE
tmp8<=tmp8+1;
ENDIF;
ENDIF;
ENDPROCESSFENPINDONGHUA;
--只是为了分析波形方便---
clkout1<=clktmp1;
clkout2<=clktmp2;
clkout3<=clktmp3;
clkout4<=clktmp4;
-------------------------
-------状态机控制模块-------
--产生随机数&比较判断&状态转移&声音效果
SUIJISHU:
PROCESS(clk)
BEGIN
IF(start='0')THEN--初始化&复位
disp0<=0;
disp1<=0;
disp2<=0;
disp3<=0;
gamestate<=athrow;
g