北邮数电综合实验_简易猜数字游戏机的设计与实现

巡山小妖精
721次浏览
2021年01月01日 04:19
最佳经验
本文由作者推荐

七仔电影-一生中最爱谭咏麟

2021年1月1日发(作者:班超)



数电综合实验


题目: 简易猜数字游戏机的设计与实现

姓名孙尚威
学院电子工程学院
专业电子信息科学与技术
班级 2013211202
学号 2013210849
班内序号 04
指导教师孙丹丹

2015年11月

摘要:
通过分析题目要求以及实际生活中猜数字游戏机 的操作方式,在以


Atmel EMP1270T144C5 芯片为核心,拥有按键、 点阵、数码管和蜂鸣器等外设
的实验板上设计并实现了简易猜数字游戏机。采用模块化设计思路在Qua rtus II
软件中利用VHDL语言实现模块化电路设计,利用自顶而下的设计思路实现系
统整体搭建,并利用Quartus II 软件功能进行仿真和分析。最终下载到实验板上
可流畅运行 ,无明显逻辑错误,在完成实验要求的基础上,实现了随机数/手动
设置数字模式切换功能,led灯提 示游戏进行状态等拓展功能。

一、游戏规则简述
通常由两个人玩,一方出数字,另 一方猜。出数字的人要想好一个没有重复数字的
4位数,不能让猜的人知道。通过 4*4 键盘进行4位数字输入, 在按下确定键后由
猜数字人在规定时间内猜对之前输入的4位数字,过程中系 统会给出提示XAYB
(A前面的数字表示位置正确的数的个数, B前的数字表示数字正确而位置不
对的数的个数。例:正确答案为 2134,而猜的人猜 5314, 则是 1A2B, 其中有一
个4的位置对了,记为1A, 而1和3这三个数字对了,而位置没对,因 此记为2B,合
起来就是1A2B)。接着猜的人再根据出题者的XAYB继续猜,直到猜中即 4A0B
为止。


二、实验要求
基本要求:
(1)设置游戏机开关以及复位键。 



(2)数字设置:通过 4*4 键盘进行 4 位数字输入,在数码管(DISP0~DISP3)上显
示当前所输入的数字。通过设置 确定键(BTN1 键)进行锁定,此时数码管上的数值
消失, 同时用点阵开始倒计时,即:初始状态 点阵全亮,然后从右上角开始,由右到
左、由下到上逐点逐排依次熄灭,间隔时间为1s,共计64s。 

(3)猜数字:可以通过 4*4 键盘进行 4 位数字输入进行猜数字,且每输入一位数
字在数码管(DISP0~DISP3)上显示当前所输入的数字,按确定键(BTN2 键)进行确
认, 此时要根据输入的这组数字给出XAYB。
(4)若数字正确则显示猜数字 成功,点阵显示“☺”笑脸;若输入数字错误系统仍
然处于猜数字状态,点阵显示“X”,并用蜂鸣器报 警。 

(5)若到点阵全灭时(64s 结束)仍未猜出正确数字,游戏失败,点阵显示“囧”。
提高要求:
(1)若数字正确则显示猜数字成功,用蜂鸣器播放一段乐曲。
(2)一键产生4位随机数字。







三、总体设计思路
功能流程图:





四、 功能模块的设计和实现
系统共通过8个模块实现,分别是:游戏控制(状态 机)、分频器、键盘模块、
点阵显示模块、数码管显示、倒计时模块、随机数生成器、音乐播放这8个模 块


实现的,具体设计如下。

(1)游戏控制模块(ssw)
1. 模块设计思路
使用状态机进行编写,共计7个状态分别是:空闲(idle)、设定 数字(set_number)、
猜数字(guess_number)、比较判断(compare) 、正确(smile)、错误(false)、
倒计时结束(jiong)。各状态间通过外接按键以及 其他模块传递过来的控制信号
进行转移。在不同的状态下输出不同的状态标志信号对后续模块进行控制。 状态
转移图如图

