北邮数电实验报告 简易迷宫游戏文档格式.docx
《北邮数电实验报告 简易迷宫游戏文档格式.docx》由会员分享,可在线阅读,更多相关《北邮数电实验报告 简易迷宫游戏文档格式.docx(33页珍藏版)》请在冰豆网上搜索。
3.增加了计时显示的精确度,让倒计时精确到0.01s
4.增加了开机画面,当按下START开始键后,点阵上开始显示“GO-6-5-4-3-2-1”的开始画面。
系统设计
(四)设计思路
此程序利用自顶向下的设计思想。
首先要考虑实现基本功能所需要哪些模块,倒计时的功能要用数码管来实现,地图的显示和迷宫游戏中动画的交互要用8×
8点阵来实现,方向的选择和开始游戏需要独立按键来显示,这些都是最顶层的模块。
然后,要实现这些模块,第一需要适当的时钟频率来驱动,这就要完成一个分频器,根据点阵、数码管以及独立按键各自的特征完成相应频率的分配。
实现倒计时功能的时候,需要一个计时器在每秒改变一次数码管的显示状态,于是还需要一个计时器模块。
而数码管动态扫描需要相应的LED灯亮灭,这就需要先定义好了显示相应数字的时候对应八段LED的高低电平状态。
点阵的显示控制原理和数码管类似,都是一个较高频率的动态扫描过程,只是代码量更大。
其次,也是该程序最关键的地方就是绿色小人移动的控制。
题干中说明小人撞墙后原地不动,不撞墙的时候进行移动。
这就需要我们判断是否撞墙。
经过和同学的商讨,我绝对将点阵坐标化,而小人所处的位置用(x,y)表示并实时的更新,然后将墙壁坐标封装好,当下一步的坐标在墙壁坐标的集合中则判定为撞墙,否则根据方向进行移动。
而终点坐标也都是提前用代码设定好的,这样通过坐标显示出点阵应该进行的下一画面。
到此为止,该实验的基本功能都已经规划得较为清晰。
对于提高要求,我通过一个拔码开关控制初始迷宫地图的选择,在程序中加入一个输入信号来选择相应地图;
在程序中添加两个计数变量,分别表示步数的个位和十位,两者添加到判断撞墙与否的逻辑语句中,在数码管显示模块中增加两个数码管的显示便可实现。
此外,为了丰富点阵界面,我还添加了开机画面,通过一个1s加1的变量扫描显示“GO-6-5-4-3-2-1”;
想到很多倒计时显示中个都精确到了0.01s甚至更精确,我又增加两个数码管来显示倒计时的小数点后两位。
(五)总体框图
1.系统结构框图
2.逻辑划分方框图
3.控制模块流程图
4.状态转移图
(六)分块设计
点阵模块:
点阵模块主要分为点阵扫描显示模块、小人移动逻辑判断模块。
扫描显示模块,主要是对迷宫地图、开机动画以及小人移动变化后的图案进行动态扫描,完成游戏交互。
开机画面通过一个一秒更新一次的变量,然后通过case语句来完成扫描;
地图图案的显示也是同样的方案,只不过要胜利或者失败的逻辑判断。
小人移动的逻辑判断模块,主要通过坐标定位。
首先将地图中墙壁的坐标位置封装好,然后将小人时刻的位置定义为(x,y),再根据按键对x,y进行变化,最后通过判断新的坐标是否在封装好的墙壁集合中来进行移动与否的判决。
如果移动则更新(x,y);
如果不移动,则保持(x,y)不变。
数码管显示模块:
数码管显示模块主要分为30s倒计时模块和小人移动步数计数模块
倒计时模块中将一个1KHZ的时钟信号进行四次的十分频,可以得到一个精确到0.01s的倒计时。
每个变量都是十进制的数,再将它们传送到数码管动态扫描模块,便可以顺利地显示30s倒计时。
小人移动步数计数模块,定义两个计数变量count、count10分别表示计数的个位和十位,将其放在小人移动逻辑判断模块中,当逻辑判定为移动,则将count加一,当加到10的时候进位。
再将两者传送到数码管动态扫描模块,就可以实时显示小人移动的步数。
按键防抖模块:
该程序再一开始开发的时候并没有加防抖模块,而是尽可能地找到一个最佳的按键扫描控制频率,使得既可以得到灵敏可靠的按键控制,又可以再长按一次后进行多步移动,这样可以方便用户的操作,一开始测试得到的按键扫描频率为5Hz。
但是好像要求按键必须加防抖,并且为了提高按键输入可靠性,由于机械触点的弹性振动,因而在按键闭合和断开的瞬间均会出现一连串的抖动,按键的抖动会造成按一次键产生的开关状态被CPU误读几次。
为了使CPU能正确地读取按键状态,必须在按键闭合或断开时,消除产生的前沿或后沿抖动。
一、仿真波形及波形分析
(七)复位、开始()
注:
以下关于点阵显示的仿真都是最开始测试用的模块,并不包含点阵动态显示的所有状态,只是挑选其中一些典型状态展示,而且点阵扫描红色和绿色是分开的。
.复位:
当按下复位键的时候,停止对点阵的扫描,点阵上无任务图形显示。
开始:
当按下开始键的时候,点阵开始进行行扫描,开始倒计时显示“GO-6-5-4-3-2-1”,上图为点阵用红色LED显示“GO”。
(二)点阵显示胜利、失败
胜利:
当玩家在30s之内到达了迷宫的终点,游戏结束并点阵显示“V”的标志。
上图为当信号victory置高电平的时候,点阵开始行扫描,并将红色、绿色LED均点亮显示“V”,上图可明显地看出。
失败:
当玩家在30s之内没有到达迷宫的终点,游戏结束并且点阵显示“X”的标志。
上图为信号fail置高电平的时候,点阵开始行扫描,并将红色、绿色LED均点亮显示“X”,由上图可以明显地看出。
(三)数码管倒计时
数码管倒计时:
实际上应该是四位数码管从30.00s倒计时,为了方便展示将倒计时的计数变量改成二进制,上图中输出信号ledshow代表数码管段选的信号,而ledstate代表数码管位选的信号,变量ledsao表示分五次对四位数字加上一个小数点进行扫描。
上图红色圈中表示显示小数点,“00000001”表示小数点,而ledstate在“111110—111101—111011—110111—111011”五个状态之间循环表示对四位数字和一个小数点的显示。
而ledshow显示相应的数字。
(四)按键防抖
按键防抖:
keyin输入一个持续时间约为0.1s的按键信号并用高频时钟模拟抖动,keyout输出一个时钟周期的高电平。
二、源程序(注释)
LIBRARYIEEE;
USEIEEE.STD_LOGIC_1164.ALL;
useieee.std_logic_unsigned.all;
ENTITYmazeIS
PORT(
clk:
INSTD_LOGIC;
--总时钟
start,reset:
--开始和复位键
l,r,f,b,mapflag:
--BTN--b/r/f/b分别代表小人向左、右、前、后移动;
mapflag代表两种地图的选择
dotshow:
OUTSTD_LOGIC_VECTOR(23DOWNTO0);
--点阵显示
ledstate:
OUTSTD_LOGIC_VECTOR(5DOWNTO0);
--数码管状态
ledshow:
OUTSTD_LOGIC_VECTOR(7DOWNTO0));
--数码管显示
ENDmaze;
ARCHITECTUREmainofmazeIS
signalcnt:
integerrange0to25000;
--分频器的计数
signalcnt1:
integerrange0to25000000;
signalcnt2:
integerrange0to5000000;
signalclk_tmp:
std_logic;
--分频器的临时信号
signalclk_tmp1:
signaltclk:
signalclk_tmp2:
signalkey_tmp0,key_tmp1,key_tmp2,key_tmp3:
std_logic;
signalrow:
std_logic_vector(7downto0);
--点阵行状态
signalcul:
std_logic_vector(15downto0);
--点阵列状态
signalaclk:
--点阵倒计时开机画面的时钟信号
signalbinclk:
--按键时钟信号
sharedvariabletend:
integerrange0to1;
signaltostart:
--开始标志信号
signalpreset:
--逻辑判断模块重置
signaldotreset:
--点阵模块重置
signalledreset:
--数码管重置
signaltreset:
--计时器重置
signalpwork:
--逻辑判断模块工作
signaldotwork:
--点阵工作
signalledwork:
--数码管工作
signaltwork:
--计时器工作
signalworked:
signalvic:
--成功
signalfal:
std_logic;
--失败
typenstisarray(0to9)ofstd_logic_vector(7downto0);
signalledshowed:
nst;
sharedvariablerowsao:
integerrange0to9;
--点阵的行扫描
sharedvariableledsao:
integerrange0to6;
--数码管的扫描
sharedvariabledaojishi:
integerrange0to7;
--开机动画倒计时扫描
sharedvariabledotsao:
integerrange0to3;
sharedvariablemapsao:
sharedvariablex:
integerrange-7to0;
--小人的坐标
sharedvariabley:
integerrange-6to1;
sharedvariablecount:
--count和count10分别代表步数的个位和十位
sharedvariablecount10:
sharedvariabletimems:
sharedvariabletime001s:
--以下分别代表30倒计时的位数
sharedvariabletime01s:
sharedvariabletime1s:
sharedvariabletime10s:
begin--数码管显示高低电平初始化
ledshowed
(1)<
="
01100000"
;
ledshowed
(2)<
11011010"
ledshowed(3)<
11110010"
ledshowed(4)<
01100110"
ledshowed(5)<
10110110"
ledshowed(6)<
10111110"
ledshowed(7)<
11100000"
ledshowed(8)<
11111110"
ledshowed(9)<
11110110"
ledshowed(0)<
11111100"
tdiv:
process(clk,clk_tmp)--计时器分频-----1K
begin
if(clk'
eventandclk='
1'
)then
ifcnt=24999then
cnt<
=0;
clk_tmp<
=notclk_tmp;
else
=cnt+1;
endif;
endif;
tclk<
=clk_tmp;
endprocess;
adiv:
process(clk,clk_tmp1)--点阵分频-------1HZ
ifcnt1=24999999then
cnt1<
clk_tmp1<
=notclk_tmp1;
=cnt1+1;
aclk<
=clk_tmp1;
usediv:
process(clk,clk_tmp2)--按键控制判断分频-----5HZ
ifcnt2=4999999then
cnt2<
clk_tmp2<
=notclk_tmp2;
=cnt2+1;
binclk<
=clk_tmp2;
process(clk_fd)--防抖模块
begin
if(clk_fd'
eventandclk_fd='
)then
key_tmp0<
=keyin;
key_tmp1<
=key_tmp0;
--利用信号赋值延时将前后信号相与完成防抖
key_tmp2<
=key_tmp0andkey_tmp1;
process(clk_fd)
key_tmp3<
=key_tmp2;
keyout<
=not(key_tmp2)andkey_tmp3;
end;
--时钟上升沿输出一个时钟周期宽度的脉冲
control:
process(clk,reset,start)--控制器
begin
if(clk'
if(start='
tostart<
='
endif;
if(reset='
ortend=1)then
preset<
dotreset<
ledreset<
treset<
tostart<
0'
dotwork<
else
preset<
dotreset<
ledreset<
treset<
if(tostart='
)then
dotwork<
--启动点阵模块
endif;
endif;
endprocess;
a:
process(aclk,dotreset)--点阵工作模块
if(dotreset='
dotsao:
else
if(aclk'
eventandaclk='
if(vic='
orfal='
if(dotsao<
=2)then
dotsao:
=dotsao+1;
process(tclk,dotreset)
mapsao:
if(tclk'
eventandtclk='
if(mapsao=9)then
mapsao:
else
=mapsao+1;
process(aclk,dotwork,worked,dotreset)
daojishi:
if(aclk'
anddotwork='
andworked='
if(daojishi=7)then
daojishi:
=daojishi+1;
if(dotreset='
rowsao:
else
if(tclk'
if(rowsao=9)then
rowsao:
=rowsao+1;
process(clk,dotreset,dotwork,mapflag)--开机动画
dotshow<
000000000000000000000000"
tend:
worked<
twork<
pwork<
if(dotwork='
if(worked='
casedaojishiis
when0=>
caserowsaois
when1=>
dotshow<
111111111111111100000000"
when0=>
101111111111011100000000"
when2=>
110111111000010100000000"
when3=>
111011111000010100000000"
when4=>
111101111011010100000000"
when5=>
111110111001010100000000"
--go
when6=>
111111011111011100000000"
when7=>
when8=>
when9=>
endcase;
when1=>
011111110011110000000000"
101111110010000000000000"
110111110010000000000000"
111011110010000000000000"
111101110011110000000000"
--6
111110110010010000000000"
111111010010010000000000"
111111100011110000000000"
when2=>