基于51单片机开发板8*8LED矩阵的贪吃蛇程序

引语:过年的时候闲着无聊,恰好也刚学了点51开发板的东西,所以就想写一个贪吃蛇的小程序。在网上总结了一些关于贪吃蛇的算法,于是就有了以下的程序。

    先来说以一下算法的原理:将8*8LED看作是直角坐标系,将左上角定为坐标原点。定义两个数组  snake_x[],snake_y[]用来存储蛇的x,y轴坐标。因此,我们的核心算法就是小蛇惯性保持自己的运动姿态,产生食物,以及小蛇吃到食物后长度增加。

    再来看一下我的开发板,我的开发板是德飞莱51开发板,这里不再讲解其8*8LED的工作原理,直接上代码

void Hc595SendByte()
{
	unsigned char a;
	SRCLK=0;
	RCLK=0;
	for(a=0;a<8;a++)
		{
			SER=CHARCODE[p_now][a];
SRCLK=1;
_nop_();
_nop_();
SRCLK=0;
}

 RCLK=1;
 _nop_();
 _nop_();
 RCLK=0;
}
void Display()
{
 unsigned int tab;
 for(tab=0;tab<8;tab++) //扫描8列
{
Hc595SendByte_clean(0x00); //消隐
COMMONPORTS= TAB[tab]; //输出字码
Hc595SendByte(); //写入一个直字节数据 
p_now++; //扫描下一行
if(p_now == 8) //扫描8行后归零
{
p_now = 0; //伪指针归零
}
}
}

      这里定义了两个函数 Hc595SendByte ()和Display()两个函数,其中CHARCODE[x][y]数组是用来存放LED的状态值的。0x00代表灭,0x01代表亮。因此,在整个程序中,如果想将小蛇或食物显示在LED上,只需将相关点的坐标作为数组括号内的两个常量表达式,并将其赋值0x00或0x01即可。
 在void Auto_Move()函数中,

void Auto_Move()
{
 unsigned char i;
 if(Time==10) //蛇500ms移动一下
{ 
	temp_x = snake_x[0]; //蛇尾坐标临时存储
	temp_y = snake_y[0];
	for(i=0;i<snake_long;i++) //除了蛇头蛇尾-身体其它部分不改变只需要移位
	{
		snake_x[i] = snake_x[i+1];
		snake_y[i] = snake_y[i+1];
	}
	snake_x[snake_long] = x; //蛇头坐标临时存储
	snake_y[snake_long] = y;
	switch(direction_flag)
	{
		case 16:
		{//默认移动-向右即一开始适时,舍
			x++;
			temp_direction=direction_flag;
			break;
	         }
                case 1:
		{//惯性制导-向上
			y--;
			temp_direction=direction_flag;
			break;
                  }
                 case 4
                 {//惯性制导-向左                
                        x--;
                        temp_direction=direction_flag;
                        break;
                  }
                 case 6:{//惯性制导-向右 
                 x++;
                 temp_direction=direction_flag;
                 break;
                 }
                 case 9:{//惯性制导-向下
                 y++;
                 temp_direction=direction_flag;
                 break;
                 }
                 default:
                 {direction_flag=temp_direction;//按键按错时修正运动方向
switch(direction_flag)
 {
 case 1:{y--;break; //修正-向上
}
case 4:{x--;break; //修正-向左
}
case 6:{x++;break; //修正-向右
}
case 9:{y++;break; //修正-向下
}
case 16:{x++;break; //修正-默认
}
 }
break;
 }
 }

Auto_move()函数是本程序的核心,关于他具体怎么实现小蛇的移动,程序的注释已经写的很清楚。

    接下来就是定义产生食物的函数。这个函数内部运用了rand()随机函数,用来产生随机的食物位置。food_x和food_y是食物的横纵坐标。

void Food()
{
 if(food_flag>0)
 {
	food_x=rand()%7; //伪随机数-食物横坐标(0-7之间)
	food_y=rand()%7; //伪随机数-食物纵坐标(0-7之间)
	CHARCODE[food_x][food_y]=0x01;//在地图中显示食物
	food_flag=-food_flag; //食物产生标志翻转
}
}

    接下来是小蛇长度变长的函数

void Eating()
{
 if(food_flag<0&&snake_x[snake_long]==food_x&&snake_y[snake_long]==food_y)//小蛇的头部坐标如果等于食物的坐标,那么则说明小蛇吃到食物
{
snake_long++; //蛇身加长,即增加小蛇数组常量表达式的值
switch(direction_flag)
{
 case 1:{
 snake_x[snake_long]=food_x; //将惯性运动下一个坐标点亮增加蛇长
snake_y[snake_long]=food_y-1;
 break;
 }
 case 4:{
 snake_y[snake_long]=food_y; //将惯性运动下一个坐标点亮增加蛇长
snake_x[snake_long]=food_x-1;
 break;
 }
 case 6:{
 snake_y[snake_long]=food_y; //将惯性运动下一个坐标点亮增加蛇长
snake_x[snake_long]=food_x+1;
 break;
 }
 case 9:{
 snake_x[snake_long]=food_x; //将惯性运动下一个坐标点亮增加蛇长
snake_y[snake_long]=food_y+1;
 break;
 }
 }

CHARCODE[food_x][food_y]=0x00;//清除食物
 
food_flag=-food_flag; //产生新的食物

}
} 

仅看注释已经可以明白该段程序。

下面是程序相关变量的定义以及函数的声明部分。

#ifndef _DEFINITION_H
#define _DEFINITION_H
#include<reg51.h> //库调用及宏
#include<intrins.h> 
#include<stdlib.h>
#include<math.h>
#define COMMONPORTS P0 //LED位码IO口
#define GPIO_KEY P1 //矩阵键盘IO口

sbit SRCLK=P3^6; //74HC595控制端口
sbit RCLK=P3^5;
sbit SER=P3^4; 
int x=1,y=3; //蛇头初始坐标
int temp_x=0,temp_y=0; //蛇尾初始坐标
int food_x,food_y; //食物坐标
int food_flag=1; //食物产生标志
unsigned char temp_direction; //方向矫正
unsigned char snake_long=1; //蛇身长-初始为2 
unsigned char Time=0; //用于定时累计
unsigned char p_now=0; //伪指针(点阵需横向扫描8次) 
unsigned char KeyValue=16; //矩阵键盘键值存储
unsigned char direction_flag=16; //惯性移动方向标志

unsigned char snake_x[10]={0,1}; //蛇的横坐标 蛇的最长长度为10
unsigned char snake_y[10]={3,3}; //蛇的纵坐标

unsigned char code TAB[8] = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};//LED位码
unsigned char CHARCODE[8][8]= //地图
{
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
};
#endif
#ifndef _FUNCTION_H
#define _FUNCTION_H
void Hc595SendByte();
void Hc595SendByte_clean(unsigned char);//消隐函数,SER=0x00
void Delay10ms();
void KeyDown();//按键扫描函数,上下左右四个方向键
void WALL();//小蛇撞到墙后,从另一边出来
void Direction();//上下左右四个方向键,对应四个direction_flag
void Auto_Move();
void Food();
void Eating();
void INIT();//定时器函数,用于扫描LED
void Display();
void Distory();//小蛇的头部坐标等于蛇身的某处坐标时,则触发bee()函数,并停止小蛇移动
void bee();//蜂鸣器函数
#endif

好了,现在你应该可以将剩下的代码完成了。

现在这个代码还有不够完善的地方,比如在实际运行的时候,小蛇的长度达到定义的长度以后就无法继续向下移动,或者是LED矩阵显示的是乱码。

   



  • 11
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值