测品娱乐
您的当前位置:首页推箱子游戏--51单片机课设计(最全)

推箱子游戏--51单片机课设计(最全)

来源:测品娱乐
.

《51单片机》 课程设计

题 目:基于51单片机的推箱子游戏设计

目 录

1、课程设计目的 ..................................................................................... 1 2、课程设计题目和实现目标 ................................................................. 1 3、设计方案.............................................................................................. 1 4、Proteus仿真原理图 ............................................................................ 7 5、程序设计.............................................................................................. 9 6、调试总结............................................................................................ 28 7、设计心得体会 ................................................................................... 28

.

参考文献 .................................................................................................. 29 附录:程序代码------------------------------------------------------------------29

1

1、课程设计目的

《MCS-51单片机》课程设计是与《MCS-51单片机》课程相配套的实践教学环节。《MCS-51单片机》是一门实践性很强的专业基础课,通过课程设计,达到进一步理解单片机的硬件、软件和综合应用方面的知识,培养实践能力和综合应用能力,开拓学习积极性、主动性,学会灵活运用已经学过的知识,并能不断接受新的知识。培养大胆发明创造的设计理念,为今后就业打下良好的基础。

通过课程设计,掌握以下知识和技能: 1.单片机应用系统的总体方案的设计; 2.单片机应用系统的硬件设计; 3.单片机应用系统的软件程序设计; 4.单片机开发系统的应用和调试能力

2、课程设计题目和实现目标

2.1 课程设计题目:基于51单片机的推箱子游戏设计 2.2实现目标

设计一款在以51单片机为核心的硬件系统中运行的推箱子游戏。游戏一共9关,功能包括:

(1)显示游戏开机界面和游戏界面;

(2)按键处理包括移动小人和移动箱子,通过移动上下左右键来控制小人的移动,通过小人推动箱子,把箱子推到指定的目的地为过关,箱子只能推不能拉; (3)用于可以任意选关,并能随时退出、进入游戏; (4)每一关都有时间计时,显示当前玩家的游戏耗时。 3、设计方案

根据设计目标,整个系统框图如下:

2

图1 系统框图

3.1 控制模块

选用ATMEL公司 生产的ATC52为主控芯片,它是是一个低电压,高性能CMOS 8位单片机,主要功能特性如下: 1、兼容MCS51指令系统;

2、8k可反复擦写(大于1000次)Flash 7、2个串行中断,可编程UART串行通道; 8、2个外部中断源,共8个中断源; 9、2个读写中断口线,3级加密位;

10、低功耗空闲和掉电模式,软件设置睡眠和唤醒功能; 本次课设选用PDIP封装的 ATC52芯片,其引脚功能如图2所示,图3为最小系统:

图2 引脚功能

3

图3 最小系统

U1:ATC52,DIPf封装;C1,C2:22pf瓷片电容 C3:10uf电解电容;X1:12M晶振 R1:10K金属膜电阻

3.2 显示模块

选用内置T6963C控制控制器的128图形点阵液晶(以下简称Lcd128)做为显示模块。

T6963C控制器的最大特点具是有硬件初始值设置功能,显示驱动所需的参数,例如:占空比系数、每行驱动传输的字节数、字符的字体选择等均由引脚电平设置。所以,液晶显示模块在上电时T6963C控制器就进行初始化设置,软件操作的主要精力就可以全部用于显示界面的设计上。

市场上出售此控制器的液晶很多,本次课设选用深圳市晶日达科技有限公司生产KXM128F.

LCD128和单片机以模拟方式连接,即通过模拟操作时序的方法控制液晶显示。具体的接线图如图4所示

4

图4 显示模块

RP1:1k排阻,用于做P0口的上拉电阻;LCD1:KXM128F 3.3按键模块

16个轻触按键连接成4*4矩阵键盘,做为按键模块,如图5所示

图5 4*4矩阵键盘

最终系统的硬件系统如下:

5

图6 硬件系统

4、Proteus仿真原理图

在proteus搭建的仿真原理图如下:

6

图7 硬件系统

图8 开机画面

7

图9 游戏画面

图10 游戏画面

8

5.程序设计

5.1 Lcd128显示驱动程序

图11 读写指令/数据时序图

准备向Lcd128进行操作时,首先要读取lcd128的当前的状态,只有lcd128不忙的时候才能读写操作和数据。相关程序如下:

/************************************************** 函数名:status_bit_01()

功能:状态位sta1(读/写指令),sta0(读/写数据)判断 入口参数:

返回值:状态值i

***************************************************/ unsigned char status_bit_01() {

unsigned char i; P0=0xff; cd=1; rd=0;

for(i=10;i>0;i--) {

if((P1&0x03)==0x03) break; } rd=1;

return i; }

/********************************************* 函数名:write_data(unsigned char dat) 功能:写数据

入口参数:8位数据dat

9

返回值:

*********************************************/ void write_data(unsigned char dat) {

while(status_bit_01()==0); rd=1;cd=0;wr=0; P0=dat;

wr=1;cd=1; }

/********************************************* 函数名:write_cmd1(unsigned char cmd) 功能:写命令,无参数 入口参数:8位命令cmd 返回值:

*********************************************/ void write_cmd1(unsigned char cmd) {

while(status_bit_01()==0); rd=1;cd=1;wr=0; P0=cmd;

wr=1;cd=0; }

/********************************************* 函数名:write_cmd2(unsigned char cmd) 功能:写单参数命令

入口参数:8位数据dat,8位命令cmd 返回值:

*********************************************/

void write_cmd2(unsigned char dat,unsigned char cmd) {

write_data(dat); write_cmd1(cmd); }

/************************************************ 函数名:write_cmd2(unsigned char cmd) 功能:写双参数命令

入口参数:8位数据data1,8位数据data2,8位命令cmd 返回值:

*************************************************/

void write_cmd3(unsigned char data1,unsigned char data2,unsigned char cmd) {

write_data(data1); write_data(data2); write_cmd1(cmd);

10

}

图12 为Lcd128的指令集,向Lcd128写入相关的指令,即可控制其显示。

图12 Lcd128的指令集

使用液晶前必须对其进行初始化操作,初始化的内容包括光标指针设置,图形区首地址,图形区宽度,显示方式设置,图形方式显示,标形状设置。相关程序如下:

/************************************************ 函数名:init_128() 功能:初始化lcd128 入口参数: 返回值:

*************************************************/ void init_128() {

wr=1;rd=1;cd=1;rst=1;//初始化

write_cmd3(0x01,0x00,0x21);//光标指针设置 write_cmd3(0x00,0x00,0x42);//图形区首地址 write_cmd3(16,0x00,0x43);//图形区宽度

11

write_cmd1(0x88);//显示方式设置,正常显示

write_cmd1(0x98);//图形方式显示,不显示字母,只打点 write_cmd1(0xa0);//光标形状设置1 0 1 0 0 N2 N1 N0 }

5.2 按键扫描程序

初始P1的电平为0x0f,当有按键下时,电平发生变化,开始程序开始扫描判断哪个按键被按下,并返回按键号,相关程序如下:

/******************************** 函数名:keys_scan() 功能:按键扫描 入口参数:

返回值:按键号keyno

*********************************/ unsigned char keys_scan() {

unsigned char tmp; unsigned char keyno; if(P1 != 0x0f) {

P1 = 0x0f; delayms(1); tmp = P1 ^ 0x0f; switch(tmp) {

case 1: keyno = 0;break; case 2: keyno = 1;break; case 4: keyno = 2;break; case 8: keyno = 3;break; default:keyno = 16; }

P1 = 0xf0; delayms(1);

tmp = (P1 >> 4)^ 0x0f; switch(tmp) {

case 1:keyno += 0;break; case 2:keyno += 4;break; case 4:keyno += 8;break; case 8:keyno += 12;break; }

P1=0x0f; return keyno;

12

} }

5.3 游戏元素设计

出现在显示画面中的游戏元素总共有6种:墙壁,箱子,小人,目的地,空白,箱子在目的地。每个元素在液晶上以一个字符显示,即8×8的点阵。在字模提取软件设计各个元素,并获得元素的显示码。显示码的每8位构成字符的一行,8就行有8个字节。其中1表示该点显示,0表示该点不显示。 图13-是在字模提取软件设计的各个元素,

图13 小人 图14 墙壁 图15 箱子

图16 目的地 图17 箱子在目的地 图18空白

定义一个二维数组elements[][8],存储这些点阵信息。其中第一个地址为元素代号

unsigned char code elements[][8]= {

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //0空白 0x3C,0x7E,0x66,0x3C,0x7E,0x99,0x3C,0x66, //1人物 0x7F,0x7F,0x7F,0x00,0xEF,0xEF,0xEF,0x00, //2砖头 0xFF,0xC3,0xA5,0x99,0x99,0xA5,0xC3,0xFF, //3箱子 0x00,0x18,0x24,0x4A,0x52,0x24,0x18,0x00, //4目标

0xFF,0xBD,0xDB,0xE7,0xE7,0xDB,0xBD,0xFF, //5箱子到达目标 };

5.4元素的显示

由于T6963c液晶是按以列1字符(8点),行1点来定位的,所以显示时,要先定位显示字符位的列字符和行字符首地址,即行*0x80+列;再定义一个循环

13

变量i,从0,到7,定位该字符位的8个点行,即行*0x80+列+i*0x10,定位到每个点行后,写入对应的元素字节,即elements[元素代号][i],就可以在液晶的指定字符位置上显示该元素了。相关元素显示子函数如下:

/************************************************ 函数名:printelement()

功能:指定字符位置,显示元素

入口参数:列字符地址xh,行字符地址yh,元素代码elnum 返回值:

*************************************************/

void printelement(unsigned char xh, unsigned char yh,unsigned char elnum) {

unsigned char i; int temp;

for(i=0;i<8;i++) //行地址加+1 {

temp = yh* 0x80+i*0x10 + xh;

write_cmd3(temp&0xff,temp/0xff,add_pos); write_cmd2(elements[elnum][i],noc_wr); } }

调用如下程序,对显示元素进行测试,图19为显示效果:

printelement(0,1,1); //在第0列,第1行,显示1号元素(小人) printelement(1,1,2); //在第1列,第1行,显示2号元素(墙壁) printelement(2,1,3); //在第2列,第1行,显示3号元素(箱子) printelement(3,1,4); //在第3列,第1行,显示4号元素(目的地)

printelement(4,1,5); //在第4列,第1行,显示5号元素(箱子在目的地上)

图19 显示效果

14

5.5 游戏关卡界面设计

游戏每关都是在8×8个字符组成的区域中进行的,只要在每一个字符显示相应的元素,就可以组成游戏界面。定义一个三维数组code level[][8][8],存储每一关每一个字符位上要显示的元素。 各关卡的界面如下: /*第1关*/ 0,0,2,2,2,2,2,0, 2,2,2,0,0,0,2,0, 2,0,3,0,2,0,2,2, 2,0,2,0,0,4,0,2, 2,0,0,0,0,2,0,2, 2,2,0,2,0,0,0,2, 0,2,1,0,0,2,2,2,

0,2,2,2,2,2,0,0,

/*第2关*/ 2,2,2,2,2,2,2,2, 2,0,0,0,0,0,1,2, 2,0,0,0,5,0,0,2, 2,0,0,2,2,2,2,2, 2,2,0,0,2,0,0,0, 2,0,3,0,2,0,0,0, 2,0,0,4,2,0,0,0,

2,2,2,2,2,0,0,0,

图20 第1关游戏画面

图21 第2关游戏画面

15

/*第3关*/ 0,0,2,2,2,2,0,0, 0,0,2,4,4,2,0,0, 0,2,2,0,4,2,2,0, 0,2,0,0,3,4,2,0, 2,2,0,3,0,0,2,2, 2,0,0,2,3,3,0,2, 2,0,0,1,0,0,0,2, 2,2,2,2,2,2,2,2,

/*第4关*/ 0,0,0,2,2,2,2,0, 0,2,2,2,0,1,2,0, 0,2,0,0,3,0,2,0, 2,2,0,2,0,2,2,2, 2,0,0,2,0,2,4,2, 2,0,2,0,0,3,4,2, 2,0,0,0,0,0,0,2, 2,2,2,2,2,2,2,2,

/*第5关*/ 0,0,0,2,2,2,2,0, 0,2,2,2,0,1,2,0, 0,2,0,0,3,0,2,0, 2,2,0,2,0,2,2,2, 2,0,0,2,0,2,4,2, 2,0,2,0,0,0,0,2, 2,0,0,0,0,0,0,2,

2,2,2,2,2,2,2,2, 图22 第3关游戏画面

图23 第4关游戏画面 图24 第5关游戏画面

16

/*第6关*/ 0,0,0,2,2,2,2,0, 0,2,2,2,0,1,2,0, 0,2,0,0,3,0,2,0, 2,2,0,2,0,2,2,2, 2,0,0,2,0,2,4,2, 2,0,2,0,0,3,4,2, 2,0,3,0,0,0,4,2,

2,2,2,2,2,2,2,2,

第6关*/ 0,0,2,2,2,2,2,0, 2,2,2,0,0,0,2,0, 2,0,3,0,2,0,2,2, 2,0,2,0,0,4,0,2, 2,0,0,0,0,2,0,2, 2,2,3,2,4,0,0,2, 0,2,1,0,0,2,2,2,

0,2,2,2,2,2,0,0,

/*第7关*/ 0,2,2,2,2,0,0,0, 2,2,0,0,2,0,0,0, 2,1,3,0,2,0,0,0, 2,2,3,0,2,2,0,0, 2,2,0,3,0,2,0,0, 2,4,3,0,0,2,0,0, 2,4,4,5,4,2,0,0,

2,2,2,2,2,2,0,0, 图25 第6关游戏画面 图26 第7关游戏画面 图27 第8关游戏画面

17

/*

};

5.6 开机画面

开机画面是用画图程序制作的一个128像素×像素的单色位图,并用取模软件提取该图像的点阵信息,共1024字节。使用t6963c的写数据地址自动加1的命令写入上述全部1024字节的数据,显示开机画面。

/*第9关*/ 0,0,0,2,2,2,2,0, 0,2,2,2,0,0,2,0, 2,2,0,1,3,0,2,0, 2,0,4,3,0,0,2,0, 2,0,4,5,0,2,2,0, 2,0,4,3,0,2,0,0, 2,2,0,0,2,2,0,0,

0,2,2,2,2,0,0,0, 图28 第9关游戏画面

图29 开机界面

图30 字模提取

18

图31 proteus中显示效果

图像的点阵码:

/*-- 宽度x高度=128x --*/

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xE0,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x7C,0xC0,0x06,0x30,0xC6,0x00,0x1F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x01,0x86,0xC7,0xF0,0x06,0x1F,0xC7,0xF8,0x30,0x00,0x01,0xC0,0x00,0x00,0x00,0x00,0x01,0x87,0x86,0x18,0x0C,0x01,0x80,0x0C,0x30,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x01,0x87,0x82,0x18,0x1C,0x01,0x80,0x0E,0x30,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x01,0x87,0x06,0x0C,0x18,0x01,0x00,0x06,0x30,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x0F,0x87,0x07,0x0F,0x10,0x03,0x00,0x0C,0x30,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x0C,0x06,0x00,0x01,0x90,0x43,0x00,0x0C,0x1F,0xFF,0x01,0x80,0x00,0x00,0x00,0x00,0x0C,0x06,0x00,0x01,0x98,0xC3,0x08,0x38,0x00,0x3E,0x03,0x00,0x00,0x00,0x00,0x00,0x0C,0x0C,0x00,0x01,0x8F,0xC3,0x1C,0x38,0x00,0x3C

19

,0x06,0x00,0x00,0x00,0x00,0x00,0x0C,0x0C,0x00,0x03,0x1F,0xC7,0xFC,0x7C,0x7F,0xF6,0x0F,0xE0,0x00,0x00,0x00,0x00,0x0F,0x88,0x1E,0x1F,0x1C,0x7F,0x67,0xDC,0xC0,0x03,0x18,0x30,0x00,0x00,0x00,0x00,0x01,0x8C,0x00,0x03,0x18,0x01,0x80,0x0C,0xC0,0x01,0xF0,0x30,0x00,0x00,0x00,0x00,0x03,0x87,0x80,0x03,0x10,0x00,0x80,0x0C,0xC0,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x0E,0x01,0x80,0x03,0x10,0x00,0x9F,0x0C,0xC0,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x0C,0x01,0x80,0x03,0x18,0x0F,0x80,0x0C,0xC0,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x0C,0x01,0x9E,0x1F,0x0E,0x1B,0x80,0x0C,0xC0,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x0C,0x03,0x00,0x03,0x0E,0x31,0x00,0x0C,0x7F,0xF0,0x7F,0xE0,0x00,0x00,0x00,0x00,0x0C,0x06,0x00,0x03,0x1C,0x30,0x9F,0x0C,0x00,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x07,0x86,0x00,0x03,0x38,0x30,0xC0,0x0C,0x00,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x01,0x86,0x1E,0x1F,0x30,0x18,0xC0,0x0C,0x01,0xF0,0x60,0x00,0x00,0x00,0x00,0x00,0x07,0x86,0x00,0x01,0xB0,0x0F,0x80,0x0C,0x03,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x0C,0x06,0x00,0x01,0x98,0x07,0x1F,0x0C,0x03,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x0C,0x06,0x00,0x01,0x8C,0x06,0x00,0x0C,0x03,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x0C,0x06,0x00,0x03,0x07,0x06,0x00,0x0C,0x03,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x0C,0x06,0x0F,0xFF,0x03,0x06,0x00,0x0C,0x03,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x0C,0x0F,0x18,0x00,0x03,0x07,0x00,0x18,0x03,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x07,0xF9,0xF0,0x00,0x01,0xFD,0xFF,0xF0,0x01,0xFF,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFD,0xFE,0x18,0x7F,0x3F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x8D,0xB6,0x18,0x31,0xB6,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x8C,0x30,0x1C,0x31,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x30,0x3C,0x31,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x30,0x3C,0x3F,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x30,0x36,0x36,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x30,0x3E,0x36,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x30,0x66,0x33,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x8C,0x30,0x63,0x33,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x8C,0x30,0x63,0x31,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xF8,0x78,0xF7,0xF9,0xCF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0

x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

20

5.7 游戏流程

游戏中,程序循环执行按键扫描程序,并做出相应判断。整个程序中,最关键的部分是要根据玩家的输入,控制小人、箱子的移动。

定义一个二维数组,用于保存当前游戏状态每个字符位的元素,当玩家按键输入时,改变该数组中相应得数据,再将此二维数组每个数据代码的元素显示出来,就可以出现小人,箱子移动的效果。

每关开始,进行游戏初始化。将关卡数据写入上述二维数组中,并记入小人的位置(man_x,man_y)。

程序只要根据小人移动方向周围的元素信息,结合游戏规则,只要判断能够移动箱子、小人的情况,才显示出来,而不用对不能移动的情况进行判定,这大大简化了程序的编写。

游戏流程框图如下(以向上移动为例,其他方向类似):

图32 流程框图1

21

·

图33 流程框图2

22

图34 流程框图3

小人、箱子移动示意图(按列看,不同的列对应上述流程的不同情况):

图35 移动示意图

23

5.8完成本关

每进行一次移动后就进行是否过关的判定。将记录本关每个字符位状态的数组与存储本关原始信息的数组的对应数据进行比较,若发现目的地上没有箱子,则不算过关,程序退出,进入等待按键输入程序,若所有的目的地都有箱子,则游戏过关,初始化下一关游戏,显示下一关游戏界面。 /************************************************

函数名:level_suc()

功能:判断是否通过本关卡 入口参数: 返回值:

*************************************************/ void level_suc() {

unsigned char i,j,k=1;

for(i = 0; i < 8; i++) //行 {

if(k==0) break;

for(j = 0; j < 8; j++) //列 {

if(level[levelg][i][j]==4||level[levelg][i][j]==5)//循环扫描目标位置都有箱子在,此关卡就通过 {

if(level_temp[i][j]==5)

k=1; //此位置箱子在目标位置上 else {

k=0; //有目标位置没有箱子 break; } } } }

if(k==1) //所有目标位置都有箱子 {

if(levelg<8) levelg+=1; else

levelg=0; //通关后重新从第一关开始 Timtcount=0; //计时清零 TH0=(65536-50000)/256; TL0=(65536-50000)%256;

24

tcount=0;

gamebg(levelg); } }

