北邮数电实验报告(猜数字)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

题目: 简易猜数字游戏机的设计与实现
姓名
学院
专业
班级
学号
班内序号
一、设计课题的任务要求
基本要求:
1、游戏规则:通常由两个人玩,一方出数字,另一方猜。

出数字的人要想好一个没有重复数字的 4 位数,不能让猜的人知道。

2、数字设置:通过 4*4 键盘进行 4 位数字输入,在数码管(DISP0~DISP3)上显示当前所输入的数字。

通过设置确定键(BTN1 键)进行锁定,此时数码管上的数值消失,同时用点阵开始倒计时,即:初始状态点阵全亮,然后从右下角开始,由右到左、由下到上逐点逐排依次熄灭,间隔时间为 1s,共计 64s。

3、猜数字:可以通过 4*4 键盘进行 4 位数字输入进行猜数字,且每输入一位数字在数码管(DISP0~DISP3)上显示当前所输入的数字,按确定键(BTN2 键)进行确认,此时要根据输入的这组数字给出几 A 几 B,其中:A前面的数字表示位置正确的数的个数,用DISP5显示B前的数字表示数字正确而位置不对的数的个数,用DISP4显示如正确答案为 2134,而猜的人猜 5314,则是1A2B,其中有一个4的位置对了,记为1A,而1和3这三个数字对了,而位置没对,因此记为 2B,合起来就是 1A2B 接着猜的人再根据出题者的几A几B继续猜,直到猜中(即 4A0B)为止。

4、若数字正确则显示猜数字成功,点阵显示“☺”笑脸;若输入数字错误
系统仍然处于猜数字状态,点阵显示“X”,并用蜂鸣器或 led 闪烁报警。

5、若到点阵全灭时(64s 结束)仍未猜出正确数字,游戏失败,点阵显示“囧”。

6、设置游戏机开关。

提高要求:
1、若数字正确则显示猜数字成功,用蜂鸣器播放一段乐曲。

2、随机产生数字,并不在数码管上显示,进行猜数字游戏,用点阵进行 128s 计时,即点阵轮询熄灭两次,其他要求同基本功能
3、4 和 5。

3、自拟其他功能。

二、系统设计
设计思路:首先是状态机的设定,设定了5个状态,分别是idle、s1、s2、s3和over。

idle是空白的等待状态,s1是输入要猜的数字状态,在s2状态输入猜的数字,确定后进入s3状态,没猜对会检测还有没有时间,有时间会回到s2状态,没时间会留在over状态,猜对了也会留在over状态,在s2状态发现没时间后会进入over状态。

详情可见状态框图。

分频器选择了1Hz和1000Hz,1Hz是点阵倒计时的频率,1000Hz是点阵、矩阵键盘、数码管、按键的扫描频率。

点阵倒计时上选择对count_down(倒计时)进行求余和除法运算,求余可以对点阵的每一行进行每次灭一个灯的行为,除法可以确定点阵亮的行数。

在输入数字时进行与前面输入数字的比较,如果发现数字出现重复的情况则不输入数字,直到输入不同的数字为止。

总体框图:
没有

不对,显示X
三、仿真波形及波形分析
为了方便仿真,在程序中加入了分辨当前所在状态的信号ld_out,idle状态时,ld_out为1000,s1时ld_out为0100,s2时为0010,s3为0001。

复位游戏开始确认输入的数字确认猜的数字复位
idle状态 s1状态 s2状态 s3状态 idle状态
四、源程序
部分代码分析:
分频器:
variable count3:integer:=0;
variable count4:integer:=0;
b egin
if clk'event and clk='1' then
if count4=12499 then
clk_scan<=not clk_scan; count4:=0;
if count3=12499999 then
clk_tm<=not clk_tm; count3:=0;
else count3:=count3+1;
end if;
else count3:=count3+1; count4:=count4+1;
end if;
end if;
count3为1Hz的频率,是点阵倒计时的频率;count4为1kHz的频率,是点阵、按键、数码管、矩阵键盘的扫描频率。

