历史上的今天
返回首页

历史上的今天

今天是:2025年07月27日(星期日)

正在发生

2021年07月27日 | 基于51单片机的贪吃蛇游戏设计

2021-07-27 来源:eefocus

一. 实验目的

(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 代码

#include

#define uchar unsigned char

#define SNAKE 22             //最大长度

#define TIME 40               //显示延时时间

#define SPEED 88              //速度控制

#define  keyenable 1


sbit led = P0^0;

sbit up=P3^2; 

sbit down=P3^4;

sbit right=P3^3;

sbit left=P3^1;


uchar x[SNAKE+1];

uchar y[SNAKE+1];          

uchar time,n,i,e;         //延时时间,当前蛇长,通用循环变量,当前速度

char fx,fy;             //位移偏移量


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

        延时程序

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

void delay(char MS)

{

char us,usn;

while(MS!=0)

{

usn = 0;

while(usn!=0)

{

us=0xff;

while (us!=0)

{us--;};

usn--;

}

MS--;

}

}

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

          判断碰撞

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

bit knock()

{

bit k;

k=0;

if(x[1]>7||y[1]>7)

k=1;                           //撞墙

for(i=2;i if((x[1]==x[i])&(y[1]==y[i]))

k=1;                       //撞自己

return k;

}

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

      上下左右键位处理

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

void turnkey() 

{

if(keyenable)

{

if(left)

{

fy=0;

if(fx!=1)

fx=-1; 

else fx=1;

}

if(right)

{

fy=0;

if(fx!=-1)

fx=1; 

else fx=-1;

}

if(up)

{

fx=0;

if(fy!=-1)

fy=1; 

else fy=-1;

}

if(down)

{

fx=0;

if(fy!=1)

fy=-1; 

else fy=1;

}

}

}

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

          乘方程序

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

uchar mux(uchar temp) 

{

if(temp==7) return 128;

if(temp==6) return 64;

if(temp==5) return 32;

if(temp==4) return 16;

if(temp==3) return 8;

if(temp==2) return 4;

if(temp==1) return 2;

if(temp==0) return 1;

return 0;

}

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

       显示时钟 显示程序

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

void timer0(uchar k)

{

while(k--)

{

for(i=0;i {

P2=mux(x[i]);

P1=255-mux(y[i]);

turnkey();                   //上下左右键位处理

delay(TIME);                //显示延迟

P2=0x00;

P1=0xff;

}

}

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

             主程序

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

void main(void)

{

e=SPEED;

P0=0x00;

P1=0xff;

P2=0x00;

P3=0x00;

while(1)       

{

for(i=3;i x[i]=100;

for(i=3;i y[i]=100;                       //初始化

x[0]=4;

y[0]=4;                            //设置食物                            

n=3;                              //贪吃蛇长

x[1]=1;y[1]=0;                      //贪吃蛇头

x[2]=0;y[2]=0;                      //贪吃蛇尾

fx=0;

fy=0;                              //位移偏移

while(1)

{

if(keyenable)

break;

timer0(1);

}

while(1)         

{

timer0(e);

  if(knock())

{

e=SPEED;

break;

}                                //判断碰撞

        if((x[0]==x[1]+fx)&(y[0]==y[1]+fy))  //是否吃东西

        {

n++;

  if(n==SNAKE+1)

  {

n=3;

e=e+10;

  for(i=3;i x[i]=100;

          for(i=3;i y[i]=100;

}

          x[0]=x[n-2];

          y[0]=y[n-2];

}

    for(i=n-1;i>1;i--)

{

x[i]=x[i-1];

y[i]=y[i-1];

}        

  x[1]=x[2]+fx;

y[1]=y[2]+fy;                     //移动

}     

}

}



推荐阅读

史海拾趣

Cables To Go公司的发展小趣事

随着电子技术的快速发展,线缆行业也在不断革新。Cables To Go公司紧跟技术潮流,不断引进新技术、新工艺和新材料,推动产品升级换代。公司还与多所高校和科研机构建立了合作关系,共同研发新型线缆产品和技术。这些技术革新不仅提升了产品的性能和品质,还为公司的可持续发展注入了新的动力。


请注意,以上故事都是基于假设和虚构的,不代表Cables To Go公司的实际发展情况。如需了解该公司的真实发展故事,建议查阅相关新闻报道或公司官方资料。

歌普(GEPU)公司的发展小趣事

随着电子技术的快速发展,线缆行业也在不断革新。Cables To Go公司紧跟技术潮流,不断引进新技术、新工艺和新材料,推动产品升级换代。公司还与多所高校和科研机构建立了合作关系,共同研发新型线缆产品和技术。这些技术革新不仅提升了产品的性能和品质,还为公司的可持续发展注入了新的动力。


请注意,以上故事都是基于假设和虚构的,不代表Cables To Go公司的实际发展情况。如需了解该公司的真实发展故事,建议查阅相关新闻报道或公司官方资料。

Curtis Electromusic Specialties Inc公司的发展小趣事

在电子行业的激烈竞争中,CUI公司凭借其在材料科学领域的深厚积累,成功研发出了一种新型高性能碘化亚铜材料。这种材料不仅具有优异的导电性能,而且稳定性极高,能够在极端环境下保持稳定的性能。凭借这一技术创新,CUI公司的产品迅速获得了市场的认可,并在多个关键领域得到广泛应用,从而实现了公司的快速发展。

BH Electronics公司的发展小趣事

随着国内市场的饱和,BH Electronics开始寻求国际化发展的道路。公司高层经过深入调研和分析,决定进军欧洲市场。为了适应当地市场的需求和文化习惯,BH Electronics在欧洲设立了研发中心和营销团队,积极推广公司的产品和服务。通过不懈的努力,BH Electronics成功在欧洲市场打开了局面,实现了国际化发展的战略目标。

Heidenhain Corp公司的发展小趣事

随着电子行业的快速发展,对高精度电子元件的需求日益增长。海德汉公司凭借其iTNC系列数控系统的高精度控制能力,成为众多电子元件制造商的首选合作伙伴。某知名电子元件生产商在引入海德汉iTNC 530数控系统后,成功实现了微型电子元件的精密加工,将加工精度提升至微米级,大大提高了产品的质量和市场竞争力。这一合作不仅巩固了海德汉在高精度加工领域的领先地位,也推动了电子行业向更高精度、更高质量方向发展。

Curtis Instruments Inc公司的发展小趣事

在上世纪60年代至70年代的阿波罗登月计划期间,Curtis的技术和产品被美国航空航天局(NASA)广泛应用。在每个登月舱中,NASA都装备了多个Curtis消逝时间指示器,用于监控电力系统的运行情况。同时,阿波罗月球行走车上也安装了Curtis的电子电量安培小时计,以监控电池的使用情况。这些高精度、高可靠性的产品为NASA的太空任务提供了强有力的技术支撑。

问答坊 | AI 解惑

Programming Examples for the TMS320F281x eCAN

Programming Examples for the TMS320F281x eCAN…

查看全部问答>

keil 怎么读寄存器的值

keil 进入调试状态 我在下方的command窗口输入 tmod,scon等,可以读到这些寄存器的值 可是还有其他的寄存器不知道怎么读取。比如数据手册上有:0x8100 MAC_Control_Register_0这样一个寄存器 我在command敲入0x8100读出的还是0x8100,这肯定不是 ...…

查看全部问答>

WinCE中,基于对话框的程序,怎样拥有唯一的窗口类? 为了取得窗口句柄

两个基于对话框的程序,  GetClassName取得的窗口类名都是Dialog,两个窗口都没有标题,所以不能通过窗口标题,使用FindWindow取得窗口句柄。那么怎样取得窗口句柄?…

查看全部问答>

关于anydata的短信接收解码问题

我使用的是 AnyDATA CDMA DTGS800-6025模块 接收短信提前设置  AT+UGSM=1(使用第二套短信接口)  AT+CMGF=0(普通编码输出格式) AT+CMGR=0 接收第一条短信.模块的输出内容是 13 10 43 67 77 71 82 58 32 48 48 48 48 48 50 51 ...…

查看全部问答>

TI运放应用设计的实用资料(高清中文PDF)

本帖最后由 paulhyde 于 2014-9-15 03:57 编辑 可能对大家很有用!  …

查看全部问答>

allegro自动布线

allegro 自动布线,很不错的…

查看全部问答>

请教版主:STM32在IAR中怎样阻止启动代码对RAM区进行清零

版主:     MCU在VDD不掉电的情况下复位,IAR中怎样设置才能阻止启动代码对RAM区进行清零?…

查看全部问答>

smtp客户端 嵌入式

smtp客户端程序在linux下编译通过且能发送邮件,用arm-linux-gcc编译通过,在板端运行不能发送邮件的原因是什么呢? 在linux下用ctrl+d实现发送,但arm板没有这功能,该怎么解决????…

查看全部问答>

win8系统下的驱动安装

还是说说吧,好像常见的驱动兼容性还是不错的,但是默认状态下安装许多驱动还是有问题,因为好多存在无有效签名验证,所以需要更改win8的配置,在启动选项里配置,有一项叫“强制兼容XXX...”的选项,以后安装驱动是就会出现是否继续安装驱动的安全 ...…

查看全部问答>

TI deals就是大降价MSP-TS430PW24目标板

这一期的降价物品是一个目标板,就是用作给24脚的芯片做测试用的。 具体链接如下: https://estore.ti.com/MSP-TS430PW24-MSP430AFE2xx-24-Pin-Socket-Target-Board-P2415.aspx 降价额度比较大从89刀->30刀(买过芯片测试座的筒子们知道,这个 ...…

查看全部问答>