资源描述
(完整word)数字系统设计实验--猜拳游戏的设计与实现
数字系统设计实验报告
实验名称:猜拳游戏的设计与实现
学 院:
班 级:
姓 名:
学 号:
日 期: 2019年12月
指导老师:
目录
一、 设计课题的任务要求
基本要求:
提高要求:
模块电路要求:………………………………………………………………………………….
二、 系统设计
1、设计思路
2、总体框图
3、分块设计
1:分频模块
2:按键、防抖模块
3:判断模块
4:点阵显示模块
5: 计分模块
6:数码管显示模块
7: 蜂鸣器模块…………………………………………………………………..。…………。.
三、 仿真波形及波形分析
四、 源程序
源程序:
原理图:
五、 功能说明及资源利用情况
1、功能说明
2、资源利用状况
3、元件清单
六、 故障及问题分析
1、防抖
七、 总结和结论
一、 设计课题的任务要求
题目 4 猜拳游戏的设计与实现
本电路可供甲乙二人进行猜拳游戏。通过不同的按键控制,选择多种出拳方式,显示猜拳的结果,实现猜拳游戏,防止了作弊的可能。
基本要求:
1、 甲乙双方各用三个按键模拟“石头”、“剪刀”、“布”, BTN7、 BTN6、 BTN5 为甲,BTN2、 BTN1、 BTN0 为乙;
2、裁判用 BTN3 表示“准备", BTN4 表示“开”;
3、 每局比赛开始前裁判先宣布“准备”, 点阵显示全灭,然后甲乙双方分别选择出拳方式(以最后一次选择为准);
4、裁判按“开”以后,用点阵的左右三列同时显示甲乙双方的猜拳选择(如下图所示),并用两个数码管显示甲乙的猜拳比分;
5、猜拳游戏为五局三胜制。若甲乙双方出拳一致,则比分保持不变,双方重新出拳;
6、比赛结束后,用 8× 8 点阵显示获胜方;
7、用拨码开关作为复位键, 复位后游戏重新开始。
提高要求:
1、 点阵显示增加游戏开机动画、结束动画;
2、 为游戏增加音效;
3、 在 LCD1602 液晶屏上显示甲乙双方的猜拳比分;
4、 自拟其他功能.
模块电路要求:
甲、乙出拳共有 9 种情况,用 4 位拨码开关做输入,当拨码对应的二进制数为 0001~1001时,在点阵上分别显示 9 种不同的出拳情况,显示图案如基本要求 4;当拨码对应的二进制数为其他值时,点阵不显示。
二、 系统设计
1、设计思路
(1)确定初步方案,进行系统设计和描述
明确猜拳游戏的任务、要求、原理和使用环境,系统外部输入信号(按键输入猜拳)及输出信号(显示获胜方,比分,输入)的特性,以及系统所需要完成的逻辑功能和所要达到的技术指标等,然后确定初步方案。
描述方法:方框图、定时图(时序图)、逻辑流程图.
(2)主要考虑问题
首先根据实验的基本要求,可以知道至少需要进行三次甲乙的比赛才能分出猜拳游戏的胜负出来.首先是甲和乙出拳方式的选择:BTN7、BTN6、BTN5是甲进行石头、剪刀、布的选择,BTN2、BTN1、BTN0是乙进行石头、剪刀、布的选择。并把按键输入的状态选择存下来。其次是裁判的选择:BTN4是裁判的选择键,开键就会在8×8 点阵上出现甲和乙的出拳方式,同时数码管上开始计分。下一次按下准备键后甲乙原来选择的出拳方式不在了,但是数码管上比分依旧保存,甲乙开始再次比赛输入猜拳方式,重复进行比赛,直到一方比分累计达到三分(即满足五局三胜要求),一局比赛结束,点阵上会显示胜利者。
但是我们还要在上述基本思想下注意如下几个问题:
1:知道如何将按键瞬间产生脉冲电平保持..
2:由于按键输入不稳定,数字跳变太快,所以需要加键盘防抖模块.
3:键盘防抖模块需要特殊的频率,所以分频器模块不止一个。
(3)系统划分,进行子系统功能描述
主要涉及以下几个模块。分频器模块,计分模块,按键防抖模块,判断模块,点阵显示模块,数码管显示模块,蜂鸣器模块。
确定使用这些子系统,以及各子系统与控制器之间的关系。对各子系统和控制器进行功能描述:ASM图、结构图等。逻辑描述,完成具体设计,设计具体电路。
2、总体框图
1:数字系统结构框图
点阵显示
甲乙出拳方式
控制器
裁判输入
蜂鸣器出声
数码管显示
时钟
子系统
子系统
数据处理器
2:逻辑划分方框图
3:ASM流程图
3、分块设计
1:分频模块
分频程序主要由3个程序来实现,利用分频的思想,从50MHz经过过分频模块,得到1000Hz,5MHz,5Hz的时钟信号,用于,防抖模块、扫描显示模块以及蜂鸣器发声频率。
2:按键消抖模块
使用的按键是机械弹性开关,按下时闭合,松开后自动断开。在按键操作时,
在触电闭合和开启的瞬间会出现电压抖动,如图 5 所示.为了保证按键识别的准确性,必须进行去抖动处理,消除抖动部分的信号。
3:判断模块
通过左右两边各三个按键输入,通过检测按键前后电平作为依据得出输入并将其存入寄存器,一旦裁判按下open键寄存器锁死,此时按键输入无效。然后对寄存器中输入状态进行比对,判定胜负,输出得分以及状态,状态传到显示模块将二者输入在点阵上显示出来,得分传入计分模块用于累计分数。
点阵能稳定显示某一图形是利用了人眼的视觉暂留现象.点阵的扫描方式主要有三种:按行扫描、按列扫描、按点扫描,这里选用了按行扫描。对于每一个显示状态,利用 1kHz 的时钟信号对点阵进行逐行扫描,可以得到稳定的点阵显示画面。点亮点阵上某一点的条件是对应的 row 管脚为低电平,col 管脚为高电平。
这里采用计数器模式,通过一个模8计数器循环扫描,甲乙输入状态会在8×8点阵显示出来,以及最后显示胜利者的图案也是如此。
4:点阵显示模块
…
…
…
…
5:计分模块
由判断模块中传过来的数据score,根据数据对甲乙赋分,score为10时,甲得一分,乙不变,当score为01时,乙得一分,甲不变,平局时传入score为00,甲乙分数不变,二者每次得分均通过两个寄存器存储,当一方达到3分时,停止传入数据,比赛结束,判断胜利方,并将结果传至显示模块。
6:数码管显示模块
将分数转换为数码管显示对应的译码数据,在一盘游戏中,甲或乙赢都会在对应的数码管中加1分,若此盘比赛中,甲乙出拳方式一样,则比分不变,即数码管显示的分不变,数码管中的分数实时显示累计和
7:蜂鸣器模块
蜂鸣器这里需要5Hz和5MHz频率,利用计数器分频后获得,查乐谱获得歌曲的调。利用频率 5Hz 的时钟信号作为节拍控制信号.具体的音阶则继续分频产生。
三、 仿真波形及波形分析
1。点阵显示模块
能够把扫描时按行扫描清晰表现出来,以及实际中九种比赛情况
2.判断模块
能够把输入输出以及寄存,对比判断的过程描述下来以及向计分模块,显示模块的输出显示出来。
3.计分模块
能够把判断模块中传过来每一次比赛的分数累计,并判断是否一方达到三分,结束一局比赛,输出结果,将分数传给数码管显示模块,将结果传给点阵显示模块,显示胜利一方。仿真很好的显示了这个过程。
4。数码管显示模块
将计分模块中传过来的双方分数实时显示,这里通过对两个数码管扫描显示比分.
四、 源程序:
module dajiaoya ( ready,play1,play2,open,clk, rst,col,row,seg_led_1,seg_led_2,speaker);
input ready,open,clk,rst; //准备键,裁判键,时钟,复位
input [2:0] play1,play2; //猜拳输入
output [7:0] row,col; //点阵扫描
output [7:0] seg_led_1,seg_led_2; //数码管显示比分
output speaker; //音频
…
…
…//剩下附加于附件
五 、功能说明及资源利用情况
1、 功能说明
比赛开始,裁判按下BTN3,准备比赛开始。甲乙通过左右三个按键输入选择猜拳方式,确定后,裁判按下BTN4确认键,确认双方输入,点阵上能够显示双方刚才输入,此时无法通过按键再修改输入。数码管上能够显示这次比赛比分.裁判再次按下准备键,再一次比赛开始重复进行,直到有一方达到三分,比赛结束,点阵显示获胜方,实现了蜂鸣器播放音乐的效果。
2、 资源利用状况
由编译结果可得:本程序一共使用逻辑单元394个 ,占用率为31%。使用逻辑管脚43个,占用率是37%。
3、元件清单
EPM1270T144C5型号FPGA版一块,电脑一台。
六、 故障及问题分析
1、防抖
起初没加防抖之前,按键有时会经常发生改变,有的时候甚至不起作用,状态跳转非常没有统一性.后来通过课件和自己查找资料加上防抖模块之后问题得到了解决.
2、ready,open
裁判打开键和准备键的处理要细心,要处理好触发条件和产生效果。在仿真图像中和预期对比,不断寻找逻辑错误,重复处理。最后处理好了这几者关系。
七、 总结和结论
这学期来做了很多小脚丫的实验,相对来说逻辑比较简单,也积累了一些逻辑经验和verilog的debug经验。但都是自己尝试摸索,比较耗时间,但非常值得.对于这个大实验一开始对其有一些想法,整体流程还是比较清晰,但此前程序都是大段一块写。这次尝试了模块化操作,按照逻辑实现从输入到判定再到显示,输出比分的流程,分块操作,利用主程序直接调用,顶层模块调用。以前只会在quartus中综合编译找出错误,但模块化后更多情况却是在quartus中都能通过,但实际却报错没有效果。学会了仿真后,利用仿真先能直接找出模块与顶层模块之间端口对应,位宽对应错误等等基本问题,这些在quartus中都是能够通过的,二逻辑错误我们就需要看到仿真图像了,实际中每一个变量的变化都能显示出来,完全可以按照自己设计预想与图像对比找错.
此外通过学习这些,我也更加懂得了硬件描述语言与软件语言的不同,以及硬件如何实现快速的操作效果.
比较遗憾的是自己精力时间有限,转专业课多考试多又赶上期末,还有提升和其他想法也未能实现。
然后自学确实不容易,网上资源很多,很多报错能够在网上找到,有些问题也能够询问老师同学得到解决,实验虽然繁琐耗时,但是每个模块出来时也是很高兴的。还有要和老师同学多交流,思考,谦虚一点懂得请教,成长更快收获更多,最后感谢老师同学的帮助吧!
参考文献
[1]袁东明等.现代数字电路与逻辑设计实验教程(第二版) 北京:北京邮电大学出
版社,2016.
[2]王金明。数字系统设计与 VHDL(第 2 版) 北京:电子工业出版社,2016。
[3]Enoch O.Hwang。 Digital System Design with Verilog and VHDL Second Edition
北京:电子工业出版社,2016.
附件:源程序
1.顶层模块
module dajiaoya ( ready,play1,play2,open,clk, rst,col,row,seg_led_1,seg_led_2,speaker); //顶层模块
input ready,open,clk,rst; //准备键,裁判键,时钟,复位
input [2:0] play1,play2; //猜拳输入
output [7:0] row,col; //点阵扫描
output [7:0] seg_led_1,seg_led_2; //数码管显示比分
output speaker; //音频
wire open_d;
wire [3:0] sw_s;
wire [2:0] score_s,score1_s,score2_s;
wire [1:0]result_d;
debounce debo_u1 //例化模块消抖
(
.clk (clk),
。rst (rst),
.key_in (open),
.key_out (open_d)
);
judge jud_u1 //例化判断模块
(
.ready (ready),
。clk (clk),
.rst (rst),
。play1 (play1),
。play2 (play2),
.score (score_s),
。open (open_d),
.sw (sw_s)
);
xianshi xia_u1 //例化点阵显示模块
(
.rst (rst),
.clk (clk),
。open (open_d),
。ready (ready),
.col (col),
.row (row),
。sw (sw_s),
。result (result_d)
);
scores sco_u1 //例化计分模块
(
.rst (rst),
.clk (clk),
.open (open_d),
.score (score_s),
。score1 (score1_s),
。score2 (score2_s),
。result (result_d)
);
segled seg_u1 //例化数码管显示分数模块
(
。rst (rst),
.clk (clk),
。score1 (score1_s),
。score2 (score2_s),
。seg_led_1 (seg_led_1),
。seg_led_2 (seg_led_2)
);
beeps beep //例化蜂鸣器音乐模块
(
.clk_50M(clk),
。rst(rst),
.speaker(speaker)
);
Endmodule
2.消抖模块
module debounce(
input wire clk, rst,
input wire key_in,
output reg key_out
);
// 20ms parameter
// localparam TIME_20MS = 1_000_000;
localparam TIME_20MS = 20; // just for test
// variable
reg [20:0] cnt;
reg key_cnt;
// debounce time passed, refresh key state
always @(posedge clk or posedge rst) begin
if(rst == 1)
key_out <= 0;
else if(cnt == TIME_20MS — 1)
key_out 〈= key_in;
end
// while in debounce state, count, otherwise 0
always @(posedge clk or posedge rst) begin
if(rst == 1)
cnt 〈= 0;
else if(key_cnt)
cnt <= cnt + 1’b1;
else
cnt 〈= 0;
end
//
always @(posedge clk or posedge rst) begin
if(rst == 1)
key_cnt 〈= 0;
else if(key_cnt == 0 && key_in != key_out)
key_cnt <= 1;
else if(cnt == TIME_20MS - 1)
key_cnt 〈= 0;
end
endmodule
3.判断模块
module judge (ready,rst,clk,open,play1,play2,sw,score);
input rst,clk,ready,open;
input [2:0] play1,play2; //选手输入猜拳方式
output [3:0] sw; //对应九种情况
output [1:0] score; //每次比赛结果,甲胜输出10,乙胜输出01
reg [5:0] play,play1_d,play2_d; //用于寄存选手输入状态,左右按键被按下前后状态
reg [1:0] score_d;
reg [3:0] sw_d;
reg state;
always @(posedge clk or posedge rst)
begin
if(rst) //总复位键,开局键
state=0;
else if(ready) //准备键,按下后点阵显示复位
state=1;
else if(open) //裁判键,按下后输入状态不可更改,点阵显示输入双方状态
state=0;
end
always @(posedge clk)
begin
if(state)
begin
play2_d 〈= {play1,play2};//通过判断按键前后电平得到按键信息
play1_d 〈= play2_d;
if((play1_d[5]==0)&&(play2_d[5]==1))
play[5:3] = 3'b100;
else if((play1_d[4]==0)&&(play2_d[4]==1))
play[5:3] = 3’b010;
else if((play1_d[3]==0)&&(play2_d[3]==1))
play[5:3] = 3'b001;
else if((play1_d[2]==0)&&(play2_d[2]==1))
play[2:0] = 3'b100;
else if((play1_d[1]==0)&&(play2_d[1]==1))
play[2:0] = 3'b010;
else if((play1_d[0]==0)&&(play2_d[0]==1))
play[2:0] = 3’b001;
case (play)//九种状态对应输出显示以及输出输赢结果
6'b100100: begin sw_d = 4'b1001; score_d = 2'b01;end
6'b100010: begin sw_d = 4’b0001; score_d = 2'b10;end
6'b100001: begin sw_d = 4’b0010; score_d = 2’b00;end
6'b010100: begin sw_d = 4’b0011; score_d = 2'b00;end
6'b010010: begin sw_d = 4'b0100; score_d = 2'b01;end
6’b010001: begin sw_d = 4’b0101; score_d = 2’b10;end
6'b001100: begin sw_d = 4'b0110; score_d = 2'b10;end
6’b001010: begin sw_d = 4’b0111; score_d = 2'b00;end
6'b001001: begin sw_d = 4'b1000; score_d = 2'b01;end
default: ;
endcase
end
end
assign score = score_d;
assign sw = sw_d;
endmodule
4.显示模块
module xianshi ( sw,result, ready,open,clk,rst, row, col );
input clk,ready,rst,open;
input [3:0] sw;
input [1:0] result;
output [7:0] row,col;
reg state,dis;
reg [7:0] col,row;
reg [2:0] cnt;
always @(posedge clk or posedge rst)
begin
if(rst)
begin state=0;dis=0;end
else if(ready)
begin state=1;dis=0;end
else if(open)
begin state=0;dis=1;end
end
always @(posedge clk)
begin
if(state==1)
cnt=3'b000;
if(dis==1)
cnt=cnt+1'b1;
end
always @(cnt)
if(rst)
begin row=8'b11111111;col=8'b00000000;end
else if(sw==4'b1001) //布VS剪刀
case(cnt)
3'b000:begin row=8'b11111110;col=8'b00000000;end
3'b001:begin row=8'b11111101;col=8'b00000000;end
3’b010:begin row=8'b11111011;col=8’b11100100;end
3'b011:begin row=8’b11110111;col=8’b11100011;end
3'b100:begin row=8’b11101111;col=8'b11100011;end
3’b101:begin row=8'b11011111;col=8'b11100100;end
3’b110:begin row=8’b10111111;col=8’b00000000;end
3'b111:begin row=8'b01111111;col=8’b00000000;end
default:;
endcase
else if(sw==4’b0001) //布VS石头
case(cnt)
3'b000:begin row=8'b11111110;col=8’b00000000;end
3'b001:begin row=8’b11111101;col=8’b00000000;end
3'b010:begin row=8'b11111011;col=8’b11100010;end
3’b011:begin row=8'b11110111;col=8’b11100111;end
3'b100:begin row=8’b11101111;col=8'b11100111;end
3'b101:begin row=8'b11011111;col=8'b11100010;end
3’b110:begin row=8’b10111111;col=8’b00000000;end
3’b111:begin row=8’b01111111;col=8'b00000000;end
default:;
endcase
else if(sw==4’b0010) //布VS布
case(cnt)
3'b000:begin row=8'b11111110;col=8'b00000000;end
3’b001:begin row=8'b11111101;col=8’b00000000;end
3'b010:begin row=8'b11111011;col=8’b11100111;end
3’b011:begin row=8’b11110111;col=8'b11100111;end
3’b100:begin row=8'b11101111;col=8’b11100111;end
3’b101:begin row=8'b11011111;col=8'b11100111;end
3'b110:begin row=8'b10111111;col=8’b00000000;end
3’b111:begin row=8'b01111111;col=8’b00000000;end
default:;
endcase
else if(sw==4'b0011) //剪刀VS剪刀
case(cnt)
3'b000:begin row=8’b11111110;col=8’b00000000;end
3'b001:begin row=8'b11111101;col=8’b00000000;end
3'b010:begin row=8'b11111011;col=8'b00100100;end
3'b011:begin row=8'b11110111;col=8'b11000011;end
3'b100:begin row=8’b11101111;col=8’b11000011;end
3’b101:begin row=8'b11011111;col=8'b00100100;end
3'b110:begin row=8’b10111111;col=8’b00000000;end
3'b111:begin row=8’b01111111;col=8'b00000000;end
default:;
endcase
else if(sw==4'b0100) //剪刀VS石头
case(cnt)
3’b000:begin row=8’b11111110;col=8'b00000000;end
3'b001:begin row=8’b11111101;col=8’b00000000;end
3’b010:begin row=8'b11111011;col=8’b00100010;end
3'b011:begin row=8'b11110111;col=8'b11000111;end
3'b100:begin row=8'b11101111;col=8’b11000111;end
3'b101:begin row=8’b11011111;col=8'b00100010;end
3’b110:begin row=8'b10111111;col=8’b00000000;end
3’b111:begin row=8'b01111111;col=8’b00000000;end
default:;
endcase
else if(sw==4’b0101) //剪刀 VS布
case(cnt)
3'b000:begin row=8’b11111110;col=8'b00000000;end
3’b001:begin row=8'b11111101;col=8'b00000000;end
3'b010:begin row=8'b11111011;col=8'b00100111;end
3'b011:begin row=8'b11110111;col=8'b11000111;end
3'b100:begin row=8’b11101111;col=8’b11000111;end
3'b101:begin row=8’b11011111;col=8’b00100111;end
3’b110:begin row=8’b10111111;col=8’b00000000;end
3'b111:begin row=8’b01111111;col=8’b00000000;end
default:;
endcase
else if(sw==4'b0110) //石头VS剪刀
case(cnt)
3’b000:begin row=8'b11111110;col=8’b00000000;end
3'b001:begin row=8'b11111101;col=8'b00000000;end
3'b010:begin row=8'b11111011;col=8'b01000100;end
3’b011:begin row=8'b11110111;col=8’b11100011;end
3'b100:begin row=8’b11101111;col=8'b11100011;end
3’b101:begin row=8'b11011111;col=8'b01000100;end
3'b110:begin row=8’b10111111;col=8'b00000000;end
3’b111:begin row=8'b01111111;col=8’b00000000;end
default:;
endcase
else if(sw==4’b0111) //石头VS石头
case(cnt)
3'b000:begin row=8’b11111110;col=8'b00000000;end
3'b001:begin row=8’b11111101;col=8'b00000000;end
3'b010:begin row=8’b11111011;col=8'b01000010;end
3'b011:begin row=8’b11110111;col=8'b11100111;end
3’b100:begin row=8'b11101111;col=8’b11100111;end
3’b101:begin row=8’b11011111;col=8'b01000010;end
3’b110:begin row=8’b10111111;col=8’b00000000;end
3'b111:begin row=8’b01111111;col=8'b00000000;end
default:;
endcase
else if(sw==4'b1000) //石头VS布
case(cnt)
3’b000:begin row=8'b11111110;col=8’b00000000;end
3’b001:begin row=8'b11111101;col=8’b00000000;end
3'b010:begin row=8’b11111011;col=8’b01000111;end
3'b011:begin row=8’b11110111;col=8'b11100111;end
3'b100:begin row=8'b11101111;col=8'b11100111;end
3’b101:begin row=8'b11011111;col=8’b01000111;end
3'b110:begin row=8'b10111111;col=8'b00000000;end
3’b111:begin row=8’b01111111;col=8'b00000000;end
default:;
endcase
else if(result==2’b10) //甲获得胜利
case(cnt)
3’b000:begin row=8'b11111110;col=8'b11111111;end
3'b001:begin row=8'b11111101;col=8'b10011001;end
3’b010:begin row=8'b11111011;col=8’b11111111;end
3'b011:begin row=8’b11110111;col=8’b10011001;end
3'b100:begin row=8’b11101111;col=8'b11111111;end
3’b101:begin row=8’b11011111;col=8’b00011000;end
3'b110:begin row=8'b10111111;col=8'b00011000;end
3'b111:begin row=8'b01111111;col=8’b00011000;end
default:;
endcase
else if(result==2'b01) //乙获得胜利
case (cnt)
3'b000:begin row=8'b11111110;col=8'b01111111;end
3’b001:begin row=8'b11111101;col=8’b00000011;end
3'b010:begin row=8’b11111011;col=8'b00000110;end
3’b011:begin row=8'b11110111;col=8’b00011000;end
3’b100:begin row=8'b11101111;col=8’b00110000;end
3’b101:begin row=8’b11011111;col=8’b01100000;end
3’b110:begin row=8’b10111111;col=8’b11000000;end
3'b111:begin row=8’b01111111;col=
展开阅读全文