状态转移:
begin
next_state<=state;
if res='1' then next_state<=idle;
else
case state is
when idle =>
if st='1' then next_state<=s1;
else next_state<=idle;
end if;
when s1 =>
if ms1='1' then
next_state<=s2;
else next_state<=s1;
end if;
when s2 =>
if ms2='1' then
next_state<=s3;
elsif tm='1' then
next_state<=over;
else next_state<=s2;
end if;
when s3 =>
if done='1' then
next_state<=over;
else next_state<=s3;
end if;
when over =>
if st='1' then next_state<=idle;
elsif tf='0' then
if tm='0' then
next_state<=s2;
else next_state<=over;
end if;
else next_state<=over;
end if;
when others =>next_state<=idle;
end case;
end if;
idle是空白的等待状态,s1是输入要猜的数字状态,在s2状态输入猜的数字,确定后进入s3状态,没猜对会检测还有没有时间,有时间会回到s2状态,没时间会留在over状态,猜对了也会留在over状态,发现没时间后也会进入over状态
点阵显示:
begin
if clk_scan'event and clk_scan='1' then
if led=1 then --jiong
case led_row is
when "10111111" => led_row<="01111111";led_col<="11111111";
when "11011111" => led_row<="10111111";led_col<="10011001";
when "11101111" => led_row<="11011111";led_col<="10100101";
when "11110111" => led_row<="11101111";led_col<="11000011";
when "11111011" => led_row<="11110111";led_col<="10111101";
when "11111101" => led_row<="11111011";led_col<="10100101";
when "11111110" => led_row<="11111101";led_col<="10100101";
when "01111111" => led_row<="11111110";led_col<="11111111";
when others => led_row<="01111111";led_col<="11111111";
end case;
elsif led=2 then --xiao
case led_row is
when "10111111" => led_row<="01111111";led_col<="00111100";
when "11011111" => led_row<="10111111";led_col<="01000010";
when "11101111" => led_row<="11011111";led_col<="10100101";
when "11110111" => led_row<="11101111";led_col<="11011011";
when "11111011" => led_row<="11110111";led_col<="10000001";
when "11111101" => led_row<="11111011";led_col<="10100101";
when "11111110" => led_row<="11111101";led_col<="01011010";
when "01111111" => led_row<="11111110";led_col<="00111100";
when others => led_row<="01111111";led_col<="11111111";
end case;
elsif led=3 then --x
case led_row is
when "10111111" => led_row<="01111111";led_col<="10000001";
when "11011111" => led_row<="10111111";led_col<="01000010";
when "11101111" => led_row<="11011111";led_col<="00100100";
when "11110111" => led_row<="11101111";led_col<="00011000";
when "11111011" => led_row<="11110111";led_col<="00011000";
when "11111101" => led_row<="11111011";led_col<="00100100";
when "11111110" => led_row<="11111101";led_col<="01000010";
when "01111111" => led_row<="11111110";led_col<="10000001";
when others => led_row<="01111111";led_col<="11111111";
end case;
elsif led=4 then --kong
case led_row is
when "10111111" => led_row<="01111111";led_col<="00000000";
when "11011111" => led_row<="10111111";led_col<="00000000";
when "11101111" => led_row<="11011111";led_col<="00000000";
when "11110111" => led_row<="11101111";led_col<="00000000";
when "11111011" => led_row<="11110111";led_col<="00000000";
when "11111101" => led_row<="11111011";led_col<="00000000";
when "11111110" => led_row<="11111101";led_col<="00000000";
when "01111111" => led_row<="11111110";led_col<="00000000";
when others => led_row<="01111111";led_col<="00000000";
end case;
else
这里都是在显示特殊情况,下面是倒计时的显示:num_1是倒计时对8的取余,num_2是倒计时对8的除法运算。

对应每个num_1,有num_x对应不同的点阵行的亮灯情况,这样的话使得61秒的倒计时只需要分8种情况讨论,即每一行一种情况。

