基于普中51单片机的贪吃蛇游戏
一、8*8LED点阵模块以及74HC595模块
首先我们先来看LED点阵的原理图:
在进行LED点阵点亮之前我们先要了解74HC595写入规则。595是一个串行输入并行输出的芯片,SRCLK引脚上升沿有效时从SER端读取一个bit位,因此8个周期后可读取一个字节的数据,此时RCLK来一个上升沿数据便可以从8个并行输出口输出数据。以下是595的写入函数:
void write_595(char dat)
{
int i;
for(i=0;i<8;i++)
{
ser = dat >> 7;//取最高位
dat = dat << 1;//把每次要读取的bit位放到最高位
srclk = 0;//产生上升沿
srclk = 1;
}
rclk = 0;//产生上升沿
rclk = 1;
}
会往74HC595写入数据后,我们可以看到LED点阵的每行接到了74HC595的并行输出口,而每列直接接到了51单片机的P0口,这样我们如果想要点亮某一个LED等,只需配置74HC595的输入以及51单片机的P0口。例如点亮第0行第0列的LED灯:
只需给595的输入口SER写入10000000b,51单片机的P0口写入01111111b即可(让LED点阵的第0行为高电平,其余行为低电平;第0列为低电平,其余列为高电平,这样就只有第0行第0列的LED点亮)。这样我们可以事先把行使能与列使能提前存入两个数组中,方便后续使用。
char buff[8] = {
0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
char buff_P0[8] = {
0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
其中buff数组为行使能,buff_P0数组为列使能。如果想要依次点亮8*8点阵,可以进行以下操作:
void display()
{
int i,j;
for(i=0;i<8;i++)
{
for(j=0;j<8;j++)
{
write_595(buff[i]);
led_col = buff_P0[j];
delay(50000);
}
}
}
有了以上的基础,我们来想一想如何实现贪吃蛇游戏。以下是我的想法:
创建一个88的数组matrix来模拟88的LED点阵。围墙的数值计为-1;食物的数值计为-2;蛇的身体为1到当前的长度len,1代表尾巴,len代表长度;其余位置计为0,这样我们的打印函数就很好实现了:
void display()
{
int i,j;
for(i=0;i<8;i++)
{
for(j=0;j<8;j++)
{
//打印围墙,食物,蛇的身体
if(matrix[i][j] == -1 || matrix[i][j] > 0 || matrix[i][j] == -2)
{
write_595(buff[i]);
led_col = buff_P0[j];
}
}
}
}
二、按键检测模块
实现了打印函数后,接下来我们要让蛇动起来,即通过四个独立按键代表上下左右四个方向。那么就先要实现按键的检测。按键检测需要注意的点是按键消抖,否则按键检测就不灵敏。我们先来看独立按键的原理图:
可以看到四个独立按键接在了51单片机P3的四个口上,按下为低电平,独立按键的扫描代码如下:
char key_scan(char mode)
{
static int n = 1;
if(mode == 1)//mode为1时实现连续检测
n = 1;
if(n == 1 && (key1 == 0 || key2 == 0 || key3 == 0 || key4 == 0))
{
n=0;
delay(1000);//按键消抖
if(key1 == 0)
return 1;
else if(key2 == 0)
return 2;
else if(key3 == 0)
return 3;
else if(key4 == 0)
return 4;
}
else if(key1 == 1 && key2 == 1 && key3 == 1 && key4 == 1 )
{
n=1;
}
return 0;
}
注意:mode为1时实现连续检测,后续用的是mode=0,即检测一次。如果理解不了可以看看b站普中科技的按键检测实验。
三、方向移动模块
实现按键扫描后,那么每个按键就代表了不同的方向,按下后就向不同的方向移动。如何实现方向的移动呢?我的想法是:
遍历数组找到数值为len的点,如果向上移动就将这个点的上方点赋值为len+1,若上方点是食物(-2),则给当前长度加一,生成食物并结束;若这点是空白处(0),则再遍历一遍数组将值大于0的点都减一;若这点是墙或者自己的身体(-1或者大于0),则让蜂鸣器发出警报。其余方向的移动思路都类似,废话不多说,之间上代码:
void up()
{
int i,j,flag=1;
for(i=0;i<8;i++)
for(j=0;j<8;j++)
if(matrix[i][j] == len)
{
if(matrix[i-1][j] == -2)
flag = 0;
else if(matrix[i-1][j] == -1 || matrix[i-1][j] > 0)
flag = 2;
matrix[i-1][j] = len+1;
}
//上方是空白处
if(flag == 1)
{
for(i=0;i<8;i++)
for(j=0;j<8;j++)
if(matrix[i][j] > 0)
matrix[i][j] -= 1;
}
//上方是食物
else if(flag == 0)
{
len++;
make_food();
}
//上方是墙或者蛇的身体
else