5.9 选关

按相应的选关键,会改变记录游戏关卡的变量levelg,对游戏重新初始化,即可记录所选关卡。相关程序如下:

case 5:

if(levelg!=8) levelg++;

gamebg(levelg); //显示第一关 Timtcount=0;

TH0=(65536-50000)/256; TL0=(65536-50000)%256; tcount=0;

break; //下一关 case 6: if(levelg!=0)

levelg--;

gamebg(levelg); //显示第一关 Timtcount=0;

TH0=(65536-50000)/256; TL0=(65536-50000)%256; tcount=0;

break; //上一关

5.10 计时

利用右半瓶的8×8字节的空间,显示当前游戏计时和当前关卡。界面设计如下:

图36 计时界面

25

其中汉字站4个字符,数字占两个字符。点阵码也是用字模软件提取的,显示方式与游戏元素的显示方式相同。显示效果如图所示:

图37 计时界面显示效果

使用定时器0的计时功能,每到1秒,触发中断程序,计时变量Timtcount就加1,在对其进行数字分解,将各位在响应的位置上显示出来。

void t0_tt() interrupt 1 {

TH0=(65536-50000)/256; TL0=(65536-50000)%256; tcount++;

if(tcount==20) {

tcount=0; Timtcount++;

time_change(Timtcount); } }

void time_change(unsigned int ttime) {

unsigned char a1,a2,a3,a4,a5; unsigned char i,j; a1=ttime/10000; a2=ttime/1000%10; a3=ttime/100%10; a4=ttime/10%10; a5=ttime%10;

26

for(j=0;j<16;j++) {

for(i=0;i<1;i++) {

setc_xy(9+i,32+j);

write_cmd2(shuzi[a1][j],inc_wr); } }

for(j=0;j<16;j++) {

for(i=0;i<1;i++) {

setc_xy(10+i,32+j);

write_cmd2(shuzi[a2][j],inc_wr); } }

for(j=0;j<16;j++) {

for(i=0;i<1;i++) {

setc_xy(11+i,32+j);

write_cmd2(shuzi[a3][j],inc_wr); } }

for(j=0;j<16;j++) {

for(i=0;i<1;i++) {

setc_xy(12+i,32+j);

write_cmd2(shuzi[a4][j],inc_wr); } }

for(j=0;j<16;j++) {

for(i=0;i<1;i++) {

setc_xy(13+i,32+j);

write_cmd2(shuzi[a5][j],inc_wr);

} }

}