2. 外部接口设计
设计输入端口:
时钟信号clk_scan:STD_LOGIC,频率2KHz;
复位信号reset: STD_LOGIC,使状态机复位到空闲(idle)状态;
开始信号start : STD_LOGIC,使状态由空闲(idle)状态转移到设定数字
(set_number)状态,开始游戏; 
设置数字保存set_save: STD_LOGIC,使状态由设定数字(set_number)转移到
猜数字(guess_number)状态,保存设置数字;
猜数字保存guess_save: STD_LOGIC,使状态由猜数字(guess_number)转移

比较判断(compare)状态,进行状态转移判断;
猜数字正确信号win:STD_LOGIC,使状态由比较判断(compare)状态转移到
正确(smile)状态,输出笑脸信号给点阵和音乐信号给音乐播放
模块;
猜数字错误信号wrong:STD_LOGIC,使状态由比较判断(compare)状态转移
到错误(false)状态,输出X信号给点阵和报警信号给音乐播放
模块;
显示等待信号done:STD_LOGIC,使状态由错误(false)状态转移到猜数字


(guess_number)状态;
倒计时结束信号time_over:STD_LOGIC,使状态由猜数字(guess_number)状
态转移到倒计时结束(jiong)状态,输出囧信号给点阵;

设计输出端口:
当前状态机信号state_flag:STD_LOGIC_VECTOR(3 downto 0),输出不同状态

状态机标志,方便后续模块对当前状态做正确判断和调用,同时
作为led输出,提示当前状态;
蜂鸣器状态信号bee:STD_LOGIC_VECTOR(1 DOWNTO 0),输出不同状态下
蜂鸣器产生不同声音的信号;
点阵显示信号display : INTEGER RANGE 0 TO 4,输出不同判断结果状态下点阵
显示标志,控制点阵模块显示不同图形。

3、关键代码
p1:PROC ESS(start,set_save,guess_save,reset,time_over,done ,win,wrong,state)
--change next_state4
BEGIN
next_state<=state;
IF reset='1' THEN next_state<=idle;
ELSE
CASE state IS
WHEN idle =>
IF start='1' THEN next_state<=setnum;
ELSE next_state<=idle;
END IF;
WHEN setnum =>
IF set_save='1' THEN
next_state<=guessnum;
ELSE next_state<=setnum;
END IF;
WHEN guessnum =>


IF guess_save='1' THEN
next_state<=compare;
ELSIF time_over='1' THEN
next_state<=jiong;
ELSE next_state<=guessnum;
END IF;
WHEN compare =>
--IF done='1' THEN
IF win='1' THEN
next_state<=smile;
ELSIF wrong='1' THEN
next_state<=false;
--END IF;
ELSE next_state<=compare;
END IF;
WHEN smile =>
IF start='1' THEN
next_state<=idle;
ELSE next_state<=smile;
END IF;
WHEN jiong =>
IF start='1' THEN
next_state<=idle;
ELSE next_state<=jiong;
END IF;
WHEN false =>
IF time_over='0' and done='1'THEN
next_state<=guessnum;
ELSE next_state<=false;
END IF;
WHEN OTHERS =>next_state<=idle;
END CASE;
END IF;
END PROCESS p1;

p2:PROCESS(clk_scan)
BEGIN
IF clk_scan'event AND clk_scan='1' THEN
CASE state IS
WHEN idle =>
state_flag<=
display<=4;
bee<=
WHEN setnum =>


state_flag<=
display<=4;
bee<=
WHEN guessnum =>
state_flag<=
display<=0;
bee<=
WHEN compare =>
state_flag<=
display<=4;
bee<=
WHEN smile =>
state_flag<=
display<=2;
bee<=
WHEN jiong =>
state_flag<=
display<=1;
bee<=
WHEN false =>
state_flag<=
display<=3;
bee<=
WHEN OTHERS =>
state_flag<=
display<=4;
bee<=
END CASE;
state<=next_state;
END IF;
END PROCESS p2;
end arch;



4、仿真图及说明

(2)分频模块(div)
1. 模块设计思路
对实验板上25MHz时钟进行分 频,分别输出2KHz,10Hz,1Hz。为其他模块提
供合适的时钟。
2. 外部接口设计
设计输入端口:
时钟输入clk : STD_LOGIC,实验板上待分频的高频时钟信号;
设计输出端口:
时钟输出clk_scan: STD_LOGIC,输出2KHz信号,为显示模块提供扫描时钟;
时钟输出clk_10hz: STD_LOGIC,输出10Hz信号,为音乐模块提供频率时钟;
时钟输出clk_count:STD_LOGIC,输出1Hz信号,为倒计时模块提供时钟;

