Transcript 总结报告
基于spartan3E实
验板的打地鼠游戏
华中科技大学
电信0904班
胡声曼
打地鼠
设计任务与要求
设计思路
功能实现
作品展示
主要负责模块:
逻辑计分模块
Lcd显示模块
VGA模块
3
一、设计任务与要求
Led灯亮灭显示8只地鼠的出现,游戏中每按对一次加
一分;否则命数扣一条。
设定初始命数为9,得分每达到10分便加1条命,失误
一次扣一条命,命数为0时游戏结束。
游戏分四个难度级别,每个级别灯闪亮的速度不同,级
别越高,速度越快,灯亮的时间越短。得分每达10分,
难度自动升一级。
设有暂停/继续和开始/停止功能,能记录和更新历史最
高分数。控制LCD进行相应的显示。
每个难度级别对应产生不同的音乐,与灯闪的频率节奏
相当。
扩展功能:VGA显示开机画面,8只地鼠的出现和等级,
失败和胜利画面。
4
二、设计思路
用8个led灯代表地鼠洞,
灯亮代表地鼠出没,由
程序随机选择一个灯亮,
8个按键对应8个锤子,
在灯亮期间按下亮的灯
对应的开关(即打中地
鼠),得一分,若按错,
则减一条命。
LCD显示命数,分数,
最高得分。
按键
button
等级时钟
分频
随机数产生
逻辑计分
随机数
分数、命数
LCD
最高分
等级
500hz
VGA
音乐
4hz
6
一个拨码开关
Start作为游戏开
始结束的总开关,
另一个拨码开关
pause为暂停键,
控制游戏的暂停
和继续。剩下两
个拨码开关作为
4个难度选择。
7
三、功能实现
逻辑计
分
音频
打地鼠
LCD输
出
VGA
逻辑计分模块
逻辑计分
分频产生
随机数
比较计分
比较计分
基本功能:
将按键输入的8位数据
(对应锤子)与8位随机
数比较(地鼠),若相
等(即打中),则分数
加一,若不等(即不中)
则命数减一。
初始化
if start=‘0’ then
……
等级为a,初始分数0,命数9
暂停
elsif pause='0' then
scoret1<=scoret1;
……
lifenum1<=lifenum1;
……
if rising_edge(clk) then
button1<=button
if button2/=button1 then
产生随机数的时候,将按键的值寄
存下来,因为还来不及按键,
button1为”00000000”
有键按下,进入计分模块
if (button2=random8)
then
…
分数加一
…
Else
…
命数减一
…
13
If score=999 then
Success<=‘1’;
如果分数达到最大
值,则分数不继续
增加,输出胜利信
号。
If life=0 then
Over<=‘1’;
如果命数减为0则
不再继续减命,输
出失败信号。
14
if
scoret1="1001" then
scoret1<="0000";
scoret10<=scoret10+1;
life+1
if a='1' then
b<='1';
.
.
.
每得到10分,
命数增加一条
等级提升一个,
难度增加
15
16
去抖动
if
button/=“00000000”
then
count<=count+1;
if flag='0' then
flag<='1';
…计分…
if(count>2500000) then
flag<='0';
count<=0;
由于按键会产生抖动,为
了不影响正常的计分,需
要一个去抖动的设计。
从第一次按下键开
始计数,50ms内不
接收按键信号。用
到了标记信号flag
17
LCD显示模块
1、命数
初始命数为9条,每按错
一次减一条命,每按对
10次加一条命。命数为0
时游戏结束。
2、分数
初始分数为0,每按对一
次加一分,加到999分游
戏胜利。
3、最大分数
显示为最终的得分。
Lcd显示原理
LCD显示数据RAM(DDRAM)存储字符编码。
如下图所示是显示器32位字符位置的默认地址。
字符的最上行存储在地址0X00与0X0F之间。第
二行的字符存储在地址0X40与0X4F之间。
字符产生器:
符编码存储在
DDRAM中,每个字
符的位置与
CGROM的位置按
顺序对应。读取相
对应的数据的时候,
先读取其地址为的
高四位,再读取低
四位。
when 'E'=> result:=x"45";
when 'I'=>
result:=x"49";
when 'L'=>
result:=x"4C";
when 'N'=>
result:=x"4E";
when 'O'=>
result:=x"4F";
when 'S'=>
result:=x"53";
when 'U'=>
result:=x"55";
when 'W'=>
result:=x"57";
when 'Y'=>
result:=x"59";
when 'c'=> result:=x"63";
when 'e'=>
result:=x"65";
when 'f'=>
result:=x"66";
when 'g'=>
result:=x"67";
when 'h'=>
result:=x"68";
when 'i'=>
result:=x"69";
when 'l'=>
result:=x"6C";
when 'o'=>
result:=x"6F";
when 'r'=>
result:=x"72";
when 's'=>
result:=x"73";
when '!'=>
result:=x"21";
when "0000"=> fig:="00110000";
when "0001"=> fig:="00110001";
when "0010"=> fig:="00110010";
when "0011"=> fig:="00110011";
when "0100"=> fig:="00110100";
when "0101"=> fig:="00110101";
when "0110"=> fig:="00110110";
when "0111"=> fig:="00110111";
when "1000"=> fig:="00111000";
when "1001"=> fig:="00111001";
when others=> fig:="00100000";
23
function
putc
(data:character)
function putn
(num:in_std_logic_vector
(3 downto 0))
译码函数完成
字符译码
译码函数完成
0~9的ASCII
译码
24
if suc='1' then
case cnt is
when 0=> data<=putc('Y')(7 downto 4);
when 1=> data<=putc('O')(7 downto 4);
when 2=> data<=putc('U')(7 downto 4);
when 3=> data<=putc(' ')(7 downto 4);
when 4=> data<=putc(' ')(7 downto 4);
when 5=> data<=putc(' ')(7 downto 4);
when 6=> data<=putc('W')(7 downto 4);
when 7=> data<=putc('I')(7 downto 4);
when 8=> data<=putc('N')(7 downto 4);
when 9=> data<=putc('!')(7 downto 4);
当胜利的时候
第一行
输出YOU WIN
25
when 15=> data<=putc('h')(7 downto 4); 第二行输出
when 16=> data<=putc('i')(7 downto 4);
High 最大得分
when 17=> data<=putc('g')(7 downto 4);
when 18=> data<=putc('h')(7 downto 4);
when 19=> data<=putc(' ')(7 downto 4);
when 20=> data<=putc(' ')(7 downto 4);
when 21=> data<=putn(max100)(7 downto
4);
when 22=> data<=putn(max10)(7 downto 4);
when 23=> data<=putn(max1)(7 downto 4);
26
同理:
当over=‘1’时
第一行显示
YOU LOSE!
第二行显示
high 最高得分
27
life score high
第二行显示 xx xxx xxx 分别代表
命数、分数和历史最高分
其他情况下第一行显示
返回
VGA模块
VGA
开机画面 游戏画面 胜利失败
29
VGA显示原理
640X480显示模式
要实现VGA显示关键是如何实现VGA时序。 行
时序和帧时序都需要产生同步脉冲(Sync a)、显
示后沿(Back porch b)、显示时序段(Display
interval c)和显示前沿(Front porch d)四个部分
30
31
if clk50m'event and
clk50m='1' then
clk25m<=not clk25m;
因为显示屏的显示频
率是60hz
60*800*525=25Mhz
因此我们要用50M的
时钟做一个2分频得
到25M的时钟。
constant H_PIXELS:
INTEGER:=640;
--行显示点数
constant H_FRONT:
INTEGER:=8;
--行前消隐点数
constant H_BACK:
INTEGER:=40;
--行后消隐点数
constant
H_SYNCTIME:INTEGER:=96;
--行同步点数
constant H_PERIOD: INTEGER:=
H_SYNCTIME + H_PIXELS +
H_FRONT + H_BACK;
--行周期计数值
process(sysclk)
begin
if (sysclk'event and
sysclk = '1') then
if hcnt < H_PERIOD
then
hcnt <= hcnt + 1;
else--当行计数到达
计数周期时将重置
hcnt <= (others =>
'0');
33
constant H_PIXELS: INTEGER:=640;
--行显示点数
constant H_FRONT: INTEGER:=8;
--行前消隐点数
constant H_BACK: INTEGER:=40;
--行后消隐点数
constant H_SYNCTIME:INTEGER:=96;
--行同步点数
if (hcnt >= (H_PIXELS + H_FRONT) and
hcnt < (H_PIXELS + H_SYNCTIME +
H_FRONT)) then
hsyncb <= '0';
else
hsyncb <= '1';
当显示的点运
动位置在
(640+8)像
素点与
(640+8+96)
像素点之间的
时候,进行消
隐。
产生行同步信号
process(hsyncb)
begin
if (hsyncb'event and
hsyncb = '1') then
if (vcnt >= (V_LINES +
V_FRONT) and vcnt <
(V_LINES +
V_SYNCTIME +
V_FRONT)) then
vsyncb <= '0';
else
vsyncb <= '1';
产生场同步信号
当显示的点运动位置在
(480+2)行与
(480+2+2)行点之间
的时候,进行消隐
process
(sysclk)
begin
if sysclk'EVENT and
sysclk = '1' then
if hcnt >= H_PIXELS
or vcnt >= V_LINES
then
enable <= '0';
else
enable <= '1';
屏幕显示使能信号
赋值
36
由RGB三种原色可以组成8种所需要的颜色
37
开机画面
38
开机画面描述:
if(play='0')then
--显示开机画面的条件
if(vloc范围)then
--约束行范围
if((hloc范围)then --约束列范围
rgbx<="000";rgby<="000"; --赋值为颜色1
elsif((hloc范围)then --约束列范围
rgbx<="100";rgby<="000"; --赋值为颜色2
else
--其他列范围
rgbx<="100";rgby<="010";
--赋值为颜色3
……
39
失败~~
40
胜利!!
返回
41
四、作品展示
将程序烧至实验板中,未开始前显示为初始化
状态,屏幕显示开机画面,拨动“start”开关,
进入游戏,背景音乐响起。每打中一只老鼠,
得分加一,否则命数减一,打中10次升一级,
老鼠出现频率加快,失败显示哭脸,成功显示
笑脸。拨动暂停键,游戏可随时暂停继续。