27

//a1

//a2

//a3

//

//a4

//

//a5

6、调试总结

下面列些了在进行proteus仿真过程中出现几个问题,通过解决这些问题是我提高了调试能力。

1.忘记将C文件调添加进工程中,导致定义的函数不能被调用;

2.由按键扫描,获取按键编号,再通过按键编号执行相关操作。记录按键编号的变量要及时复位,否则在没有按键按下时,程序出现误操作;

3.图形液晶显示器的最大特性是要先定位,在写数据,而且是按1字节写入的,所以行是按位寻址,列是按字节寻址,即行有行,列有8列。显示时常常没有注意到这个,导致定位不准确,没有出现应有的图形;

4.调试时常常出现MULTIPLE PUBLIC DEFINITIONS的错误而能编译。经过多方查找,解决了这个问题,并个深刻的明白.h文件和.c文件的关系和作用,感受到结构化编程对大型程序的编写和调试带来方便;

对于比较小的程序,一般只有一个c文件和一个头文件,全局变量我们通常会直接定义在c文件中。在程序之前加int i定义。如果要在头文件中定义有以下两种方法:用extern来声明:extern int i;这一句只是对变量i进行声明,在c文件的程序之前必须加上int i进行定义。extern int i=0;这一句声明和定义都做了。

对于大一点的程序,有很多c文件和头文件,这个时候全局变量就必须在头文件中声明(不需要初始化),然后在一个c文件中定义(该初始化的要初始化)。如果在头文件中定义,则编译的时候会出现重复定义的错误。如果只有头文件中声明就会出现没有定义有警告。

.c文件主要是具体定义函数、定义全局变量的。.h文件主要是申明外部函数,变量的。 7 设计心得体会

参考文献

[1] 陈海宴. 51单片机原理及应用--基于Keil C与Proteus. 北京航空航天大学出版,2010-07-01,第1版.

28

[2] 彭伟. 单片机C语言程序设计实训100例——基于8051+PROTEUS仿真. 电子工业出版社,2009-06-01 .

[3] 浦滨. C游戏编程从入门到精通. 北京希望电子出版社,2002-5-1

[4] 李宏 张家田,等. 液晶显示器件应用技术 机械工业出版社, 2004-7-1 [5] ATc52数据手册

附录9 程序代码

---------------------main.c-----------------------------------------

#include

#include\"LCD128.h\" #include\"key.h\" #include\"boxgames.h\" #include\"timecount.h\"

void main() {

unsigned char kupdate; unsigned char startflag;

int51_timec(); //初始化51 init_128(); //初始化128 startflag=1; playing=0; start_ui();

while(1) { while(startflag) //等待确定键按下 { kupdate=16; if(P1!=0x0f) //若没有这句,有可能在按键扫描后执行while(P1!=0x0f),就得不到按键值,使按键失效 { kupdate=keys_scan(); while(P1!=0x0f); } switch(kupdate) { case 4: startflag=0; playing=1;

29

break; } } clc();//清屏 levelg=0; gamebg(levelg); //显示第一关 Timtcount=0; TR0=1; while(playing) //游戏中... { put_box(); } startflag=1; } }

---------key.c---------------------- #include

/******************************** 函数名:delayms(x) 功能:按键扫描延时 入口参数:x=延迟时间 返回值:

*********************************/ void delayms(unsigned int x) {

unsigned char i; while(x--);

for(i=0;i<100;i++); }

/******************************** 函数名:keys_scan() 功能:按键扫描 入口参数:

返回值:按键号keyno

*********************************/ unsigned char keys_scan() {

unsigned char tmp; unsigned char keyno; if(P1 != 0x0f)

30

{ P1 = 0x0f; delayms(1); tmp = P1 ^ 0x0f; switch(tmp) { case 1: keyno = 0;break; case 2: keyno = 1;break; case 4: keyno = 2;break; case 8: keyno = 3;break; default:keyno = 16; } P1 = 0xf0; delayms(1); tmp = (P1 >> 4)^ 0x0f; switch(tmp) { case 1:keyno += 0;break; case 2:keyno += 4;break; case 4:keyno += 8;break; case 8:keyno += 12;break; } P1=0x0f; return keyno; } }

------------------key.h---------------------------------- /******************************** 函数名:delayms(x) 功能:按键扫描延时 入口参数:x=延迟时间 返回值:

*********************************/ extern unsigned char keys_scan();

/******************************** 函数名:keys_scan() 功能:按键扫描 入口参数:

返回值:按键号keyno

*********************************/ extern void delayms(unsigned int x);

----------------------------T6963c_lcd128.c----------------------------------------

31

/************************************ 功能:1、lcd128显示的相关函数 2、游戏操作函数

*************************************/

#include\"T6963C_LCD128.h\" #include\"CGRAM.h\" #include\"key.h\"

/************************************************** 函数名:status_bit_01()

功能:状态位sta1(读/写指令),sta0(读/写数据)判断 入口参数:

返回值:状态值i

***************************************************/ unsigned char status_bit_01() {

unsigned char i; P0=0xff; cd=1; rd=0;

for(i=10;i>0;i--) { if((P1&0x03)==0x03) break; } rd=1;

return i; }