3、关键代码
P1:PROCESS(clk)
BEGIN
IF clk'event AND clk='1' THEN


IF tmp1=24999 THEN
tmp1<=0;clktmp1<=not clktmp1;
ELSE
tmp1<=tmp1+1;
END IF;
END IF;
END PROCESS P1;

P2:PROCESS(clk)
BEGIN
IF clk'event AND clk='1' THEN
IF tmp2=12499999 THEN
tmp2<=0;clktmp2<=not clktmp2;
ELSE
tmp2<=tmp2+1;
END IF;
END IF;
END PROCESS P2;


P3:PROCESS(clk)
BEGIN
IF clk'event AND clk='1' THEN
IF tmp3=1249999 THEN
tmp3<=0;clktmp3<=not clktmp3;
ELSE
tmp3<=tmp3+1;
END IF;
END IF;
END PROCESS P3;
clk_scan<=clktmp1;
clk_count<=clktmp2;
clk_10hz<=clktmp3;

END a;

(3)键盘模块(key)
1. 模块设计思路
判断键盘中有无按键按下是通过行先送入扫描信号,然后从列线读取状态后得到
的。其方法是依次给行线送低电平,检查列线的输入。如果列线信号全为高电平,
则代表低电平信号所在 的行中无键按下;如果列线有输入为低电平,则低电平信号
所在的行和出现低电平的列的交叉点有键按下 。
2. 外部接口设计
设计输入端口:


时钟输入clk_scan: STD_LOGIC,输入2KHz信号,为键盘模块提供扫描时钟;
当前状态机信号state_flag:STD_LOGIC_VECTOR(3 downto 0),输入当前状态

状态机标志,在不同状态下键入不同的值;
扫描信号key_row:STD_LOGIC_VECTOR(3 downto 0),依次给行线送低电平;
设计输出端口:
键值信号key1: STD_LOGIC_VECTOR(6 DOWNTO 0),输出简直信号给数码

显示模块;
检查列线scan_out::STD_LOGIC_VECTOR(3 downto 0),如果列线信号全为高

平,则代表低电平信号所在的行中无键按下;如果列线有输入为低电
平,则低电平信号所在的行和出现低电平的列的交叉点有键按下。

3、关键代码

p1:PROCESS(clk_scan) --scan
BEGIN
IF clk_scan'event AND clk_scan='1' THEN
CASE scan IS
WHEN
WHEN
WHEN
WHEN
WHEN OTHERS => scan<=
END CASE;
scan_out<=scan;
END IF;
END PROCESS p1;

p2:PROCESS(clk_scan) --key in

BEGIN

IF clk_scan'event AND clk_scan='1' THEN
-- if state_flag=
-- key1<=
-- end if;









































CASE key_row IS
WHEN
CASE scan IS
WHEN
WHEN
WHEN
WHEN
WHEN OTHERS => NULL;
END CASE;
WHEN
CASE scan IS
WHEN
WHEN
WHEN
WHEN
WHEN OTHERS => NULL;
END CASE;
WHEN
CASE scan IS
WHEN
WHEN
WHEN
WHEN
WHEN OTHERS => NULL;
END CASE;
WHEN
CASE scan IS
WHEN
WHEN
WHEN
WHEN
WHEN OTHERS => NULL;
END CASE;
WHEN OTHERS => NULL;
END CASE;
END IF;
END PROCESS p2;

(4)键盘模块(key)
1. 模块设计思路
判断键盘中有无按键按下是通过行 先送入扫描信号,然后从列线读取状态后得到
的。其方法是依次给行线送低电平,检查列线的输入。如果 列线信号全为高电平,
则代表低电平信号所在的行中无键按下;如果列线有输入为低电平,则低电平信号


