之前在做贪吃蛇的时候一直想找一些好理解的51单片机贪吃蛇代码,不是找不到了就是很难理解,又或者CS某N要付费,后面就直接自己写了加上参考了一部分资料,几天才写完,就想着来分享一下吧本次代码采用模块化设计,分为主函数模块,点阵模块和延时模块。
#include <REGX52.H>
#include <stdlib.h>
#include <intrins.h>
#include "Delay.h"
#include "MatrixLED.h"
typedef unsigned int u16;
typedef unsigned char u8;
sbit up=P3^1;
sbit down=P3^0;
sbit lt=P3^2;
sbit rt=P3^3;
u8 coordx[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe,};
u8 coordy[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01,};
u8 foodx;
u8 foody;
u8 snake_x[20]={0};
u8 snake_y[20]={0};
u8 length;
u8 direction;
void initsnake();
void Keyboard();
void move();
void creatfood();
void snakegrow(void);
void drawsnake();
void initsnake()//蛇的初始化
{
snake_x[0]=0;//1
snake_y[0]=0;//1
length=1;
direction=2;
}
void move()//移动
{
u8 len=length-1;//u16,漏-1
for (len;len>0;len--)
{
snake_x[len]=snake_x[len-1];
snake_y[len]=snake_y[len-1];
}
switch(direction)//case不加()
{
case 1:
snake_y[0]--;
break;
case 2:
snake_y[0]++;
break;
case 3:
snake_x[0]--;
break;
case 4:
snake_x[0]++;
break;
default:
break;
}
}
void Keyboard()//按钮
{
if(up==0)
{
Delay(10);//避免
if(up==0)
{
direction=1;
}
while(!up);//!up,原up==1
}
if(down==0)
{
Delay(10);
if(down==0)
{
direction=2;
}
while(!down);//!down
}
if(lt==0)
{
Delay(10);
if(lt==0)
{
direction=3;
}
while(!lt);//改
}
if(rt==0)
{
Delay(10);
if(rt==0)
{
direction=4;
}
while(!rt);//改
}
}
void creatfood()//食物创造
{
u8 i;//u16
foodx=rand()%8;
foody=rand()%8;
for(i=0; i<length; i++)
{
if((foodx==snake_x[i])&&(foody==snake_y[i]))//括号运算优先级
{
creatfood();
}
}
}
void snakegrow()//吃食物后增厂长
{
if(foody==snake_y[0]&&foodx==snake_x[0])
{
creatfood();
snake_x[length]=snake_x[length-1];
snake_y[length]=snake_y[length-1];
length++;
}
}
void drawsnake()//调佣mtrixled来绘制蛇和食物
{
u8 i;//u16
for(i=0;i<length;i++)//应该是小于length
{
MatrixLED_ShowColumn(coordy[snake_y[i]],coordx[snake_x[i]]);
MatrixLED_ShowColumn(coordy[foody],coordx[foodx]);
}
}
void judgedeath()//判断死亡
{
u8 i;//u16
if((snake_x[0]>7)||(snake_y[0]>7))
{
_74H595_WriteByte(0x00);//MatrixLED_ShowColumn(0x00,0xff);//清屏
while(1);
}
for(i=4; i<length;i++)
{
if((snake_x[0]==snake_x[i])&&(snake_y[0]==snake_y[i]))
{
P0=0xFF;//MatrixLED_ShowColumn(0x00,0xff);
while(1);
}
}
}
void Timer0Init()
{
TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。
TH0=0XD8; //给定时器赋初值,定时10ms
TL0=0XF0;
ET0=1;//打开定时器0中断允许
EA=1;//打开总中断
TR0=1;//打开定时器
}
void Timer0() interrupt 1
{
static u16 i;
TH0=0XD8; //给定时器赋初值,定时10ms
TL0=0XF0;
i++;
if(i==50)
{
i=0;
move();
}
}
void main()
{
Timer0Init();
initsnake();
while (1)
{
drawsnake();
judgedeath();
snakegrow();
Keyboard();
}
}
#include <intrins.h>//延时函数
void delay(unsigned char a) //@11.0592MHz
{
unsigned char b;
for(b=1;b<=a;b++)
{
unsigned char i=2;
while(--i);
}
}
#include <REGX52.H>
#include "Delay.h"
sbit SER=P3^4;
sbit SCK=P3^6;
sbit RCK=P3^5;
typedef unsigned char u8;
typedef unsigned int u16;
void _74H595_WriteByte(unsigned char Byte)
{
u8 i=0;
for(i=0;i<8;i++)
{
SER=Byte>>7;
Byte<<=1;
SCK=1;//1
Delay(1);
SCK=0;//0
}
RCK=1;//1
Delay(1);
RCK=0;//0
}
void MatrixLED_ShowColumn(u8 Column,u8 Date)//Column为行(74H595),Date为列(0有效)
{
_74H595_WriteByte((Column));
P0=(Date);//if(Date==0){P0=~0x80;}
Delay(1);
P0=0xff;//位清零
}
大概还有.h文件没有补充,一般来说学到这里的人应该都会模块化,.h的文件创建也很简单就懒得上传了。后面可以改善的就是死亡后的点阵动画,有兴趣的人可以自己写一下改善我的代码。另外本代码运用了vscode的EIDE模块,vscode真的在长一点的代码写作上面很有用,此外我在设置vscode的时候也遇了很多的问题,调试了我一下午,有空也可以写来分享下避免踩坑。