/********************************************* 函数名:write_data(unsigned char dat) 功能:写数据

入口参数:8位数据dat 返回值:

*********************************************/ void write_data(unsigned char dat) {

while(status_bit_01()==0); rd=1;cd=0;wr=0; P0=dat;

wr=1;cd=1; //一定要有这一句,补完后面的时序! }

32

/********************************************* 函数名:write_cmd1(unsigned char cmd) 功能:写命令,无参数 入口参数:8位命令cmd 返回值:

*********************************************/ void write_cmd1(unsigned char cmd) {

while(status_bit_01()==0); rd=1;cd=1;wr=0; P0=cmd;

wr=1;cd=0; //一定要有这一句,补完后面的时序! }

/********************************************* 函数名:write_cmd2(unsigned char cmd) 功能:写单参数命令

入口参数:8位数据dat,8位命令cmd 返回值:

*********************************************/ void write_cmd2(unsigned char dat,unsigned char cmd) {

write_data(dat); write_cmd1(cmd); }

/************************************************ 函数名:write_cmd2(unsigned char cmd) 功能:写双参数命令

入口参数:8位数据data1,8位数据data2,8位命令cmd 返回值:

*************************************************/

void write_cmd3(unsigned char data1,unsigned char data2,unsigned char cmd) {

write_data(data1); write_data(data2); write_cmd1(cmd); }

/************************************************ 函数名:init_128() 功能:初始化lcd128 入口参数: 返回值:

*************************************************/

33

void init_128() {

wr=1;rd=1;cd=1;rst=1;//初始化

write_cmd3(0x01,0x00,0x21);//光标指针设置 write_cmd3(0x00,0x00,0x42);//图形区首地址 write_cmd3(16,0x00,0x43);//图形区宽度 write_cmd1(0x88);//显示方式设置,正常显示

write_cmd1(0x98);//图形方式显示,不显示字母,只打点 write_cmd1(0xa0);//光标形状设置1 0 1 0 0 N2 N1 N0 }

/************************************************ 函数名:clc() 功能:清屏 入口参数: 返回值:

*************************************************/ void clc() { int i;

write_cmd3(0,0,add_pos); for(i = 0; i < 1024; i++) write_cmd2(0x00,inc_wr); }

-----------------lcd128.h------------------------------------------ extern unsigned char status_bit_01(); //状态位sta1(读/写指令),sta0(读/写数据)判断 extern void write_data(unsigned char dat); /写数据 extern void write_cmd1(unsigned char cmd); //写无参数命令 extern void write_cmd2(unsigned char dat,unsigned char cmd); //写单参数命令 extern void write_cmd3(unsigned char data1,unsigned char data2,unsigned char cmd); //写双参数命令 extern void init_128(); //初始化lcd128

extern void clc();

--------------------------T6963c_lcd128.h---------------------------------------------------------------------- /************************************ 功能:1、T6963c命令宏定义 2、lcd128引脚位定义

*************************************/ #include

34

//**********lcd128引脚位定义*********************// sbit wr =P2^0; sbit rd =P2^1; sbit cd =P2^2; sbit rst=P2^3;

//**********T6963c命令宏定义*********************// //地址指针设置

#define cur_pos 0x21 //光标位置设置

#define CGR_pos 0x22 //CGRAM偏置地址设置 #define add_pos 0x24 //地址指针位置

//显示区域设置

#define txt_stp 0x40 //文本区首地址 #define txt_wid 0x41 //文本区宽度 #define grh_stp 0x42 //图形区首地址 #define grh_wid 0x43 //图形区宽度

//显示方式设置

#define mod_or 0x80 //显示方式:逻辑或 #define mod_xor 0x81 //显示方式:逻辑异或 #define mod_and 0x82 //显示方式:逻辑与 #define mod_tch 0x83 //显示方式:文本特征

//显示状态设置

#define dis_sw 0x90 //显示开关

//D0=1/0:光标闪烁启用/禁用 //D1=1/0:光标显示启用/禁用 //D2=1/0:文本显示启用/禁用 //D3=1/0:图形显示启用/禁用

//光标形状设置

#define cur_shp 0xa0 //光标形状选择:0xa0~0xa7光标占的行数:1行~8行

//数据自动读写设置 //数据一次读写设置

#define inc_wr 0xc0 //数据写,地址+1 #define inc_rd 0xc1 //数据读,地址+1 #define dec_wr 0xc2 //数据写,地址-1 #define dec_rd 0xc3 //数据读,地址-1 #define noc_wr 0xc4 //数据写,地址不变 #define noc_rd 0xc5 //数据读,地址不变

------------------lcd128.c--------------------------------------------------------------- #include

35

#include\"LCD128.h\" #include\"CGRAM.h\" #include\"key.h\"

#include\"T6963C_LCD128.h\" #include\"timecount.h\"

unsigned char man_x,man_y; //纪录当前小人所在位置 unsigned char levelg; //记录当前关卡 unsigned char playing,startflag;

/************************************************ 函数名:setc_xy() 功能:定位

入口参数:列字符地址x,行位地址y 返回值:

*************************************************/ void setc_xy(unsigned char x, unsigned char y) {

int temp;

temp = y * 0x10 + x;

write_cmd3(temp&0xff,temp/0xff,add_pos); }

/************************************************ 函数名:printelement()

功能:指定字符位置,显示元素

入口参数:列字符地址xh,行字符地址yh,元素代码elnum 返回值:

*************************************************/

void printelement(unsigned char xh, unsigned char yh,unsigned char elnum) {

unsigned char i; int temp;

for(i=0;i<8;i++) //行地址加+1 { temp = yh* 0x80+i*0x10 + xh; write_cmd3(temp&0xff,temp/0xff,add_pos); write_cmd2(elements[elnum][i],noc_wr); } }

/************************************************ 函数名:set_xy()

功能:定位字符位置

入口参数:列字符地址x,行字符地址y 返回值:

36

*************************************************/ void set_xy(unsigned char x, unsigned char y) {

int temp;

temp = y * 0x80 + x;

write_cmd3(temp&0xff,temp/0xff,add_pos); }

/************************************************ 函数名:start_ui() 功能:开机画面 入口参数: 返回值:

*************************************************/ void start_ui() {

unsigned int i; setc_xy(0,0);

for(i=0;i<1024;i++) { write_cmd2(start_box[i],inc_wr); } }

void display_time() {

unsigned i,j; for(j=0;j<16;j++) //第 { for(i=0;i<2;i++) { setc_xy(9+i,j); write_cmd2(zhong_di[j*2+i],inc_wr); //数组的地址不要乱! } } fo { for(i=0;i<2;i++) { setc_xy(12+i,j); write_cmd2(zhong_guan[j*2+i],inc_wr); //关 } }

37

for(j=0;j<16;j++) { for(i=0;i<2;i++) 是按位寻址的 { setc_xy(9+i,16+j); write_cmd2(zhong_yong[j*2+i],inc_wr); } }

for(j=0;j<16;j++) { for(i=0;i<2;i++) { setc_xy(12+i,16+j); write_cmd2(zhong_shi[j*2+i],inc_wr); } }

for(j=0;j<16;j++) { for(i=0;i<2;i++) { setc_xy(14+i,32+j); write_cmd2(zhong_miao[j*2+i],inc_wr); //setc_xy(13+i,32+j); } } }

/*********************************

功能:分解计时值的各位,并显示在响应的位置上 函数名: time_change(unsigned int ttime) 入口参数:计时值 返回值:

***********************************/

void time_change(unsigned int ttime) a5=ttime%10;

for(j=0;j<16;j++) { for(i=0;i<1;i++)

38

//列式按字符寻址的,行

//用

//时

//时

//a1

{ setc_xy(9+i,32+j); write_cmd2(shuzi[a1][j],inc_wr); } }

for(j=0;j<16;j++) //a2 { for(i=0;i<1;i++) { setc_xy(10+i,32+j); write_cmd2(shuzi[a2][j],inc_wr); } }

for(j=0;j<16;j++) //a3 { for(i=0;i<1;i++) { setc_xy(11+i,32+j); write_cmd2(shuzi[a3][j],inc_wr); // } }

for(j=0;j<16;j++) //a4 { for(i=0;i<1;i++) { setc_xy(12+i,32+j); write_cmd2(shuzi[a4][j],inc_wr); // } } } }

/************************************************ 函数名:gamebg()

功能:显示游戏本关卡游戏界面 入口参数:关卡代号g 返回值:

*************************************************/ void gamebg(unsigned char g) {

unsigned i,j;

for(i=0;i<8;i++) //行

39

{ for(j=0;j<8;j++) //列 { if(level[g][i][j]==1) { man_x=j; man_y=i; } level_temp[i][j]=level[g][i][j]; //当前关卡存入游戏缓冲 printelement(j,i,level_temp[i][j]); //显示当前关卡 } }

display_time();

time_change(Timtcount); }

/************************************************ 函数名:level_suc()

功能:判断是否通过本关卡 入口参数: 返回值:

*************************************************/ void level_suc() {

unsigned char i,j,k=1; for(i = 0; i < 8; i++) //行 { if(k==0) break; for(j = 0; j < 8; j++) //列 { if(level[levelg][i][j]==4||level[levelg][i][j]==5) //循环扫描目标位置都有箱子在,此关卡就通过 { if(level_temp[i][j]==5) k=1; //此位置箱子在目标位置上 else { k=0; //有目标位置没有箱子 break; } } } }

40

if(k==1) //所有目标位置都有箱子 { if(levelg<8) levelg+=1; else levelg=0; //通关后重新从第一关开始 Timtcount=0; //计时清零 TH0=(65536-50000)/256; TL0=(65536-50000)%256; tcount=0; gamebg(levelg); } }

/************************************************ 函数名:key_up()

功能:按向上键的操作 入口参数: 返回值: 注释含义:

?=:是否等与 上:本位置的上一个位置 目: 箱子的目标位置 成:箱子在目标位置上 位置 箱:箱子

*************************************************/ void key_up() {

if(level_temp[man_y-1][man_x]==0||level_temp[man_y-1][man_x]==4) { if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5) 成 { level_temp[man_y][man_x]=4; =目 printelement(man_x,man_y,4); } else { level_temp[man_y][man_x]=0; =空 printelement(man_x,man_y,0); }

41

//上?=目/成 //本,源?=目/ //本 //本 man_y=man_y-1; //上=人//完成一次移动 level_temp[man_y][man_x]=1; printelement(man_x,man_y,1); }

else if(level_temp[man_y-1][man_x]==3) //上?=箱 { if(level_temp[man_y-2][man_x]==0) //再上?=空白 { if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5) 成 { level_temp[man_y][man_x]=4; =目 printelement(man_x,man_y,4); } else { level_temp[man_y][man_x]=0; printelement(man_x,man_y,0); } man_y=man_y-1; =人 level_temp[man_y][man_x]=1; printelement(man_x,man_y,1); level_temp[man_y-1][man_x]=3; 箱//完成一次移动 printelement(man_x,man_y-1,3); } else if(level_temp[man_y-2][man_x]==4) =目 { if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5) /成 { level_temp[man_y][man_x]=4; =目 printelement(man_x,man_y,4); } else { level_temp[man_y][man_x]=0;

42

//本,源?=目/ //本 //本=空 //上 //再上= //再上?//本,源?=目 //本 //本=空 printelement(man_x,man_y,0); } man_y=man_y-1; level_temp[man_y][man_x]=1; =人 printelement(man_x,man_y,1); level_temp[man_y-1][man_x]=5; 成 printelement(man_x,man_y-1,5); } }

else if(level_temp[man_y-1][man_x]==5) 成 { if(level_temp[man_y-2][man_x]==0) 上?=空 { if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5) 目/成 { level_temp[man_y][man_x]=4; 本=目 printelement(man_x,man_y,4); } else { 本=空 level_temp[man_y][man_x]=0; printelement(man_x,man_y,0); } man_y=man_y-1; 上=人 level_temp[man_y][man_x]=1; printelement(man_x,man_y,1); level_temp[man_y-1][man_x]=3; 箱 printelement(man_x,man_y-1,3); } else if(level_temp[man_y-2][man_x]==4) 上?=目 { if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5) 目/成 {

43

//上 //再上= //上?= //再 //本,源?= // // // //再上= //再 //本,源?= level_temp[man_y][man_x]=4; 本=目 printelement(man_x,man_y,4); } else { level_temp[man_y][man_x]=0; printelement(man_x,man_y,0); } man_y=man_y-1; 上=人 level_temp[man_y][man_x]=1; printelement(man_x,man_y,1); level_temp[man_y-1][man_x]=5; 成 printelement(man_x,man_y-1,5); } }

level_suc(); 是否完成本关 }

/************************************************ 函数名:key_down() 功能:按向下键的操作 入口参数: 返回值:

*************************************************/ void key_down() {

if(level_temp[man_y+1][man_x]==0||level_temp[man_y+1][man_x]==4) { if an_y,4); } else { level_temp[man_y][man_x]=0; printelement(man_x,man_y,0); } man_y=man_y+1; level_temp[man_y][man_x]=1; printelement(man_x,man_y,1); }

44

// //本=空 // //再上= //判断 else if(level_temp[man_y+1][man_x]==3) { if(level_temp[man_y+2][man_x]==0) { if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5) { 0); } man_y=man_y+1; level_temp[man_y][man_x]=1; printelement(man_x,man_y,1); level_temp[man_y+1][man_x]=3; printelement(man_x,man_y+1,3); } else if(level_temp[man_y+2][man_x]==4) { if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5) { level_temp[man_y][man_x]=4; printelement(man_x,man_y,4); } else { level_temp[man_y][man_x]=0; printelement(man_x,man_y,0); } m }

else if(level_temp[man_y+1][man_x]==5) { if(level_temp[man_y+2][man_x]==0) { if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5) { level_temp[man_y][man_x]=4; printelement(man_x,man_y,4); } else { level_temp[man_y][man_x]=0; printelement(man_x,man_y,0); } man_y=man_y+1;

45

level_temp[man_y][man_x]=1; printelement(man_x,man_y,1); level_temp[man_y+1][man_x]=3; printelement(man_x,man_y+1,3); } else if(level_temp[man_y+2][man_x]==4) { if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5) { level_temp[man_y][man_x]=4; printelement(man_x,man_y,4); } else { level_temp[man_y][man_x]=0; printelement(man_x,man_y,0); }

level_suc(); }

/************************************************ 函数名:key_left()

功能:按向左键的操作 入口参数: 返回值:

*************************************************/ void key_left() {

if(level_temp[man_y][man_x-1]==0||level_temp[man_y][man_x-1]==4) { if(leve ,man_y,4); } else { level_temp[man_y][man_x]=0; printelement(man_x,man_y,0); } man_x=man_x-1; level_temp[man_y][man_x]=1; printelement(man_x,man_y,1); }

46

else if(level_temp[man_y][man_x-1]==3) { if(level_temp[man_y][man_x-2]==0) { if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5) { level_temp[man_y][man_x]=4; printelement(man_x,man_y,4); } else { level_temp[man_y][man_x]=0; printelement(man_x,man_y,0); } man_x else if(level_temp[man_y][man_x-2]==4) { if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5) { level_temp[man_y][man_x]=4; printelement(man_x,man_y,4); } else { level_temp[man_y][man_x]=0; x-1]=5; printelement(man_x-1,man_y,5); } }

else if(level_temp[man_y][man_x-1]==5) { if(level_temp[man_y][man_x-2]==0) { if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5) { level_temp[man_y][man_x]=4; printelement(man_x,man_y,4); } else { level_temp[man_y][man_x]=0; printelement(man_x,man_y,0); }

47

man_x=man_x-1; level_temp[man_y][man_x]=1; printelement(man_x,man_y,1); level_temp[man_y][man_x-1]=3; ); } else { level_temp[man_y][man_x]=0; printelement(man_x,man_y,0); } man_x=man_x-1;

} level_suc(); }

/************************************************ 函数名:key_right()

功能:按向右键的操作 入口参数: 返回值:

*************************************************/ void key_right() {

if(level_temp[man_y][man_x+1]==0||level_temp[man_y][man_x+1]==4) { if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5) { level_temp[man_y][man_x]=4; printelement(man_x,man_y,4); } else { level_temp[man_y][man_x]=0; printelement(man_x,man_y,0); } man_x=man_x+1; if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5) { level_temp[man_y][man_x]=4; printelement(man_x,man_y,4);

48

} else { level_temp[man_y][man_x]=0; printelement(man_x,man_y,0); } man_x=man_x+1; level_temp[man_y][man_x]=1; level_temp[man_y][man_x]=4; printelement(man_x,man_y,4); } else { level_temp[man_y][man_x]=0; printelement(man_x,man_y,0); } man_x=man_x+1; level_temp[man_y][man_x]=1; printelement(man_x,man_y,1); level_temp[man_y][man_x+1]=5; printelement(man_x+1,man_y,5); } }

else if(level_temp[man_y][man_x+1]==5) { if(level_temp[man_y][man_x+2]==0) else { level_temp[man_y][man_x]=0; printelement(man_x,man_y,0); } man_x=man_x+1; level_temp[man_y][man_x]=1; printelement(man_x,man_y,1); level_temp[man_y][man_x+1]=3; printelement(man_x+1,man_y,3); } else if(level_temp[man_y][man_x+2]==4) { if(level[levelg][man_y][man_x]==4||level[levelg][man_y][man_x]==5) { man_x=man_x+1;

49

level_temp[man_y][man_x]=1; printelement(man_x,man_y,1); level_temp[man_y][man_x+1]=5; printelement(man_x+1,man_y,5); } } level_suc(); }