所在的行和出现低电平的列的交叉点有键按下。
2. 外部接口设计
设计输入端口:
时钟输入clk_scan: STD_LOGIC,输入2KHz信号,为点阵模块提供扫描时钟;
当前状态机信号state_flag:STD_LOGIC_VECTOR(3 downto 0),输入当前状态

状态机标志,在不同状态下键入不同的值;
倒计时清零信号count_clear:STD_LOGIC,倒计时模块清零;
设计输出端口:
倒计时结束信号time_over: STD_LOGIC,倒计时结束后将结束信号传递给状

机模块切换状态;
倒计时 count_down:inout :INTEGER RANGE 0 TO 64,64s倒计时, 同时将当
前倒计时状态传递给点阵显示模块。

3、关键代码
PROCESS(clk_count)

BEGIN
IF count_clear='1' THEN
count_down<=0; time_over<='0';
--END IF;
ELSIF state_flag=
IF clk_count'event AND clk_count='1' THEN
IF count_down=64 THEN
time_over<='1'; count_down<=0;
ELSE count_down<=count_down+1;
END IF;
END IF;
END IF;
END PROCESS



(5)点阵显示模块(dot_led)
1. 模块设计思路

< br>LED点阵显示由8*8共64个发光二极管组成。控制时,分别控制阳极8个行控
制口和阴极8 个列控制口。显示时,向阳极送字模,向阴极送选通信号。送出一
行的字模,再送选通信号,再送第二行 的字模和选通信号,循环扫描8次,就可以在
一块点阵上显示一个字符。
2. 外部接口设计
设计输入端口:
时钟输入clk_count:STD_LOGIC,输入1Hz信号,为倒计时模块提供扫描时钟;
点阵显示信号display : INTEGER RANGE 0 TO 4,输入不同判断结果状态下点阵
显示标志,控制点阵模块显示不同图形。
设计输出端口:
点阵行输出dot_led_row: STD_LOGIC_VECTOR(7 downto 0)
点阵列输出dot_led_col: STD_LOGIC_VECTOR(7 downto 0)
3、关键代码
PROCESS(clk_scan) --display led
BEGIN
IF clk_scan'event AND clk_scan='1' THEN
IF display=1 THEN
CASE led_row IS
WHEN
=>led_row<=
WHEN
=>led_row<=
WHEN
=>led_row<=
WHEN
=>led_row<=
WHEN
=>led_row<=
WHEN
=>led_row<=
WHEN
=>led_row<=
WHEN
=>led_row<=
WHEN
=>led_row<=
END CASE;










OTHERS



(6)点阵显示模块(dot_led)
1. 模块设计思路 < br>将已经设置的四位数字和猜的四位数字进行循环比较,得出XAYB中X、Y值,
并在数码管上进 行显示。根据状态标志符的不同显示以输入的四位数字。
2. 外部接口设计
设计输入端口:
时钟输入clk_scan:STD_LOGIC,输入2KHz信号,为数码管模块提供扫描时钟;
键值信号key1:STD_LOGIC_VECTOR(6 DOWNTO 0),输入已键入四位数字的
数码管译码信号;
键值信号key2:STD_LOGIC_VECTOR(6 DOWNTO 0),输入随机生成的四位数
字的数码管译码信号;
当前状态机信号state_flag:STD_LOGIC_VECTOR(3 downto 0),输入当前状态

状态机标志,在不同状态下显示不同的输入值;
模式选择信号 mode:STD_LOGIC,通过拨码开关选择设置的四位数字是认为输
入的还是随机生成模式
设计输出端口:
猜数字正确信号win:STD_LOGIC,使状态机模块由比较判断(compare)状态
转移到正确(smile)状态,输出笑脸信号给点阵和音乐信号给音

播放模块;
猜数字错误信号wrong:STD_LOGIC,使状态机模块由比较判断(compare)状
态转移到错误(false)状态,输出X信号给点阵和报警信号给音乐
播放模块;
显示等待信号done:STD_LOGIC,使状态由错误(false)状态转移到猜数字
(guess_number)状态;
倒计时清零信号count_clear:STD_LOGIC,倒计时模块清零;
数码管段选信号seg_num::STD_LOGIC_VECTOR(6 downto 0);
数码管位选信号cat_num:STD_LOGIC_VECTOR(5 downto 0)。
3、关键代码

