基于51单⽚机的贪吃蛇游戏设计
本科时候做的⼀个课程作业,⾃⼰搭⼀个很简易的电路,⽐较有意思且易上⼿,故将之记录下来。(全套的仿真及代码,演⽰视频,课程报告以及PPT展⽰上传在。)
⼀. 实验⽬的
(1)通过对C51语⾔的理解,编写程序实现对贪吃蛇的有效控制;
(2)通过对51单⽚机硬件的学习,学会运⽤⾯包板,独⽴按键、点阵屏等,完成对完整电路的搭建过程;
(3)通过对Proteus仿真软件的学习,实现基于STC89C52单⽚机的8*8点阵贪吃蛇的硬件电路仿真。
⼆. 实验介绍
贪吃蛇是⼀款经典⼩游戏,其游戏的规则是:玩家通过四个⽅向键来控制蛇的移动,控制其在地图上吃⾖⼦。吃掉⾖⼦后蛇⾝相应加长,蛇⾝速度加快。蛇运动过程中撞到墙壁或蛇⾝,则⽴即结束本轮游戏。
三. 实现功能
(1)制作⼀个8*8点阵的贪吃蛇游戏;
(2)通过LED点阵屏为载体显⽰数据;
(3)外接4个独⽴按键作为输⼊端,分别控制蛇的移动⽅向(上、下、左、右);
(4)蛇头与墙壁或蛇⾝相撞,随即结束游戏并复位。
四. ⽅案设计
在该系统中,硬件部分包括STC89C52单⽚机,8*8点阵屏,4个按键;软件部分是在keil环境下⽤C51语⾔编写,设置蛇的初始段数为2点,并设置有障碍墙壁,游戏结束后⾃动复位。
(1)贪吃蛇的移动
在贪吃蛇的移动过程中,每次需要将蛇头要到的下⼀个LED灯点亮,对应蛇尾的LED灯熄灭。在程序中即是先把蛇尾位置的值传给蛇头的下⼀个位置,然后改变蛇尾的值即可。蛇头下⼀个位置的确定由蛇头和偏移量来确定,每次通过操作四个独⽴按键来控制蛇步进的偏移量。因⽽只要将蛇头的位置加上其偏移量的值,即可得到新的蛇头位置。
(2)⾷物的出现
在市场上所流⾏的贪吃蛇游戏中,⾷物的出现是⼀种随机⾏为,这在程序中需要做⼀个随机数来⽀撑该过程。我们组在实验过程中也尝试了该过程,最终选择让⾷物出现在蛇尾的后⼀步,来执⾏整个程序。与此同时,⾷物出现的位置不能与蛇的位置重合,也不能超出墙外,否则需要重置⾷物。
五. 模块应⽤
(1)AT89C52单⽚机最⼩系统模块
本系统是以STC89C52RC为核⼼,加上复位电路和晶振电路来构成最⼩系统。该系统中选⽤11.0592M晶振,使得单⽚机有较为合理的运⾏速度;其起振电容对振荡器的频率⾼低、稳定性以及快速性影响较合适,复位电路为按键⾼电平复位。
(2)1588BS 8*8共阳点阵屏模块
本实验中是采⽤8*8共阳红⾊点阵显⽰屏,它共16个引脚,分别与单⽚机P1⼝的⼋位管脚、P2⼝的⼋位管脚,按照⼀定要求(连接规则来源于百度查询)通过杜邦线⼀⼀对应连接,继⽽⽤来显⽰贪吃蛇的游戏画⾯。
点阵屏各点的点亮原理:
贪吃蛇的编程代码
该点阵屏各引脚分别对应各led点(其原理图详见下图),其基本原理是:当第⼀⾏接⼊⾼电平,第⼀列接⼊低电平,且其它列为⾼电平时,则第⼀个led灯点亮。同理,其他所有的led灯点亮原理均是如此。
(3)独⽴按键模块
本实验中外接4个独⽴按键,分别通过控制单⽚机P3⼝的P3.1~P3.4,从⽽控制蛇的游⾛⽅向(上、下、左、右)。当按键未按下时,控制P3⼝为低电平;当其中某⼀按键按下后,电流会通过该按键,通过P3⼝中相对应的管脚进⼊单⽚机,使单⽚机变为⾼电平。当单⽚机检测到⾼电平的时候,会做出相应反应,继⽽实现贪吃蛇游戏。
六. 程序流程
本实验中主程序⼯作流程如下图5所⽰,系统上电后⾸先对LED进⾏初始化,接着对定时器初始化,并启动定时器,之后执⾏程序主题逻辑部分,程序主题逻辑执⾏⼀遍后检查是否有中断发⽣。本实验中有两个中断源:⼀个是驱动贪吃蛇⾃动前⾏的定时中断,另⼀个是⽤户控制贪吃蛇移动⽅向的按键中断。任意中断的到来都将改变贪吃蛇当前状态。若当前没有中断发⽣,主程序将继续判断蛇头是否碰壁或发⽣头尾相撞。若是,则结束游戏,否则返回继续执⾏程序主体循环即可。
七. 附录
7.1 Proteus电路仿真图
7.2 代码
1 #include <reg52.h>
2#define uchar unsigned char
3#define SNAKE 22 //最⼤长度
4#define TIME 40 //显⽰延时时间
5#define SPEED 88 //速度控制
6#define keyenable 1
7
8 sbit led = P0^0;
9 sbit up=P3^2;
10 sbit down=P3^4;
11 sbit right=P3^3;
12 sbit left=P3^1;
13
14 uchar x[SNAKE+1];
15 uchar y[SNAKE+1];
16 uchar time,n,i,e; //延时时间,当前蛇长,通⽤循环变量,当前速度
17char fx,fy; //位移偏移量
18
19/***************************
20延时程序
21****************************/
22void delay(char MS)
23 {
24char us,usn;
25while(MS!=0)
26 {
27 usn = 0;
28while(usn!=0)
29 {
30 us=0xff;
31while (us!=0)
32 {us--;};
33 usn--;
34 }
35 MS--;
36 }
37 }
38/****************************
39判断碰撞
40*****************************/
41 bit knock()
42 {
43 bit k;
44 k=0;
45if(x[1]>7||y[1]>7)
46 k=1; //撞墙
47for(i=2;i<n;i++)
48if((x[1]==x[i])&(y[1]==y[i]))
49 k=1; //撞⾃⼰
50return k;
51 }
52/*****************************
53上下左右键位处理
54******************************/
55void turnkey()
56 {
57if(keyenable)
58 {
59if(left)
60 {
62if(fx!=1)
63 fx=-1;
64else fx=1;
65 }
66if(right)
67 {
68 fy=0;
69if(fx!=-1)
70 fx=1;
71else fx=-1;
72 }
73if(up)
74 {
75 fx=0;
76if(fy!=-1)
77 fy=1;
78else fy=-1;
79 }
80if(down)
81 {
82 fx=0;
83if(fy!=1)
84 fy=-1;
85else fy=1;
86 }
87 }
88 }
89/*******************************
90乘⽅程序
91********************************/
92 uchar mux(uchar temp)
93 {
94if(temp==7) return128;
95if(temp==6) return64;
96if(temp==5) return32;
97if(temp==4) return16;
98if(temp==3) return8;
99if(temp==2) return4;
100if(temp==1) return2;
101if(temp==0) return1;
102return0;
103 }
104/*******************************
105显⽰时钟显⽰程序
106*******************************/
107void timer0(uchar k)
108 {
109while(k--)
110 {
111for(i=0;i<SNAKE+1;i++)
112 {
113 P2=mux(x[i]);
114 P1=255-mux(y[i]);
115 turnkey(); //上下左右键位处理116 delay(TIME); //显⽰延迟
117 P2=0x00;
118 P1=0xff;
119 }
120 }
121 }
122/*******************************
123主程序
124*******************************/
125void main(void)
126 {
127 e=SPEED;
128 P0=0x00;
129 P1=0xff;
130 P2=0x00;
131 P3=0x00;
132while(1)
133 {
134for(i=3;i<SNAKE+1;i++)
135 x[i]=100;
136for(i=3;i<SNAKE+1;i++)
137 y[i]=100; //初始化
138 x[0]=4;
139 y[0]=4; //设置⾷物
140 n=3; //贪吃蛇长
141 x[1]=1;y[1]=0; //贪吃蛇头142 x[2]=0;y[2]=0; //贪吃蛇尾143 fx=0;
144 fy=0; //位移偏移
146 {
147if(keyenable)
148break;
149 timer0(1);
150 }
151while(1)
152 {
153 timer0(e);
154if(knock())
155 {
156 e=SPEED;
157break;
158 } //判断碰撞
159if((x[0]==x[1]+fx)&(y[0]==y[1]+fy)) //是否吃东西160 {
161 n++;
162if(n==SNAKE+1)
163 {
164 n=3;
165 e=e+10;
166for(i=3;i<SNAKE+1;i++)
167 x[i]=100;
168for(i=3;i<SNAKE+1;i++)
169 y[i]=100;
170 }
171 x[0]=x[n-2];
172 y[0]=y[n-2];
173 }
174for(i=n-1;i>1;i--)
175 {
176 x[i]=x[i-1];
177 y[i]=y[i-1];
178 }
179 x[1]=x[2]+fx;
180 y[1]=y[2]+fy; //移动
181 }
182 }
183 }
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论