/************************************************ 函数名:void put_box() 功能:推箱子游戏规则 入口参数: 返回值:

*************************************************/ void put_box() {

unsigned int keyupdate; keyupdate=16; if(P1!=0x0f) //若没有这句,有可能在按键扫描后执行while(P1!=0x0f),就得不到按键值,使按键失效 { keyupdate=keys_scan(); while(P1!=0x0f); }

switch(keyupdate) { case 0: key_up();break; case 1:key_down();break; case 2:key_left();break; case 3:key_right();break; case 4: playing=0; startflag=1; Timtcount=0; TR0=0; clc(); start_ui(); break; //退出游戏 } }

50

------------------------------timecount.c-------------------------------------------------------- #include\"boxgames.h\" #include\"reg51.h\"

unsigned int Timtcount; unsigned char tcount;

void int51_timec() {

EA=1;

TMOD=0x11; ET0=1; TR0=0;

TH0=(65536-50000)/256; TL0=(65536-50000)%256; }

void t0_tt() interrupt 1 {

TH0=(65536-50000)/256; TL0=(65536-50000)%256; tcount++; if(tcount==20) { tcount=0; Timtcount++; time_change(Timtcount); } }

---------------------timecount.h--------------------------------------------- extern unsigned int Timtcount; extern unsigned char tcount; extern void int51_timec(); extern void t0_tt();

--------------CGRAM.c---------------------------------------------------------- unsigned char code elements[][8]= {

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //0空白 0x3C,0x7E,0x66,0x3C,0x7E,0x99,0x3C,0x66, //1人物 0x7F,0x7F,0x7F,0x00,0xEF,0xEF,0xEF,0x00, //2砖头 0xFF,0xC3,0xA5,0x99,0x99,0xA5,0xC3,0xFF, //3箱子 0x00,0x18,0x24,0x4A,0x52,0x24,0x18,0x00, //4目标

51

0xFF,0xBD,0xDB,0xE7,0xE7,0xDB,0xBD,0xFF, //5箱子到达目标

// 0x24,0x7E,0x66,0x3C,0x7E,0x99,0xBD,0x24 //人物样式2 };

/********************************************* 游戏关卡 一共9关

数字符号表示:人物1 砖头2 箱子3 目的4 成功5 **********************************************/ unsigned char code level[][8][8]={ /*第0关*/ 0,0,2,2,2,2,2,0, 2,2,2,0,0,0,2,0, 2,0,3,0,2,0,2,2, 2,0,2,0,0,4,0,2, 2,0,0,0,0,2,0,2, 2,2,0,2,0,0,0,2, 0,2,1,0,0,2,2,2, 0,2,2,2,2,2,0,0,

/*第1关*/ 2,2,2,2,2,2,2,2, 2,0,0,0,0,0,1,2, 2,0,0,0,5,0,0,2, 2,0,0,2,2,2,2,2, 2,2,0,0,2,0,0,0, 2,0,3,0,2,0,0,0, 2,0,0,4,2,0,0,0, 2,2,2,2,2,0,0,0,

/*第2关*/ 0,0,2,2,2,2,0,0, 0,0,2,4,4,2,0,0, 0,2,2,0,4,2,2,0, 0,2,0,0,3,4,2,0, 2,2,0,3,0,0,2,2, 2,0,0,2,3,3,0,2, 2,0,0,1,0,0,0,2, 2,2,2,2,2,2,2,2,

/*第3关*/ 0,0,0,2,2,2,2,0, 0,2,2,2,0,1,2,0,

52

0,2,0,0,3,0,2,0, 2,2,0,2,0,2,2,2, 2,0,0,2,0,2,4,2, 2,0,2,0,0,3,4,2, 2,0,0,0,0,0,0,2, 2,2,2,2,2,2,2,2, /*第4关*/ 0,0,0,2,2,2,2,0, 0,2,2,2,0,1,2,0, 0,2,0,0,3,0,2,0, 2,2,0,2,0,2,2,2, 2,0,0,2,0,2,4,2, 2,0,2,0,0,0,0,2, 2,0,0,0,0,0,0,2, 2,2,2,2,2,2,2,2, /*第5关*/ 0,0,0,2,2,2,2,0, 0,2,2,2,0,1,2,0, 0,2,0,0,3,0,2,0, 2,2,0,2,0,2,2,2, 2,0,0,2,0,2,4,2, 2,0,2,0,0,3,4,2, 2,0,3,0,0,0,4,2, 2,2,2,2,2,2,2,2,

/*第6关*/ 0,0,2,2,2,2,2,0, 2,2,2,0,0,0,2,0, 2,0,3,0,2,0,2,2, 2,0,2,0,0,4,0,2, 2,0,0,0,0,2,0,2, 2,2,3,2,4,0,0,2, 0,2,1,0,0,2,2,2, 0,2,2,2,2,2,0,0,

/*第7关*/ 0,2,2,2,2,0,0,0, 2,2,0,0,2,0,0,0, 2,1,3,0,2,0,0,0, 2,2,3,0,2,2,0,0, 2,2,0,3,0,2,0,0,

2,4,3,0,0,2,0,0,

53

2,4,4,5,4,2,0,0, 2,2,2,2,2,2,0,0,

/*第8关*/ 0,0,0,2,2,2,2,0, 0,2,2,2,0,0,2,0, 2,2,0,1,3,0,2,0, 2,0,4,3,0,0,2,0, 2,0,4,5,0,2,2,0, 2,0,4,3,0,2,0,0, 2,2,0,0,2,2,0,0, 0,2,2,2,2,0,0,0, };

//开机画面

unsigned char code start_box[]= {

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xE0,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFC,0x7C,0xC0,0x06,0x30,0xC6,0x00,0x1F,0xFF,0xFF,0x00,0x00,0x00, 0x00,0x00,0x01,0x86,0xC7,0xF0,0x06,0x1F,0xC7,0xF8,0x30,0x00,0x01,0xC0,0x00,0x00, 0x00,0x00,0x01,0x87,0x86,0x18,0x0C,0x01,0x80,0x0C,0x30,0x00,0x00,0xC0,0x00,0x00, 0x00,0x00,0x01,0x87,0x82,0x18,0x1C,0x01,0x80,0x0E,0x30,0x00,0x00,0x40,0x00,0x00, 0x00,0x00,0x01,0x87,0x06,0x0C,0x18,0x01,0x00,0x06,0x30,0x00,0x00,0x40,0x00,0x00, 0x00,0x00,0x0F,0x87,0x07,0x0F,0x10,0x03,0x00,0x0C,0x30,0x00,0x00,0xC0,0x00,0x00, 0x00,0x00,0x0C,0x06,0x00,0x01,0x90,0x43,0x00,0x0C,0x1F,0xFF,0x01,0x80,0x00,0x00, 0x00,0x00,0x0C,0x06,0x00,0x01,0x98,0xC3,0x08,0x38,0x00,0x3E,0x03,0x00,0x00,0x00, 0x00,0x00,0x0C,0x0C,0x00,0x01,0x8F,0xC3,0x1C,0x38,0x00,0x3C,0x06,0x00,0x00,0x00, 0x00,0x00,0x0C,0x0C,0x00,0x03,0x1F,0xC7,0xFC,0x7C,0x7F,0xF6,0x0F,0xE0,0x00,0x00, 0x00,0x00,0x0F,0x88,0x1E,0x1F,0x1C,0x7F,0x67,0xDC,0xC0,0x03,0x18,0x30,0x00,0x00, 0x00,0x00,0x01,0x8C,0x00,0x03,0x18,0x01,0x80,0x0C,0xC0,0x01,0xF0,0x30,0x00,0x00, 0x00,0x00,0x03,0x87,0x80,0x03,0x10,0x00,0x80,0x0C,0xC0,0x00,0x00,0x30,0x00,0x00, 0x00,0x00,0x0E,0x01,0x80,0x03,0x10,0x00,0x9F,0x0C,0xC0,0x00,0x00,0x30,0x00,0x00,

54

0x00,0x00,0x0C,0x01,0x80,0x03,0x18,0x0F,0x80,0x0C,0xC0,0x00,0x00,0x30,0x00,0x00, 0x00,0x00,0x0C,0x01,0x9E,0x1F,0x0E,0x1B,0x80,0x0C,0xC0,0x00,0x00,0x30,0x00,0x00, 0x00,0x00,0x0C,0x03,0x00,0x03,0x0E,0x31,0x00,0x0C,0x7F,0xF0,0x7F,0xE0,0x00,0x00, 0x00,0x00,0x0C,0x06,0x00,0x03,0x1C,0x30,0x9F,0x0C,0x00,0x30,0x60,0x00,0x00,0x00, 0x00,0x00,0x07,0x86,0x00,0x03,0x38,0x30,0xC0,0x0C,0x00,0x30,0x60,0x00,0x00,0x00, 0x00,0x00,0x01,0x86,0x1E,0x1F,0x30,0x18,0xC0,0x0C,0x01,0xF0,0x60,0x00,0x00,0x00, 0x00,0x00,0x07,0x86,0x00,0x01,0xB0,0x0F,0x80,0x0C,0x03,0x00,0x60,0x00,0x00,0x00, 0x00,0x00,0x0C,0x06,0x00,0x01,0x98,0x07,0x1F,0x0C,0x03,0x00,0x60,0x00,0x00,0x00, 0x00,0x00,0x0C,0x06,0x00,0x01,0x8C,0x06,0x00,0x0C,0x03,0x00,0x60,0x00,0x00,0x00, 0x00,0x00,0x0C,0x06,0x00,0x03,0x07,0x06,0x00,0x0C,0x03,0x00,0x60,0x00,0x00,0x00, 0x00,0x00,0x0C,0x06,0x0F,0xFF,0x03,0x06,0x00,0x0C,0x03,0x00,0x60,0x00,0x00,0x00, 0x00,0x00,0x0C,0x0F,0x18,0x00,0x03,0x07,0x00,0x18,0x03,0x00,0xC0,0x00,0x00,0x00, 0x00,0x00,0x07,0xF9,0xF0,0x00,0x01,0xFD,0xFF,0xF0,0x01,0xFF,0x80,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFD,0xFE,0x18,0x7F,0x3F,0xC0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x8D,0xB6,0x18,0x31,0xB6,0xC0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x8C,0x30,0x1C,0x31,0x86,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x30,0x3C,0x31,0x86,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x30,0x3C,0x3F,0x06,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x30,0x36,0x36,0x06,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x30,0x3E,0x36,0x06,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x30,0x66,0x33,0x06,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x8C,0x30,0x63,0x33,0x06,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x8C,0x30,0x63,0x31,0x86,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xF8,0x78,0xF7,0xF9,0xCF,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, };

unsigned char code zhong_di[]= 第 {

0x20,0x40,0x3F,0x7E,0x48,0x90,0x85,0x08,0x3F,0xF8,0x01,0x08,0x01,0x08,0x3F,0xF8,

55

//

0x21,0x00,0x21,0x00,0x3F,0xFC,0x03,0x04,0x05,0x04,0x19,0x28,0xE1,0x10,0x01,0x00, };

unsigned char code zhong_guan[]= 关 {

0x10,0x10,0x08,0x10,0x08,0x20,0x00,0x00,0x3F,0xF8,0x01,0x00,0x01,0x00,0x01,0x00, 0xFF,0xFE,0x01,0x00,0x02,0x80,0x02,0x80,0x04,0x40,0x08,0x20,0x30,0x18,0xC0,0x06, };

unsigned char code zhong_yong[]=

//用 {

0x00,0x00,0x3F,0xF8,0x21,0x08,0x21,0x08,0x21,0x08,0x3F,0xF8,0x21,0x08,0x21,0x08, 0x21,0x08,0x3F,0xF8,0x21,0x08,0x21,0x08,0x21,0x08,0x41,0x08,0x41,0x28,0x80,0x10, };

unsigned char code zhong_shi[]= //时 {

0x00,0x08,0x00,0x08,0x7C,0x08,0x44,0x08,0x45,0xFE,0x44,0x08,0x44,0x08,0x7C,0x08, 0x44,0x88,0x44,0x48,0x44,0x48,0x44,0x08,0x7C,0x08,0x44,0x08,0x00,0x28,0x00,0x10, };

unsigned char code zhong_miao[]=

//秒 {

0x08,0x20,0x1C,0x20,0xF0,0x20,0x10,0xA8,0x10,0xA4,0xFC,0xA2,0x11,0x22,0x31,0x20, 0x3A,0x24,0x54,0x24,0x54,0x28,0x90,0x08,0x10,0x10,0x10,0x20,0x10,0xC0,0x00,0x00, };