WHEN
flagA:=0; flagB:=0;


for i in 0 to 3 loop
if (set_number(i)=guess_number(i)) then flagA:=flagA+1;
end if;
end loop;

for i in 0 to 3 loop
for j in 0 to 3 loop
if (set_number(i)=guess_number(j)) thenflagB:=flagB+1;
end if;
end loop;
end loop;
flagB:=flagB-flagA;
CASE cat IS
WHEN
WHEN
WHEN
WHEN
WHEN
WHEN
WHEN OTHERS => cat<=
END CASE;
IF flagA=4 THEN
win<='1'; wrong<='0';
ELSE win<='0'; wrong<='1';
END IF;
num_a<=flagA;
num_b<=flagB;

p2:PROCESS(num_a,num_b) --trans num to seg
BEGIN
CASE num_a IS
WHEN 0 =>dis_a_sig<=
WHEN 1 =>dis_a_sig<=
WHEN 2 =>dis_a_sig<=
WHEN 3 =>dis_a_sig<=
WHEN 4 =>dis_a_sig<=
WHEN OTHERS =>dis_a_sig<=
END CASE;
CASE num_b IS
WHEN 0 =>dis_b_sig<=
WHEN 1 =>dis_b_sig<=
WHEN 2 =>dis_b_sig<=
WHEN 3 =>dis_b_sig<=
WHEN 4 =>dis_b_sig<=





WHEN OTHERS =>dis_b_sig<=
END CASE;
END PROCESS p2;

(7)点阵显示模块(music)
1. 模块设计思路
通过蜂 鸣器输出不同频率的声音信号,产生不同的音调,根据预设置的生日快乐
乐谱输出胜利时的音乐。
2. 外部接口设计
设计输入端口:
时钟输入clk_10hz:STD_LOGIC,输入10Hz信号,为蜂鸣器提供报警时钟频率;
时钟输入clk_25Mhz: STD_LOGIC,输入25MHz信号,提供预分频信号;
声音选择信号 bee:STD_LOGIC_VECTOR(1 DOWNTO 0),根据信号选择输出
报警信号,还是胜利音乐信号;
设计输出端口:
蜂鸣器信号bee_out:STD_LOGIC,向蜂鸣器输出不同频率的方波信号,产生简
单的乐曲。
3、关键代码
p3:PROCESS(counter)--diside music
BEGIN
CASE counter IS
WHEN 1 to 3|7 to 9|19 to 21|25 to 27|37 to 39=> index <=4520;--1
WHEN 4 to 6|22 to 24|52 to 54=> index <=7126;--2
WHEN 13 to 18|49 to 51=> index <=9448;--3
WHEN 10 to 12|31 to 36|46 to 48|61 to 63|67 to 72
=>index<=10512;--4
WHEN 28 to 30|64 to 66=> index <=12465;--5
WHEN 43 to 45|58 to 60=> index <=14204;--6
WHEN 55 to 57=> index <=15754;--7
WHEN 40 to 42=> index <=16453;--g1
WHEN 73 to 75=> index <=22083; --0
WHEN 0 => index <=22082; --g7
WHEN OTHERS => index <=22083;
END CASE;
END PROCESS p3;


(8)随机数生成模块(random_num)
1. 模块设计思路

通过不断扫描预设置伪随机序列,在按下设置随机数序列按键时,将当前序列值
保存在key2中。 完成随机数的设置。
2. 外部接口设计
设计输入端口:
时钟输入clk_scan:STD_LOGIC,输入2KHz信号,为随机序列提供扫描频率;
设置随机数信号set_random:STD_LOGIC,连接到外部按键,按下时保存当前
时刻序列值为设置的数字;
设计输出端口:
键值信号key2: STD_LOGIC_VECTOR(6 DOWNTO 0),输出已随机生成的四