num_1<=count_down rem 8; --quyu
num_2<=count_down/8;
case num_1 is
when 0=> num_x <="00000000";
when 1=> num_x <="10000000";
when 2=> num_x <="11000000";
when 3=> num_x <="11100000";
when 4=> num_x <="11110000";
when 5=> num_x <="11111000";
when 6=> num_x <="11111100";
when 7=> num_x <="11111110";
when others => num_x <="00000000";
end case;
case num_2 is
when 0 =>
case led_row is
when "10111111" => led_row<="01111111";led_col<="11111111"-num_x;
when "11011111" => led_row<="10111111";led_col<="11111111";
when "11101111" => led_row<="11011111";led_col<="11111111";
when "11110111" => led_row<="11101111";led_col<="11111111";
when "11111011" => led_row<="11110111";led_col<="11111111";
when "11111101" => led_row<="11111011";led_col<="11111111";
when "11111110" => led_row<="11111101";led_col<="11111111";
when "01111111" => led_row<="11111110";led_col<="11111111";
when others => led_row<="01111111";led_col<="11111111";
end case;
when 1 =>
case led_row is
when "10111111" => led_row<="01111111";led_col<="00000000";
when "11011111" => led_row<="10111111";led_col<="11111111"-num_x;
when "11101111" => led_row<="11011111";led_col<="11111111";
when "11110111" => led_row<="11101111";led_col<="11111111";
when "11111011" => led_row<="11110111";led_col<="11111111";
when "11111101" => led_row<="11111011";led_col<="11111111";
when "11111110" => led_row<="11111101";led_col<="11111111";
when "01111111" => led_row<="11111110";led_col<="11111111";
when others => led_row<="01111111";led_col<="11111111";
end case;
when 2 =>
case led_row is
when "10111111" => led_row<="01111111";led_col<="00000000";
when "11011111" => led_row<="10111111";led_col<="00000000";
when "11101111" => led_row<="11011111";led_col<="11111111"-num_x;
when "11110111" => led_row<="11101111";led_col<="11111111";
when "11111011" => led_row<="11110111";led_col<="11111111";
when "11111101" => led_row<="11111011";led_col<="11111111";
when "11111110" => led_row<="11111101";led_col<="11111111";
when "01111111" => led_row<="11111110";led_col<="11111111";
when others => led_row<="01111111";led_col<="11111111";
e nd case;
when 3 =>
case led_row is
when "10111111" => led_row<="01111111";led_col<="00000000";
when "11011111" => led_row<="10111111";led_col<="00000000";
when "11101111" => led_row<="11011111";led_col<="00000000";
when "11110111" => led_row<="11101111";led_col<="11111111"-num_x;
when "11111011" => led_row<="11110111";led_col<="11111111";
when "11111101" => led_row<="11111011";led_col<="11111111";
when "11111110" => led_row<="11111101";led_col<="11111111";
when "01111111" => led_row<="11111110";led_col<="11111111";
when others => led_row<="01111111";led_col<="11111111";
e nd case;
when 4 =>
case led_row is
when "10111111" => led_row<="01111111";led_col<="00000000";
when "11011111" => led_row<="10111111";led_col<="00000000";
when "11101111" => led_row<="11011111";led_col<="00000000";
when "11110111" => led_row<="11101111";led_col<="00000000";
when "11111011" => led_row<="11110111";led_col<="11111111"-num_x;
when "11111101" => led_row<="11111011";led_col<="11111111";
when "11111110" => led_row<="11111101";led_col<="11111111";
when "01111111" => led_row<="11111110";led_col<="11111111";
when others => led_row<="01111111";led_col<="11111111";
e nd case;
when 5 =>
case led_row is
when "10111111" => led_row<="01111111";led_col<="00000000";
when "11101111" => led_row<="11011111";led_col<="00000000";
when "11110111" => led_row<="11101111";led_col<="00000000";
when "11111011" => led_row<="11110111";led_col<="00000000";
when "11111101" => led_row<="11111011";led_col<="11111111"-num_x;
when "11111110" => led_row<="11111101";led_col<="11111111";
when "01111111" => led_row<="11111110";led_col<="11111111";
when others => led_row<="01111111";led_col<="11111111";
e nd case;
when 6 =>
case led_row is
when "10111111" => led_row<="01111111";led_col<="00000000";
when "11011111" => led_row<="10111111";led_col<="00000000";
when "11101111" => led_row<="11011111";led_col<="00000000";
when "11110111" => led_row<="11101111";led_col<="00000000";
when "11111011" => led_row<="11110111";led_col<="00000000";
when "11111101" => led_row<="11111011";led_col<="00000000";
when "11111110" => led_row<="11111101";led_col<="11111111"-num_x;
when "01111111" => led_row<="11111110";led_col<="11111111";
when others => led_row<="01111111";led_col<="11111111";
e nd case;
when 7 =>
case led_row is
when "10111111" => led_row<="01111111";led_col<="00000000";
when "11011111" => led_row<="10111111";led_col<="00000000";
when "11101111" => led_row<="11011111";led_col<="00000000";
when "11110111" => led_row<="11101111";led_col<="00000000";
when "11111011" => led_row<="11110111";led_col<="00000000";
when "11111101" => led_row<="11111011";led_col<="00000000";
when "11111110" => led_row<="11111101";led_col<="00000000";
when "01111111" => led_row<="11111110";led_col<="11111111"-num_x;
when others => led_row<="01111111";led_col<="11111111";
e nd case;
when others =>
case led_row is
when "10111111" => led_row<="01111111";led_col<="11111111";
when "11011111" => led_row<="10111111";led_col<="11111111";
when "11101111" => led_row<="11011111";led_col<="11111111";
when "11110111" => led_row<="11101111";led_col<="11111111";
when "11111011" => led_row<="11110111";led_col<="11111111";
when "11111101" => led_row<="11111011";led_col<="11111111";
when "01111111" => led_row<="11111110";led_col<="11111111";
when others => led_row<="01111111";led_col<="11111111";
end case;
end case;
end if;
led_row_out<=led_row; led_col_out<=led_col;
end if;
如上是这8种情况。