unsigned char code shuzi[][16]= {

0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00, 0x00,0x00,0x00,0x10,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00, 0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x04,0x04,0x08,0x10,0x20,0x42,0x7E,0x00,0x00, 0x00,0x00,0x00,0x3C,0x42,0x42,0x04,0x18,0x04,0x02,0x02,0x42,0x44,0x38,0x00,0x00, 0x00,0x00,0x00,0x04,0x0C,0x14,0x24,0x24,0x44,0x44,0x7E,0x04,0x04,0x1E,0x00,0x00, 0x00,0x00,0x00,0x7E,0x40,0x40,0x40,0x58,0x,0x02,0x02,0x42,0x44,0x38,0x00,0x00, 0x00,0x00,0x00,0x1C,0x24,0x40,0x40,0x58,0x,0x42,0x42,0x42,0x24,0x18,0x00,0x00, 0x00,0x00,0x00,0x7E,0x44,0x44,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00, 0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x42,0x3C,0x00,0x00, 0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x26,0x1A,0x02,0x02,0x24,0x38,0x00,0x00, };

56

//

//0 //1 //2 //3 //4 //5 //6 //7 //8 //9

-----------------------CGRAM.h------------------------------------------- #ifndef __CGRAM_H__ #define __CGRAM_H__

extern unsigned char code elements[][8]; extern unsigned char code level[][8][8]; extern unsigned char code start_box[]; extern unsigned char code zhong_di[]; extern unsigned char code zhong_guan[]; extern unsigned char code zhong_yong[]; extern unsigned char code zhong_shi[]; extern unsigned char code zhong_miao[]; extern unsigned char code shuzi[][16];

#endif

57

因篇幅问题不能全部显示,请点此查看更多更全内容