数字的数码管译码信号;
3、关键代码
PROCESS(clk_scan,set_random)
VARIABLE random:INTEGER RANGE 0 TO 9:=0;
BEGIN
IF clk_scan'event AND clk_scan='1' THEN
IF random=9 THEN
random:=0;
ELSE random:=random+1;
END IF;
IF set_random='1' THEN
CASE random IS
WHEN 4 => key2<=
WHEN 7 => key2<=
WHEN 2 => key2<=
WHEN 3 => key2<=
WHEN 5 => key2<=
WHEN 6 => key2<=
WHEN 9 => key2<=
WHEN 0 => key2<=
WHEN 8 => key2<=
WHEN 1 => key2<=
WHEN OTHERS => NULL;
end case;
end if;
end if;
END PROCESS




五、系统的整体搭建
1、使用Quartus II的COMPONENT以及MAP PORT将以上8个分立模块连接在
一起成为一个统一的系统,编译通过后生成RTL图:







2. 程序编译后,得到关于芯片资源占用的情况表,如下图:



3、实际效果图



4、功能说明
1)按BTN3为reset,可在任意时刻重置游戏,回到初始状态。
2)按BTN2为start,开始游戏,只有在按下后才可进行键盘数字的
输入
3)拨码开关SW7为模式选择。置1时为随机生成数模式,当前模
式下按BTN7会随机生成4位数。置0时为手动生成数模式,当
前模式下按矩阵键盘设置4位数。数码管显示4位数。
4)按BTN0为确认设置数,并进入猜数字状态,此时点阵开始显示
倒计时图案。
5)按矩阵键盘输入猜的4位数,按BTN1确认猜数字。若猜对点阵
将显示笑脸同时蜂鸣器播放生日快乐歌;若猜错点阵显示X同
时蜂鸣器发出报警音,1s后系统回到猜数字状态。
6)若在猜数字的过程中,64S倒计时结束,点阵显示囧,游戏结束
7)在游戏过程中,右下角的led灯显示游戏当前进行状态。


六、 故障和问题分析

1. 状态转移异常,直接跳到囧状态
分析:通过检查代码和对问 题状况的分析,发现问题出在控制倒计时模块没有工
作,所以导致time_over信号始终为1,所 以一直会跳到囧状态。
解决:发现在初始状态下没有将count_clear信号置1,使两个模块 完成正常通讯,
使倒计时模块正常进入工作状态。点阵显示也回复正常

2. 蜂鸣器不报警
分析:由于开始时蜂鸣器使用的时钟频率不合理,而其中使蜂鸣器置高的时间过
短,使蜂鸣器发出的声音不能被耳朵听到。
解决:单独为蜂鸣器设置了一个时钟频率控制蜂鸣器的报 警,并通过信号区分报
警和胜利音乐,使蜂鸣器发出正确声音。
3. 猜数字完成后会残留一位数字在下一次猜数字显示
分析:当完成4位数字的输入后,按下确认键后, 第四位数字会残留在下一次的
4位数的第一位,由于我在数码管显示时设置了显示标志符,导致下一次只 能从
第二位开始输入。分析后应该是key1的寄存器内保存着上一次的键值,导致在
下一次猜 数字时会把key1值传给数码管的第一位。
解决:在按下guess_save按钮的同时,强制 清楚key1寄存器中的内存,避免了
上述的bug。
七、总结和结论
这次数电实 验,我亲身经历了设计开发一个完整的数字电路系统的过程,从拿到
题目时的一片空白到最后验收时一个 完整的可操作的简易数字系统,这个过程不
仅锻炼了我们VHDL语言的编写,更是对我们工程实践应用 的极大锻炼。
要想完成一个实际系统的设计, 首先要明确系统功能,接着从系统的功能出发
将其拆分为几个模块。之后按照模块各自的需求,设计状态转移图等,逐步考虑
模块的实现,不断细化 功能直到把模块实现。之后通过各模块仿真,分析模块功
能是否正常,并且要关注每个模块输入输出的特 点,注意保持清晰的逻辑,避免
出现状态转移时的逻辑错误。
通过数电综合实验可以 将书本上的理论知识应用到实际当中,独立完成一个
简易数字系统也很有成就感,我从中受益很多。

dnf弹药专家加点-什么让生活更美好作文400字


关于中秋节的名言-停课不停学


dnf黑暗君主-学习交流会


健康快乐-描写人的英语作文


好感-温暖2008


大学数学课程-写游记的作文


lol周年庆典皮肤-简朴的反义词


神秘代码电影-白云湖公园