c51单片机俄罗斯方块设计
发布时间:2017-07-04 09:05:56
发布时间:2017-07-04 09:05:56
设计题目: C51单片机俄罗斯方块游戏
一、系统设计小组工作分工
序号 | 成员 | 工作分工 |
1 | 焦磊 | 软件编程及修改 |
2 | 韩洋 | 硬件选择及设计 |
3 | 张宏 | 最终整体调试运行及优化 |
二.系统设计目标
俄罗斯方块是一款风靡全球的电视游戏机和掌上游戏机游戏,作为最经典的游戏之一,它曾造成的轰动与经济价值可以说是游戏史上的一件大事。这款游戏最初是由苏联的游戏制作人 Alex Pajitnov 制作的,它看似简单但却变化无穷,令人上瘾。相信大多数用户都还记得为它痴迷得茶不思饭不想的那个俄罗斯方块时代。 虽然用单片机来设计一个简单的俄罗斯方块游戏程序似乎有点大材小用了,但这仅仅是一个单片机在嵌入式游戏方面的简单应用,正因为他的前景无可预计,所以才有这个设计,此次设计仅仅是为了举一个单片机在游戏上应用的一个简单例子,他可以很好的说明单片机功能的强大,更高的可控性和高集成度的好处,因此它可以在电子游戏方面成为一个不可计量的明日之星。 2005年,以计算机技术、通信技术和软件技术为核心的信息技术取得了更加迅猛的发展,加上3C(计算机、通讯、消费电子)产业的加速融合及3G移动通信时代的逐步到来,嵌入式软件在国民经济各领域和日常生活中发挥了更加重要的作用。嵌入式软件的发展为几乎所有的电子设备注入了新的活力,各种装备与设备上嵌入式系统软件的广泛应用也大大地推动了其行业渗透性应用。嵌入式软件不仅提高了传统产品的技术含量,更成为产品增值的关键因素,在整个软件产业中占据了重要地位,并受到世界各国的广泛关注,如今已成为信息产业中最为耀眼的“明星”之一。 |
三.系统方案设计
程序整体思路
单片机上的程序设计一般是一个大循环结构,对于俄罗斯方块的程序设计,首先产生一个伪随机数,其范围是0-6,然后程序根据此数值所对应的图形模块装入ram的固定区域内,紧接着将此图像写入led所对应的显示缓冲区中,显示程序将缓冲区内的内容显示在led上,如果没有控制键按下,图形将自动向下移动。如果有键按下,程序将根据按下的键来改变图形存储区的值,同时程序将判断图形是否已到达边界,当图形最上层到达显示区顶部,则游戏结束,此时将清楚显示缓冲的内容,游戏重新开始。
图形的上下移动根据点阵理论可通过图形数据的左右移动和地址变化来实现。
图形的变化图形的变化图形的变化图形的变化: 可通过地址变化来得到。即把需要变化的数据送到一固定地址,通过地址变化再送回显示的地址里面。 图形的碰边处理图形的碰边处理图形的碰边处理图形的碰边处理: 可通过各个边上的数据判断是否到边来实现。 与原有图形相遇与原有图形相遇与原有图形相遇与原有图形相遇: 可通过与原有图形数据进行比较处理来实现。: 图形的旋转图形的旋转图形的旋转图形的旋转: 在固定地址里面实现旋转比较容易,但是在行进中的图形旋转就比较费脑筋,我是用一个地址计数下移的次数,再用一个地址计数左移右移的次数。再根据这些次数确定图形的地址,再把这些地址送到图形变化的一个固定的地址中,变化后再送回到显示的地址中去显示。 图形的碰边处理图形的碰边处理图形的碰边处理图形的碰边处理: 如果不对图形进行边框处理,图形就会一直移动,看不到我们想要的效果。我是用把边框数据与图形数据进行位运算。再判断这些数据就可以得到图形是否到边
四.硬件电路设计及描述
button 按钮 若干
METALFILM100K 电阻 若干
7404 为六组反向器 若干
74LS21 双4输入与门 若干
8*8LED点阵 四组
AT89C52 一个低电压,高性能CMOS 8位单片机 一个
片内含8k bytes的可反复擦写的Flash只读程序存储器和256
bytes的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度、非易失性存储技术生产,
兼容标准MCS-51指令系统,片内置通用8位中央处理器和Flash存储单元,
AT89C52单片机在电子行业中有着广泛的应用。
74LS138 74LS138 为3 线-8 线译码器 一个
①当一个选通端(E1)为高电平,另两个选通端((/E2))和/(E3))为低电平时,可将地址端(A0、A1、A2)的二进制编码在Y0至Y7对应的输出端以低电平译出。比如:A2A1A0=110时,则Y6输出端输出低电平信号。
②利用 E1、E2和E3可级联扩展成 24 线译码器;若外接一个反相器还可级联扩展成 32 线译码器。
③若将选通端中的一个作为数据输入端时,74LS138还可作数据分配器。
④可用在8086的译码电路中,扩展内存。
74LS373 D 锁存器 四个
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中定义*/
unsigned int code Box_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表示灭)
unsigned int code game_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,)
unsigned int code over_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,)
unsigned int code score_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,)
unsigned int code tetris_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,)
unsigned long code num_data[]=
{
0xF99999F0,//0字模
0x11111110,//1字模
0xF11F88F0,//2字模
0xF11F11F0,//3字模
0x999F1110,//4字模
0xF88F11F0,//5字模
0xF88F99F0,//6字模
0xF1111110,//7字模
0xF99F99F0,//8字模
0xF99F11F0,//9字模
};//数字字模
unsigned int idata Box_Ram[19];//定义游戏点阵缓存10*16
unsigned char box_down_reg;//定义方块下落累加寄存器
unsigned char time0_reg;//定义定时器0累加寄存器
unsigned char next_mode;//定义下一个方块的类型
unsigned char next_shape;//定义下一个方块的形状
bit game_over_flag;//游戏结束标志位置0表示游戏未结束
bit pause_game_flag;//游戏暂停标志位置0表示游戏未暂停
struct
{
unsigned char mode;//类型
unsigned char shape;//形状
unsigned char x;//x坐标
unsigned char y;//y坐标
unsigned int box;//定义方块缓存
}s_box; //定义方块结构体
//声明函数
void box_build();//方块生成函数
unsigned int box_read_data(unsigned char tpmode,unsigned char tpshape);//方块缓存数据函数(输入方块类型和形状即可获得方块缓存数据)
void box_load();//方块载入函数
void box_to_Box_Ram(unsigned char tpx,unsigned char tpy,unsigned int tpbox);//方块映射游戏点阵缓存函数(参数是原来方块的位置、缓存,先消去原有位置的方块)
void Box_Ram_to_Ram();//游戏点阵缓存映射显示点阵缓存函数
void game_execute();//游戏执行函数(控制方块下落,检测是否到底,如果到底调用消行函数)
void time0_initialize();//定时器0初始化函数
bit check_cover(unsigned char tpx,unsigned char tpy,unsigned int tpbox);//检查覆盖函数(检查此时带入的参数所确定的方块是否会覆盖原有图形,不会覆盖返回1,覆盖返回0)
void destroy_row();//消行函数
void next_box();//显示下一个方块函数
void Tetris_main();//俄罗斯方块游戏主函数
void game_over_show();//游戏结束画面显示函数
void game_initialize();//游戏初始化函数
void game_start_show();//游戏开始显示画面
bit check_game_over();//检查游戏结束函数(游戏结束返回1,游戏没有结束返回0)
void check_pause_game();//检测暂停游戏函数
/*Tetris.h中定义*/
/*button_drive.h中定义*/
#define button_delay 600 //按键延时
sbit button_a = P0^7;
sbit up = P3^4;
sbit down = P3^5;
sbit left = P3^6;
sbit right = P3^7;
unsigned int up_reg=button_delay; //按键up累加器
unsigned int down_reg=button_delay; //按键down累加器
unsigned int left_reg=button_delay; //按键left累加器
unsigned int right_reg=button_delay; //按键right累加器
unsigned int button_a_reg=button_delay; //按键button_a累加器
//声明函数
void game_button();//游戏中按键识别程序(有优先级,从高到低依次是button_a_reg>down>left>right)
unsigned char basic_button();//基本按键程序(返回0表示没按键被按下,返回1表示down被按下,返回2表示up被按下,返回3表示button_a被按下,返回4表示left被按下,返回5表示right被按下)
/*button_drive.h中定义*/
俄罗斯方块游戏程序
void box_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;//产生随机数,但是是伪随机的
}//方块生成函数
unsigned int box_read_data(unsigned char tpmode,unsigned char tpshape)
{
unsigned int tpbox;
switch(tpmode)
{
case 0: switch(tpshape)
{
case 0: tpbox=0xf000;break;
case 1: tpbox=0x8888;break;
case 2: tpbox=0xf000;break;
case 3: tpbox=0x8888;break;
default:;
}break;
case 1: switch(tpshape)
{
case 0: tpbox=0xe800;break;
case 1: tpbox=0xc440;break;
case 2: tpbox=0x2e00;break;
case 3: tpbox=0x88c0;break;
default:;
}break;
case 2: switch(tpshape)
{
case 0: tpbox=0xe200;break;
case 1: tpbox=0x44c0;break;
case 2: tpbox=0x8e00;break;
case 3: tpbox=0xc880;break;
default:;
}break;
case 3: switch(tpshape)
{
case 0: tpbox=0xcc00;break;
case 1: tpbox=0xcc00;break;
case 2: tpbox=0xcc00;break;
case 3: tpbox=0xcc00;break;
default:;
}break;
case 4: switch(tpshape)
{
case 0: tpbox=0xc600;break;
case 1: tpbox=0x4c80;break;
case 2: tpbox=0xc600;break;
case 3: tpbox=0x4c80;break;
default:;
}break;
case 5: switch(tpshape)
{
case 0: tpbox=0x6c00;break;
case 1: tpbox=0x8c40;break;
case 2: tpbox=0x6c00;break;
case 3: tpbox=0x8c40;break;
default:;
}break;
case 6: switch(tpshape)
{
case 0: tpbox=0x4e00;break;
case 1: tpbox=0x8c80;break;
case 2: tpbox=0xe400;break;
case 3: tpbox=0x4c40;break;
default:;
}break;
default:;
}
return(tpbox);
}//方块缓存数据函数(输入方块类型和形状即可获得方块缓存数据)
void box_load()
{
s_box.box=box_read_data(s_box.mode,s_box.shape);
}//方块载入函数
void box_to_Box_Ram(unsigned char tpx,unsigned char tpy,unsigned int tpbox)
{
unsigned char i;
unsigned int temp;
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;
}//在游戏点阵缓存中加入新的方块
}//方块映射游戏点阵缓存函数(参数是原来方块的位置、缓存,先消去原有位置的方块)
void Box_Ram_to_Ram()
{
unsigned char i;
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;
}
}//游戏点阵缓存映射显示点阵缓存函数
void game_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();
}//如果不能下降则调用消行函数检查是否可以消行,之后重新建立方块
}
}//游戏执行函数(控制方块下落,检测是否到底,如果到底调用消行函数)
void time0_initialize()
{
TMOD=0x03;//定时器0,16位工作方式
TR0=1; //启动定时器
ET0=1; //打开定时器0中断
//默认中断优先级为低
EA=1; //打开总中断
}//定时器0初始化函数
void timer0() interrupt 1
{
TH0=0x00;
TL0=0x00;
if(time0_reg<10)
{
time0_reg++;
}
else
{
time0_reg=0;
game_execute();
display();
}
}//定时器0中断服务
bit check_cover(unsigned char tpx,unsigned char tpy,unsigned int tpbox)
{
unsigned char i;
bit tpflag=1;
unsigned int temp;
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)
void destroy_row()
{
unsigned char i,j=0;
unsigned char tpflag[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;
}//检查完有四行要消除则退出检查循环
}
}//依次检测是否有行缓存为0xffff,如果是则标志tpflag为此行的行号
for(j=0;j<4;j++)
{
if(tpflag[j]!=0)
{
for(i=tpflag[j]-1;i>0;i--)
{
Box_Ram[i]=(Box_Ram[i-1]&0xffc0)|(Box_Ram[i]&0x003f);
Box_Ram[0]=0x0000|(Box_Ram[0]&0x003f);
}
}
}//被标志的行依次被上一行所取代,即被消去
}//消行函数
void next_box()
{
unsigned char i;
unsigned int temp;
temp=box_read_data(next_mode,next_shape);
for(i=0;i<4;i++)
{
Box_Ram[3-i]=(temp&0x000f)|(Box_Ram[3-i]&0xfff0);
temp=temp>>4;
}//在游戏点阵缓存中显示下一个方块的样子
}//显示下一个方块函数
void Tetris_main()
{
unsigned char i;
for(i=0;i<19;i++)
{
Box_Ram[i]=Box_Ram_data[i];
};//载入游戏初始显示画面
game_over_flag=0;//游戏结束标志位置0表示游戏未结束
box_build();
box_load();
next_box();
box_to_Box_Ram(s_box.x,s_box.y,s_box.box);
Box_Ram_to_Ram();
// intermit0_initialize();
time0_initialize();
while(!game_over_flag)//如果游戏结束标志位置1,表示游戏结束,打破循环,调用游戏结束画面显示函数
{
game_button();
check_pause_game();
}
EA=0;//游戏结束后关中断,要不缓存区数据不正确
game_over_show();
}//俄罗斯方块游戏主函数
void game_over_show()
{
unsigned char i;
bit tpflag=1;//置循环标志位为1
for(i=0;i<8;i++)
{
Box_Ram[i]=game_data[i];
Box_Ram[i+8]=over_data[i];
}
Box_Ram_to_Ram();
while(tpflag)
{
display();
switch(basic_button())
{
case 3: tpflag=0;
break;
default:;
}
}//game over画面循环
game_start_show();//进入游戏开始显示画面
}//游戏结束画面显示函数
void game_initialize()
{
box_down_reg=0;
time0_reg=0;
next_mode=6;
next_shape=2;
game_over_flag=0;
pause_game_flag=0;
}//游戏初始化函数
void game_start_show()
{
unsigned char i;
bit tpflag=1;//置循环标志位为1
game_initialize();//调用游戏初始化函数,初始化游戏所有变量
for(i=0;i<16;i++)
{
Box_Ram[i]=0x0000;
};//清楚图像
for(i=0;i<8;i++)
{
Box_Ram[i+3]=tetris_data[i];
}
Box_Ram_to_Ram();
while(tpflag)
{
display();
switch(basic_button())
{
case 3: tpflag=0;
break;
default:;
}
}//game_start_show循环
Tetris_main();//进入俄罗斯方块游戏主函数
}//游戏开始显示画面
bit check_game_over()
{
unsigned char i;
bit tpflag=0;
unsigned int temp;
temp=s_box.box;
for(i=0;i<4;i++)
{
if((((temp&0x000f)<<(12-s_box.x))&Box_Ram[3-i+s_box.y])!=0x0000)
{
tpflag=1;
}
temp=temp>>4;
}//检查新建方块是否和原有图形重叠,重叠置标志位tpflag为1,不重叠不置标志位,即tpflag为0
return(tpflag);
}//检查游戏结束函数(游戏结束返回1,游戏没有结束返回0)
void check_pause_game()
{
if(pause_game_flag)
{
while(basic_button()!=2)
{
display();
}
}
pause_game_flag=0;
EA=1;//开中断,继续游戏
}//检测暂停游戏函数
按键驱动程序
void game_button()
{
switch(basic_button())
{
case 3: if(s_box.y!=0)//3表示button_a被按下
{
EA=0;//关中断,如果不关的话可能引起游戏显示混乱
if(s_box.shape==3&check_cover(s_box.x,s_box.y,box_read_data(s_box.mode,0)))
{
s_box.shape=0;
box_load();
box_to_Box_Ram(s_box.x,s_box.y,box_read_data(s_box.mode,3));
Box_Ram_to_Ram();
}
else
{ if(check_cover(s_box.x,s_box.y,box_read_data(s_box.mode,s_box.shape+1)))
{
s_box.shape++;
box_load();
box_to_Box_Ram(s_box.x,s_box.y,box_read_data(s_box.mode,s_box.shape-1));
Box_Ram_to_Ram();
}
}
EA=1;//开中断
}break;
case 1: if(s_box.y!=0)//1表示down被按下
{
EA=0;//关中断,如果不关的话可能引起游戏显示混乱
while(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();
}
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();
EA=1;//开中断
}break;
case 4: if(s_box.y!=0)//4表示left被按下
{
EA=0;//关中断,如果不关的话可能引起游戏显示混乱
if(s_box.x!=0&check_cover(s_box.x-1,s_box.y,s_box.box))
{
s_box.x--;
box_to_Box_Ram(s_box.x+1,s_box.y,s_box.box);
Box_Ram_to_Ram();
}
EA=1;//开中断
}break;
case 5: if(s_box.y!=0)//5表示right被按下
{
EA=0;//关中断,如果不关的话可能引起游戏显示混乱
if(check_cover(s_box.x+1,s_box.y,s_box.box))
{
s_box.x++;
box_to_Box_Ram(s_box.x-1,s_box.y,s_box.box);
Box_Ram_to_Ram();
}
EA=1;//开中断
}break;
case 2: //2表示up被按下
EA=0;//关中断,如果不关的话可能引起游戏显示混乱
pause_game_flag=1;//游戏暂停标志位置1,游戏暂停
break;
default:;
}
}//游戏中按键识别程序(有优先级,从高到低依次是button_a_reg>down>left>right>up)
unsigned char basic_button()
{
unsigned char tpflag=0;
if(down==0)
{
if(down_reg
{
down_reg++;
}
else
{
down_reg=0;
tpflag=1;//返回1表示down被按下
}
}
else
{
down_reg=button_delay;//释放按键时置按键缓存为button_delay,以便在下次按键时及时响应
}
if(up==0)
{
if(up_reg
{
up_reg++;
}
else
{
up_reg=0;
tpflag=2;//返回2表示up被按下
}
}
else
{
up_reg=button_delay;//释放按键时置按键缓存为button_delay,以便在下次按键时及时响应
}
if(button_a==0)
{
if(button_a_reg
{
button_a_reg++;
}
else
{
button_a_reg=0;
tpflag=3;//返回3表示button_a被按下
}
}
else
{
button_a_reg=button_delay;//释放按键时置按键缓存为button_delay,以便在下次按键时及时响应
}
if(left==0)
{
if(left_reg
{
left_reg++;
}
else
{
left_reg=0;
tpflag=4;//返回4表示left被按下
}
}
else
{
left_reg=button_delay;//释放按键时置按键缓存为button_delay,以便在下次按键时及时响应
}
if(right==0)
{
if(right_reg
{
right_reg++;
}
else
{
right_reg=0;
tpflag=5;//返回5表示right被按下
}
}
else
{
right_reg=button_delay;//释放按键时置按键缓存为button_delay,以便在下次按键时及时响应
}
return(tpflag);
}//基本按键程序(返回0表示没按键被按下,返回1表示down被按下,返回2表示up被按下,返回3表示button_a被按下,返回4表
点阵显示驱动程序
#define Line P1
#define Row P2
sbit CS1 = P3^0;
sbit CS2 = P3^1;
sbit CS3 = P3^2;
sbit CS4 = P3^3;
unsigned char Ram[]=
{
0x7F,0x02,0x1F,0x10,0x1F,0x10,0x1F,0x10,0xFE,0x00,0xF0,0x10,0xF0,0x10,0xF0,0x10,
0x1F,0x08,0x0F,0x08,0x16,0x21,0x0E,0x70,0xF0,0x00,0xF0,0x20,0x40,0x80,0x70,0x0E,
};//显示点阵缓存(1表示亮,0表示灭)
void delay(unsigned char temp)
{
unsigned char tp=temp;
while(tp--);
}//延时函数
void display()
{
unsigned char i,j;
for(i=0;i<4;i++)
{
Row=0x00;//初值都为低电平,将所有行锁存成低电平
CS1=1;CS2=1;CS3=1;CS4=1;
switch(i)
{
case 0:CS2=0;CS3=0;CS4=0;break;
case 1:CS1=0;CS3=0;CS4=0;break;
case 2:CS1=0;CS2=0;CS4=0;break;
case 3:CS1=0;CS2=0;CS3=0;break;
default:;
}
Row=0x01;//置行扫描初值
for(j=0;j<8;j++)
{
Line=~(Ram[i*8+j]);//列扫描
delay(100);//延时(仿真不延时无法显示,实物可能不用延时)
Row=Row<<1;//行扫描
}
}
}//点阵显示函数
游戏机主程序
#include
#include
#include
#include
#include
void main()
{
game_start_show();
}
六.设计调试过程及结果
第一 检查单片机的最小系统是否正常,包括检查晶振、单片机2端电压、复位电路已经EA 第二 看驱动芯片是否工作正常、接法是否正确,再检查LED点阵是否接的正确,可以用一节干电池测,也可以用指针万用表打到电阻10K档位测。
第三 软件程序正常运行无误
第四 最终试验成功
7.系统设计体会
通过此次课程设计,选这个课题并不是要做多么高级的游戏机,或者是游戏。通过这么一个普通的游戏机的设计,可以更深刻的了解单片机的构造,和对C语言的运用。游戏不是最主要的,主要的是在编辑的过程中,对程序的理解,数组的运用。我不仅把知识融会贯通,而且丰富了大脑,同时在查找资料的过程中也了解了许多课外知识,开拓了视野,认识了将来电子的发展方向,使自己在专业知识方面和动手能力方面有了质的飞跃。 “基于单片机的游戏机设计与实现”是从我们的日常生活而来的一个课题,该课题本身不是那么复杂,而且当今市场上卖的游戏机也是高级得多。
本课题的设计过程中,最为复杂的部分就是软件编程的调试,在程序调试过程中遇到一些问题,都得到了圆满的解决。 之前看似简单的程序竟然让我感觉到无从下手,有时一个数组算了好久,经过调试发现错了一位。 现在我明白知识必须通过应用才能实现其价值!有些东西以为学会了,但真正到用的时候才发现是两回事,所以我认为只有到真正会用的时候才是真的学会了。 在此要感谢我的指导老师对我悉心的指导,感谢老师给我的帮助。我通过查阅大量的有关资料,与同学交流经验和自学,并向老师请教等方式,使自己学到了不少知识,也经历了不少艰辛,但收获同样巨大。在整个设计中我懂得了许多东西,也培养了我独立工作的能力,树立了对自己工作能力的信心,相信会对今后的学习工作生活有非常重要的影响。而且大大提高了动手的能力,使我充分体会到了在创造过程中探索的艰难和成功时的喜悦。虽然这个设计做的也不是特别完美,但是在设计过程中所学到的东西是这次毕业设计的最大收获和财富,使我终身受益。
八.参考文献
[1]高凌琴,陈青华.俄罗斯方块游戏关键技术探讨[J]. 信息技术与信息化.2008.
[2]谭浩强. C程序设计.[M] 北京:清华大学出版社,2003.
[3]张齐.杜群贵.单片机应用系统设计技术——基于C语言编程[M].北京:电子工业出版社,2004.
[4]刘洪波.AT89C2051单片机及I/O口的扩展方法[J].山东电子,1997,1:16-18
[5]胡汉才.单片机原理及其接口技术[M].清华大学出版社,2000
[6]王彦朝. 二维数组在俄罗斯方块游戏编程中的应用[J].信息与电脑(理论版),2010-04:46-47 [7]王晓威,唐叔进,邢瑞.基于单片机和液晶显示器的游戏开发[J].电子世界,2005,7:30-31
[8]徐金增.单片机编程仿真实验系统的设计与实现[D].山东师范大学,2009,