c51单片机俄罗斯方块设计.docx
《c51单片机俄罗斯方块设计.docx》由会员分享,可在线阅读,更多相关《c51单片机俄罗斯方块设计.docx(34页珍藏版)》请在冰豆网上搜索。
c51单片机俄罗斯方块设计
设计题目:
C51单片机俄罗斯方块游戏
一、系统设计小组工作分工
序号
成员
工作分工
1
焦磊
软件编程及修改
2
韩洋
硬件选择及设计
3
张宏
最终整体调试运行及优化
二.系统设计目标
俄罗斯方块是一款风靡全球的电视游戏机和掌上游戏机游戏,作为最经典的游戏之一,它曾造成的轰动与经济价值可以说是游戏史上的一件大事。
这款游戏最初是由苏联的游戏制作人AlexPajitnov制作的,它看似简单但却变化无穷,令人上瘾。
相信大多数用户都还记得为它痴迷得茶不思饭不想的那个俄罗斯方块时代。
虽然用单片机来设计一个简单的俄罗斯方块游戏程序似乎有点大材小用了,但这仅仅是一个单片机在嵌入式游戏方面的简单应用,正因为他的前景无可预计,所以才有这个设计,此次设计仅仅是为了举一个单片机在游戏上应用的一个简单例子,他可以很好的说明单片机功能的强大,更高的可控性和高集成度的好处,因此它可以在电子游戏方面成为一个不可计量的明日之星。
2005年,以计算机技术、通信技术和软件技术为核心的信息技术取得了更加迅猛的发展,加上3C(计算机、通讯、消费电子)产业的加速融合及3G移动通信时代的逐步到来,嵌入式软件在国民经济各领域和日常生活中发挥了更加重要的作用。
嵌入式软件的发展为几乎所有的电子设备注入了新的活力,各种装备与设备上嵌入式系统软件的广泛应用也大大地推动了其行业渗透性应用。
嵌入式软件不仅提高了传统产品的技术含量,更成为产品增值的关键因素,在整个软件产业中占据了重要地位,并受到世界各国的广泛关注,如今已成为信息产业中最为耀眼的“明星”之一。
三.系统方案设计
程序整体思路
单片机上的程序设计一般是一个大循环结构,对于俄罗斯方块的程序设计,首先产生一个伪随机数,其范围是0-6,然后程序根据此数值所对应的图形模块装入ram的固定区域内,紧接着将此图像写入led所对应的显示缓冲区中,显示程序将缓冲区内的内容显示在led上,如果没有控制键按下,图形将自动向下移动。
如果有键按下,程序将根据按下的键来改变图形存储区的值,同时程序将判断图形是否已到达边界,当图形最上层到达显示区顶部,则游戏结束,此时将清楚显示缓冲的内容,游戏重新开始。
图形的上下移动根据点阵理论可通过图形数据的左右移动和地址变化来实现。
图形的变化图形的变化图形的变化图形的变化:
可通过地址变化来得到。
即把需要变化的数据送到一固定地址,通过地址变化再送回显示的地址里面。
图形的碰边处理图形的碰边处理图形的碰边处理图形的碰边处理:
可通过各个边上的数据判断是否到边来实现。
与原有图形相遇与原有图形相遇与原有图形相遇与原有图形相遇:
可通过与原有图形数据进行比较处理来实现。
:
图形的旋转图形的旋转图形的旋转图形的旋转:
在固定地址里面实现旋转比较容易,但是在行进中的图形旋转就比较费脑筋,我是用一个地址计数下移的次数,再用一个地址计数左移右移的次数。
再根据这些次数确定图形的地址,再把这些地址送到图形变化的一个固定的地址中,变化后再送回到显示的地址中去显示。
图形的碰边处理图形的碰边处理图形的碰边处理图形的碰边处理:
如果不对图形进行边框处理,图形就会一直移动,看不到我们想要的效果。
我是用把边框数据与图形数据进行位运算。
再判断这些数据就可以得到图形是否到边
四.硬件电路设计及描述
button按钮若干
METALFILM100K电阻若干
7404为六组反向器若干
74LS21双4输入与门若干
8*8LED点阵四组
AT89C52一个低电压,高性能CMOS8位单片机一个
片内含8kbytes的可反复擦写的Flash只读程序存储器和256
bytes的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度、非易失性存储技术生产,
兼容标准MCS-51指令系统,片内置通用8位中央处理器和Flash存储单元,
AT89C52单片机在电子行业中有着广泛的应用。
74LS13874LS138为3线-8线译码器一个
①当一个选通端(E1)为高电平,另两个选通端((/E2))和/(E3))为低电平时,可将地址端(A0、A1、A2)的二进制编码在Y0至Y7对应的输出端以低电平译出。
比如:
A2A1A0=110时,则Y6输出端输出低电平信号。
②利用E1、E2和E3可级联扩展成24线译码器;若外接一个反相器还可级联扩展成32线译码器。
③若将选通端中的一个作为数据输入端时,74LS138还可作数据分配器。
④可用在8086的译码电路中,扩展内存。
74LS373D锁存器四个
373为三态输出的八D透明锁存器,共有54S373和74LS373两种线路
结构型式,373的输出端Q0~Q7可直接与总线相连。
当三态允许控制端OE为低电平时,Q0~Q7为正常逻辑状态,可用来驱动负载或总线。
当OE为高电平时,Q0~Q7呈高阻态,即不驱动总线,也不为总线的负载,但锁存器内部的逻辑操作不受影响。
当锁存允许端LE为高电平时,Q随数据D而变。
当LE为低电平时,D被锁存在已建立的数据电平。
当LE端施密特触发器的输入滞后作用,使交流和直流噪声抗扰度被改善400mV。
引出端符号:
D0~D7数据输入端
OE三态允许控制端(低电平有效)
LE锁存允许端
Q0~Q7输出端
五.软件设计及描述
程序源代码
俄罗斯方块游戏定义程序
/*Tetris.h中定义*/
unsignedintcodeBox_Ram_data[]=
{
0x0020,0x0020,0x0020,0x0020,0x0020,0x0020,0x0020,0x0020,
0x0020,0x0020,0x0020,0x0020,0x0020,0x0020,0x0020,0x0020,
0xffff,0x0000,0x0000//多出来的三行是为了能让方块落到最低位置
//多出来的第一行置0xffff用于检测方块释放到底
//显示行初值为0x0020表示右边界
};//游戏点阵缓存10*16(用前10位表示)(1表示亮,0表示灭)
unsignedintcodegame_data[]=
{
0x64DB,0x8AAA,0x8AAA,0x8AAB,0xEEAA,0xAAAA,0xEAAB,0x0000
};//game字模(0x64,0xDB,0x8A,0xAA,0x8A,0xAA,0x8A,0xAB,0xEE,0xAA,0xAA,0xAA,0xEA,0xAB,0x00,0x00,)
unsignedintcodeover_data[]=
{
0x6566,0x9549,0x9549,0x956F,0x954A,0x9549,0x6268,0x0000
};//over字模(0x65,0x66,0x95,0x49,0x95,0x49,0x95,0x6F,0x95,0x4A,0x95,0x49,0x62,0x68,0x00,0x00,)
unsignedintcodescore_data[]=
{
0xC000,0x8000,0x9BB7,0xD2A5,0x52A7,0x52A4,0xDBA7,0x0000
};//score字模(0xC0,0x00,0x80,0x00,0x9B,0xB7,0xD2,0xA5,0x52,0xA7,0x52,0xA4,0xDB,0xA7,0x00,0x00,)
unsignedintcodetetris_data[]=
{
0xE000,0x4008,0x4000,0x5A6B,0x574A,0x5A4B,0x5249,0x5B4B
};//tetris字模(0xE0,0x00,0x40,0x08,0x40,0x00,0x5A,0x6B,0x57,0x4A,0x5A,0x4B,0x52,0x49,0x5B,0x4B,)
unsignedlongcodenum_data[]=
{
0xF99999F0,//0字模
0x11111110,//1字模
0xF11F88F0,//2字模
0xF11F11F0,//3字模
0x999F1110,//4字模
0xF88F11F0,//5字模
0xF88F99F0,//6字模
0xF1111110,//7字模
0xF99F99F0,//8字模
0xF99F11F0,//9字模
};//数字字模
unsignedintidataBox_Ram[19];//定义游戏点阵缓存10*16
unsignedcharbox_down_reg;//定义方块下落累加寄存器
unsignedchartime0_reg;//定义定时器0累加寄存器
unsignedcharnext_mode;//定义下一个方块的类型
unsignedcharnext_shape;//定义下一个方块的形状
bitgame_over_flag;//游戏结束标志位置0表示游戏未结束
bitpause_game_flag;//游戏暂停标志位置0表示游戏未暂停
struct
{
unsignedcharmode;//类型
unsignedcharshape;//形状
unsignedcharx;//x坐标
unsignedchary;//y坐标
unsignedintbox;//定义方块缓存
}s_box;//定义方块结构体
//声明函数
voidbox_build();//方块生成函数
unsignedintbox_read_data(unsignedchartpmode,unsignedchartpshape);//方块缓存数据函数(输入方块类型和形状即可获得方块缓存数据)
voidbox_load();//方块载入函数
voidbox_to_Box_Ram(unsignedchartpx,unsignedchartpy,unsignedinttpbox);//方块映射游戏点阵缓存函数(参数是原来方块的位置、缓存,先消去原有位置的方块)
voidBox_Ram_to_Ram();//游戏点阵缓存映射显示点阵缓存函数
voidgame_execute();//游戏执行函数(控制方块下落,检测是否到底,如果到底调用消行函数)
voidtime0_initialize();//定时器0初始化函数
bitcheck_cover(unsignedchartpx,unsignedchartpy,unsignedinttpbox);//检查覆盖函数(检查此时带入的参数所确定的方块是否会覆盖原有图形,不会覆盖返回1,覆盖返回0)
voiddestroy_row();//消行函数
voidnext_box();//显示下一个方块函数
voidTetris_main();//俄罗斯方块游戏主函数
voidgame_over_show();//游戏结束画面显示函数
voidgame_initialize();//游戏初始化函数
voidgame_start_show();//游戏开始显示画面
bitcheck_game_over();//检查游戏结束函数(游戏结束返回1,游戏没有结束返回0)
voidcheck_pause_game();//检测暂停游戏函数
/*Tetris.h中定义*/
/*button_drive.h中定义*/
#definebutton_delay600//按键延时
sbitbutton_a=P0^7;
sbitup=P3^4;
sbitdown=P3^5;
sbitleft=P3^6;
sbitright=P3^7;
unsignedintup_reg=button_delay;//按键up累加器
unsignedintdown_reg=button_delay;//按键down累加器
unsignedintleft_reg=button_delay;//按键left累加器
unsignedintright_reg=button_delay;//按键right累加器
unsignedintbutton_a_reg=button_delay;//按键button_a累加器
//声明函数
voidgame_button();//游戏中按键识别程序(有优先级,从高到低依次是button_a_reg>down>left>right)
unsignedcharbasic_button();//基本按键程序(返回0表示没按键被按下,返回1表示down被按下,返回2表示up被按下,返回3表示button_a被按下,返回4表示left被按下,返回5表示right被按下)
/*button_drive.h中定义*/
俄罗斯方块游戏程序
voidbox_build()
{
s_box.mode=next_mode;
s_box.shape=next_shape;
s_box.x=3;
s_box.y=0;
next_mode=TL0%7;//产生随机数,但是是伪随机的
next_shape=TL0%4;//产生随机数,但是是伪随机的
}//方块生成函数
unsignedintbox_read_data(unsignedchartpmode,unsignedchartpshape)
{
unsignedinttpbox;
switch(tpmode)
{
case0:
switch(tpshape)
{
case0:
tpbox=0xf000;break;
case1:
tpbox=0x8888;break;
case2:
tpbox=0xf000;break;
case3:
tpbox=0x8888;break;
default:
;
}break;
case1:
switch(tpshape)
{
case0:
tpbox=0xe800;break;
case1:
tpbox=0xc440;break;
case2:
tpbox=0x2e00;break;
case3:
tpbox=0x88c0;break;
default:
;
}break;
case2:
switch(tpshape)
{
case0:
tpbox=0xe200;break;
case1:
tpbox=0x44c0;break;
case2:
tpbox=0x8e00;break;
case3:
tpbox=0xc880;break;
default:
;
}break;
case3:
switch(tpshape)
{
case0:
tpbox=0xcc00;break;
case1:
tpbox=0xcc00;break;
case2:
tpbox=0xcc00;break;
case3:
tpbox=0xcc00;break;
default:
;
}break;
case4:
switch(tpshape)
{
case0:
tpbox=0xc600;break;
case1:
tpbox=0x4c80;break;
case2:
tpbox=0xc600;break;
case3:
tpbox=0x4c80;break;
default:
;
}break;
case5:
switch(tpshape)
{
case0:
tpbox=0x6c00;break;
case1:
tpbox=0x8c40;break;
case2:
tpbox=0x6c00;break;
case3:
tpbox=0x8c40;break;
default:
;
}break;
case6:
switch(tpshape)
{
case0:
tpbox=0x4e00;break;
case1:
tpbox=0x8c80;break;
case2:
tpbox=0xe400;break;
case3:
tpbox=0x4c40;break;
default:
;
}break;
default:
;
}
return(tpbox);
}//方块缓存数据函数(输入方块类型和形状即可获得方块缓存数据)
voidbox_load()
{
s_box.box=box_read_data(s_box.mode,s_box.shape);
}//方块载入函数
voidbox_to_Box_Ram(unsignedchartpx,unsignedchartpy,unsignedinttpbox)
{
unsignedchari;
unsignedinttemp;
temp=tpbox;
for(i=0;i<4;i++)
{
Box_Ram[3-i+tpy]=Box_Ram[3-i+tpy]&(~((temp&0x000f)<<(12-tpx)));
temp=temp>>4;
}//从游戏点阵缓存中删除以前的方块
temp=s_box.box;
for(i=0;i<4;i++)
{
Box_Ram[3-i+s_box.y]=((temp&0x000f)<<(12-s_box.x))|Box_Ram[3-i+s_box.y];
temp=temp>>4;
}//在游戏点阵缓存中加入新的方块
}//方块映射游戏点阵缓存函数(参数是原来方块的位置、缓存,先消去原有位置的方块)
voidBox_Ram_to_Ram()
{
unsignedchari;
for(i=0;i<8;i++)
{
Ram[i]=(Box_Ram[i]>>8)&0x00ff;
Ram[i+8]=Box_Ram[i]&0x00ff;
Ram[i+16]=(Box_Ram[i+8]>>8)&0x00ff;
Ram[i+24]=Box_Ram[i+8]&0x00ff;
}
}//游戏点阵缓存映射显示点阵缓存函数
voidgame_execute()
{
if(box_down_reg<20)
{
box_down_reg++;
}
else
{
box_down_reg=0;
if(check_cover(s_box.x,s_box.y+1,s_box.box))
{
s_box.y++;
box_to_Box_Ram(s_box.x,s_box.y-1,s_box.box);
Box_Ram_to_Ram();
}//检测是否还可以下降,如果还能下降则继续下降
else
{
destroy_row();
box_build();
box_load();
game_over_flag=check_game_over();//游戏结束标志位置1表示游戏结束
next_box();
box_to_Box_Ram(s_box.x,s_box.y,s_box.box);
Box_Ram_to_Ram();
}//如果不能下降则调用消行函数检查是否可以消行,之后重新建立方块
}
}//游戏执行函数(控制方块下落,检测是否到底,如果到底调用消行函数)
voidtime0_initialize()
{
TMOD=0x03;//定时器0,16位工作方式
TR0=1;//启动定时器
ET0=1;//打开定时器0中断
//默认中断优先级为低
EA=1;//打开总中断
}//定时器0初始化函数
voidtimer0()interrupt1
{
TH0=0x00;
TL0=0x00;
if(time0_reg<10)
{
time0_reg++;
}
else
{
time0_reg=0;
game_execute();
display();
}
}//定时器0中断服务
bitcheck_cover(unsignedchartpx,unsignedchartpy,unsignedinttpbox)
{
unsignedchari;
bittpflag=1;
unsignedinttemp;
temp=s_box.box;
for(i=0;i<4;i++)
{
Box_Ram[3-i+s_box.y]=Box_Ram[3-i+s_box.y]&(~((temp&0x000f)<<(12-s_box.x)));
temp=temp>>4;
}//先将现有的方块从游戏点阵缓存中删除
temp=tpbox;
for(i=0;i<4;i++)
{
if((((temp&0x000f)<<(12-tpx))&Box_Ram[3-i+tpy])!
=0x0000)
{
tpflag=0;
}
temp=temp>>4;
}//检查方块是否和原有图形重叠,重叠置标志位tpflag为0,不重叠不置标志位,即tpflag为1
temp=s_box.box;
for(i=0;i<4;i++)
{
Box_Ram[3-i+s_box.y]=((temp&0x000f)<<(12-s_box.x))|Box_Ram[3-i+s_box.y];
temp=temp>>4;
}//在游戏点阵缓存中恢复原有方块
return(tpflag);
}//检查覆盖函数(检查此时带入的参数所确定的方块是否会覆盖原有图形,不会覆盖返回1,覆盖返回0)
voiddestroy_row()
{
unsignedchari,j=0;
unsignedchartpflag[4]={0,0,0,0};//最多一次只能消四行,所以设置四个标志位即可,初值为0
for(i=0;i<16;i++)
{
if((Box_Ram[i]&0xffc0)==0xffc0)
{
tpflag[j]=i+1;//tpflag为0表示不标志,1表示第0行缓存为0xffff,n表示第n+1行缓存为0xffff
j++;
if(j==4)
{
break;
}//检查完有四行要消除则退出检查循环
}
}//依次检