数码管:
begin
if clk_scan'event and clk_scan='1' then
case state is
when idle =>
case cat is
when "111110" => cat<="011111";seg<="0000000";
when "011111" => cat<="101111";seg<="0000000";
when "101111" => cat<="110111";seg<="0000000";
when "110111" => cat<="111011";seg<="0000000";
when "111011" => cat<="111101";seg<="0000000";
when "111101" => cat<="111110";seg<="0000000";
when others => cat<="011111";seg<="0000000";
end case;
when s1 =>
case cat is
when "111110" => cat<="011111";seg<="0000000";
when "011111" => cat<="101111";seg<="0000000";
when "101111" => cat<="110111";seg<=x1;
when "110111" => cat<="111011";seg<=x2;
when "111011" => cat<="111101";seg<=x3;
when "111101" => cat<="111110";seg<=x4;
when others => cat<="011111";seg<="0000000";
end case;
when s2 =>
case cat is
when "111110" => cat<="011111";seg<=seg_a;
when "011111" => cat<="101111";seg<=seg_b;
when "101111" => cat<="110111";seg<=y1;
when "110111" => cat<="111011";seg<=y2;
when "111011" => cat<="111101";seg<=y3;
when "111101" => cat<="111110";seg<=y4;
when others => cat<="011111";seg<="0000000";
end case;
when s3 =>
case cat is
when "111110" => cat<="011111";seg<=seg_a;
when "011111" => cat<="101111";seg<=seg_b;
when "101111" => cat<="110111";seg<=y1;
when "110111" => cat<="111011";seg<=y2;
when "111011" => cat<="111101";seg<=y3;
when "111101" => cat<="111110";seg<=y4;
when others => cat<="011111";seg<="0000000";
end case;
when over =>
case cat is
when "111110" => cat<="011111";seg<=seg_a;
when "011111" => cat<="101111";seg<=seg_b;
when "101111" => cat<="110111";seg<=y1;
when "110111" => cat<="111011";seg<=y2;
when "111011" => cat<="111101";seg<=y3;
when "111101" => cat<="111110";seg<=y4;
when others => cat<="011111";seg<="0000000";
end case;
when others =>null;
end case;
cat_out<=cat; seg_out<=seg;
end if;
在s1状态只显示输入的4个数字,在其他状态均显示猜的4个数字和A、B 的数值。

矩阵键盘:
case key_row is
when "0111" =>
case scan is
when "0111" => key1<=data1;
when "1011" => key1<=data4;
when "1101" => key1<=data3;
when "1110" => key1<=data2;
when others => null;
end case;
when "1011" =>
case scan is
when "0111" => key1<=data5;
when "1011" => key1<=data8;
when "1101" => key1<=data7;
when "1110" => key1<=data6;
when others => null;
end case;
when "1101" =>
case scan is
when "0111" => key1<=data9;
when "1011" => key1<=data0;
when "1101" => key1<=data0;
when "1110" => key1<=data0;
when others => null;
end case;
when "1110" =>
case scan is
when "0111" => key1<=data0;
when "1011" => key1<=data0;
when "1101" => key1<=data0;
when "1110" => key1<=data0;
when others => null;
end case;
如上是矩阵键盘不同按键对应数字的定义,矩阵键盘顺序:
1 2 3 4
5 6 7 8
9 0 0 0
00 0 0;
case count1 is
when 0 =>
if key1 /= x4 then
x1<=key1; count1:=1;
else null;
end if;
when 1 =>
if key1 /= x1 then
x2<=key1; count1:=2;
else null;
end if;
when 2 =>
if key1 /= x2 and key1 /= x1 then
x3<=key1; count1:=3;
else null;
end if;
when 3 =>
if key1 /= x3 and key1 /= x1 and key1 /= x2 then
x4<=key1; count1:=0;
else null;
end if;
when others => null;
end case;
如上是将矩阵键盘输入的数字显示在数码管上的代码,同时判断输入的数字不能出现重复,相当于消除了键盘抖动的问题。

count_a:=0; count_b:=0;
if x1=y1 then count_a:=count_a+1;end if;
if x2=y2 then count_a:=count_a+1;end if;
if x3=y3 then count_a:=count_a+1;end if;
if x4=y4 then count_a:=count_a+1;end if;
if x1=y2 then count_b:=count_b+1;end if;
if x1=y3 then count_b:=count_b+1;end if;
if x1=y4 then count_b:=count_b+1;end if;
if x2=y1 then count_b:=count_b+1;end if;
if x2=y3 then count_b:=count_b+1;end if;
if x2=y4 then count_b:=count_b+1;end if;
if x3=y1 then count_b:=count_b+1;end if;
if x3=y2 then count_b:=count_b+1;end if;
if x3=y4 then count_b:=count_b+1;end if;
if x4=y1 then count_b:=count_b+1;end if;
if x4=y2 then count_b:=count_b+1;end if;
if x4=y3 then count_b:=count_b+1;end if;
如上是对A、B的计数,用基本的if语句。

详细程序见附件。

五、功能说明及资源利用情况
按BTN6按键开始游戏,即可开始用矩阵键盘输入数字,数字不能出现重复(输入了重复的数字时将不会算作输入了数字),如图,输入了6312:
按BTN1按键确定输入的数字即可开始游戏,开始计时:
用矩阵键盘输入猜的数字,数字不允许出现重复,按BTN2按键确定,如图输入1234,出现0和3表示0A3B,并且点阵显示X、蜂鸣器警报表示猜的不对:
当时间结束时仍没有猜对数字时,点阵显示囧表示到时间了:
如果在64秒内猜对了数字,则点阵显示笑脸表示猜对了:
在整个猜数字的过程中均可按BTN7按键重置游戏,再次按BTN6开始。

矩阵键盘顺序: 1 2 3 4
5 6 7 8
9 0 0 0
00 0 0;
管教使用:
资源利用情况:
共使用逻辑单元836个,占用率66%,使用逻辑管脚47个,占用率为41%。

六、故障及问题分析
在使用quartus Ⅱ时,发现有时候不能正常下载程序,下载之后发验板上的程序并没有发生改变,依然是上次下载的程序,重复几次之后也是这样,后来发现每次修改代码后,都需要重新打开programmer界面,再次下载即可。

在使用vhdl语言时发现有时候有赋值的语法错误,最后发现:= 表示对变量赋值,而 <= 表示对信号赋值。

在编写点阵倒计时的部分时,出现了点阵灯灭的顺序不对的情况,后来发现是led_col的信号写反了。

在下载程序后,发现矩阵键盘的按键数字和预想的不一样,后来改写了代码后面的数字,解决了这个问题。

当然在编写代码的过程中也出现过各种各样的error,有一次多写了一个end if花了很长时间才发现。

七、总结和结论
可以说,在这学期的数电综合实验中,复习巩固了上学期数电小实验时学到的知识和能力,尤其是在编写分频器和计数器(在做伪随机的时候考虑使用了计数器)时。

这次的综合实验第一次尝试了对状态机的编写,深刻感觉到状态机的
强大和不可或缺。

在刚刚开始接触状态机时,经常犯现在看起来很低级的错误,当然,我也在一次一次的错误中学会了很多。

在这学期的综合实验中,我深刻的认识到了vhdl语言和c语言的一些不同点,体会到了vhdl语言在对信号处理上的优势。

最后我想说,不管什么困难,在经过努力之后都能解决,第一次课的时候我甚至都不知道怎么玩这个猜数字游戏。

在这次实验中我对vhdl语言产生了浓厚的兴趣,在今后的日子里,我会继续学习vhdl语言,会继续学习quartus Ⅱ,提升我的个人价值。

相关文档
最新文档