51单片机实现贪吃蛇(清翔单片机)

这篇具有很好参考价值的文章主要介绍了51单片机实现贪吃蛇(清翔单片机)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、创作背景

二、实现过程

1.一些声明与定义

2.键盘扫描

3.定时器中断

5.蛇的初始化

6.蛇体的移动

7.食物的创建

8.食物的检测和身体的增长

9.检测死亡

10.总代码

总结


一、创作背景

由于大一的一个小作业,花了10天完成了这个小项目,中途克服了很多困难,发此文章以作纪念。

二、实现过程

1.一些声明与定义

这些后面会讲到。

#include <reg52.h>
#include <stdlib.h>
#define uint unsigned int
#define uchar unsigned char
#include <intrins.h>

sbit DIO = P3 ^ 4;
sbit S_CLK = P3 ^ 5;
sbit R_CLK = P3 ^ 6;
sbit key_s2 = P3 ^ 0;//独立键盘4个按键
sbit key_s3 = P3 ^ 1;
sbit key_s4 = P3 ^ 2;
sbit key_s5 = P3 ^ 3;

uchar coorx[8] = { 0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe };
uchar coory[8] = { 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 };
uchar snakex[20];//蛇体x坐标
uchar snakey[20];//蛇体y坐标
uchar m = 0;
uchar len = 1;//蛇体长度
uchar foodx, foody;//食物x, y坐标
uchar d, xx, yy;

2.键盘扫描

这里我用的是独立键盘,由于点阵屏的IO口和矩阵键盘的IO口冲突导致显示的内容不对(个人能力有限,暂时没办法解决这个冲突问题,只好避开),所以采用了独立键盘。同时也是因为这个原因我没有采用扫描的方式,而是一个一个判断。如果开发板不冲突可以选择矩阵键盘。

char key = 0;

void delay(uint z)
{
	uint x, y;
	for (x = z; x > 0; x--)
		for (y = 114; y > 0; y--);
}

void keyscan()
{
	if (key_s2 == 0)
	{
		delay(10);
		if (key_s2 == 0)
		{
			if (key != 4)
				key = 1;
		}
	}
	if (key_s3 == 0)
	{
		delay(10);
		if (key_s3 == 0)
		{
			if (key != 3)
				key = 2;
		}
	}
	if (key_s4 == 0)
	{
		delay(10);
		if (key_s4 == 0)
		{
			if (key != 2)
				key = 3;
		}
	}
	if (key_s5 == 0)
	{
		delay(10);
		if (key_s5 == 0)
		{
			if (key != 1)
				key = 4;
		}
	}
}

3.定时器中断

这里是相关寄存器的配置,定时为5ms,用处是为了控制蛇的移动速度已经键盘的判断。

void timer0Init()
{
	EA = 1;
	ET0 = 1;
	TR0 = 1;
	TMOD = 0X01;
	TH0 = 0XED;
	TL0 = 0XFF;
}
void SendByte(uchar x, uchar y)//用来接收行列值,这里x和y是坐标,点阵屏左下角为坐标原点
{
	uchar i, j, dat1, dat2;
	dat1 = coorx[x - 1];//这里通过前面定义的两个数组将坐标转化为了行列的十六进制数
	dat2 = coory[y - 1];
	for (i = 0; i < 8; i++)
	{
		if (dat1 & 0x01)
			DIO = 1;
		else
			DIO = 0;
		S_CLK = 1;//穿行输入
		S_CLK = 0;
		dat1 >>= 1;
	}
	for (j = 0; j < 8; j++)
	{
		if (dat2 & 0x01)
			DIO = 1;
		else
			DIO = 0;
		S_CLK = 1;//串行输入
		S_CLK = 0;
		dat2 >>= 1;
	}
	R_CLK = 1;//并行输出
	R_CLK = 0;
}

5.蛇的初始化

main函数主要内容

void main()
{
	timer0Init();//定时器0初始化
	snakex[0] = 5;//蛇体初始x坐标
	snakey[0] = 5;//蛇初始y坐标
	creat_food();
	while (1)
	{
		snakemove();
		FoodAnd();
	}
}

void timer0() interrupt 1
{
	TH0 = 0XED;
	TL0 = 0XFF;
	m++;//每加到一百蛇体移动一次,速度可以自己调
	keyscan();//键盘扫描
	for (d = 0; d < len; d++)
	{
		SendByte(snakex[d], snakey[d]);//将蛇体显示在点阵屏上,参数是xy坐标
	}
	SendByte(foodx, foody);//显示食物
	CheckDead();//检验是否死亡
}

6.蛇体的移动

void left()//上下左右都是一个道理
{
	uchar i, x1, x2, y1, y2;
	x1 = snakex[0];//保留上一结点的x轴状态
	snakex[0]--;//坐标减1
	if (snakex[0] == 0)//这里是判定是否碰到边界了,这里设定的是可以从另一边出来,当然也可以设定为碰到就死
		snakex[0] = 8;
	y1 = snakey[0];//保留上一结点的y轴状态
	for (i = 1; i < len; i++)
	{
		y2 = snakey[i];//进行各个结点的状态移动,形成蛇运动的效果
		snakey[i] = y1;
		y1 = y2;

		x2 = snakex[i];
		snakex[i] = x1;
		x1 = x2;
	}
}

void up()
{
	uchar i, x1, x2, y1, y2;
	y1 = snakey[0];
	snakey[0]--;
	if (snakey[0] == 0)
		snakey[0] = 8;
	x1 = snakex[0];
	for (i = 1; i < len; i++)
	{
		x2 = snakex[i];
		snakex[i] = x1;
		x1 = x2;

		y2 = snakey[i];
		snakey[i] = y1;
		y1 = y2;
	}
}

void down()
{
	uchar i, x1, x2, y1, y2;
	y1 = snakey[0];
	snakey[0]++;
	if (snakey[0] == 9)
		snakey[0] = 1;
	x1 = snakex[0];
	for (i = 1; i < len; i++)
	{
		y2 = snakey[i];
		snakey[i] = y1;
		y1 = y2;

		x2 = snakex[i];
		snakex[i] = x1;
		x1 = x2;
	}
}

void right()
{
	uchar i, x1, x2, y1, y2;
	x1 = snakex[0];
	snakex[0]++;
	if (snakex[0] == 9)
		snakex[0] = 1;
	y1 = snakey[0];
	for (i = 1; i < len; i++)
	{
		x2 = snakex[i];
		snakex[i] = x1;
		x1 = x2;

		y2 = snakey[i];
		snakey[i] = y1;
		y1 = y2;
	}
}

void snakemove()
{
	if (key == 1 && m == 100)//这里是判断按键值并且m要达到100,也就是500ms移动一次
	{
		left();
		m = 0;//要清一下零
	}
	if (key == 2 && m == 100)
	{
		up();
		m = 0;
	}
	if (key == 3 && m == 100)
	{
		down();
		m = 0;
	}
	if (key == 4 && m == 100)
	{
		right();
		m = 0;
	}
}

7.食物的创建

这一部分本来以为使用c语言里面srand(unsigned seed)(这个函数只要种子的值是变化的生成的就是某种意义上随机数)函数加上一个一直变化的时间戳就可以生成随机数的,但是后来发现keil里面没有time.h这个头文件,导致没法实现真正意义的随机数。这个问题暂留

uchar CheckFood()//检验食物有没有和蛇体重合
{
	uchar i;
	for (i = 0; i < len; i++)
	{
		if (foodx == snakex[i] && foody == snakey[i])
		{
			return 1;
		}
	}
	return 0;
}

void creat_food()
{
	do
	{
		foodx = (uchar)(rand() % 8 + 1);
		foody = (uchar)(rand() % 8 + 1);
	} while (CheckFood() != 0);
}

8.食物的检测和身体的增长

void FoodAnd()//检验食物有没有被吃掉
{
	if (foodx == snakex[0] && foody == snakey[0])
	{
		if (len < 20)
		{
			snakex[len] = snakex[len - 1];//和之前一样,把上一个结点的状态赋给下一个结点,用来增加长度
			snakey[len] = snakey[len - 1];
			len++;
		}
		creat_food();//被吃掉重新生成食物
	}
}

9.检测死亡

这里i = 2是因为等于1的时候会在吃食物的时候冲突,而蛇头不可能碰到碰到第二节,所以初值设定为2

void CheckDead()
{
	uchar i;
	for (i = 2; i < len; i++)
	{
		if (snakex[0] == snakex[i] && snakey[0] == snakey[i])
		{
			while (1);
		}
	}
}

10.总代码

#include <reg52.h>
#include <stdlib.h>
#define uint unsigned int
#define uchar unsigned char
#include <intrins.h>

sbit DIO = P3 ^ 4;
sbit S_CLK = P3 ^ 5;
sbit R_CLK = P3 ^ 6;
sbit key_s2 = P3 ^ 0;
sbit key_s3 = P3 ^ 1;
sbit key_s4 = P3 ^ 2;
sbit key_s5 = P3 ^ 3;

uchar coorx[8] = { 0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe };
uchar coory[8] = { 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 };
uchar snakex[20];
uchar snakey[20];
uchar m = 0;
uchar len = 1;
uchar foodx, foody;
uchar d, xx, yy;


char key = 0;

void delay(uint z)
{
	uint x, y;
	for (x = z; x > 0; x--)
		for (y = 114; y > 0; y--);
}

void keyscan()
{
	if (key_s2 == 0)
	{
		delay(10);
		if (key_s2 == 0)
		{
			if (key != 4)
				key = 1;
		}
	}
	if (key_s3 == 0)
	{
		delay(10);
		if (key_s3 == 0)
		{
			if (key != 3)
				key = 2;
		}
	}
	if (key_s4 == 0)
	{
		delay(10);
		if (key_s4 == 0)
		{
			if (key != 2)
				key = 3;
		}
	}
	if (key_s5 == 0)
	{
		delay(10);
		if (key_s5 == 0)
		{
			if (key != 1)
				key = 4;
		}
	}
}


void SendByte(uchar x, uchar y)//用来接收行列值,这里x和y是坐标,点阵屏左下角为坐标原点
{
	uchar i, j, dat1, dat2;
	dat1 = coorx[x - 1];//这里通过前面定义的两个数组将坐标转化为了行列的十六进制数
	dat2 = coory[y - 1];
	for (i = 0; i < 8; i++)
	{
		if (dat1 & 0x01)
			DIO = 1;
		else
			DIO = 0;
		S_CLK = 1;//穿行输入
		S_CLK = 0;
		dat1 >>= 1;
	}
	for (j = 0; j < 8; j++)
	{
		if (dat2 & 0x01)
			DIO = 1;
		else
			DIO = 0;
		S_CLK = 1;//串行输入
		S_CLK = 0;
		dat2 >>= 1;
	}
	R_CLK = 1;//并行输出
	R_CLK = 0;
}

uchar CheckFood()//检验食物有没有和蛇体重合
{
	uchar i;
	for (i = 0; i < len; i++)
	{
		if (foodx == snakex[i] && foody == snakey[i])
		{
			return 1;
		}
	}
	return 0;
}

void creat_food()
{
	do
	{
		foodx = (uchar)(rand() % 8 + 1);
		foody = (uchar)(rand() % 8 + 1);
	} while (CheckFood() != 0);
}

void FoodAnd()//检验食物有没有被吃掉
{
	if (foodx == snakex[0] && foody == snakey[0])
	{
		if (len < 20)
		{
			snakex[len] = snakex[len - 1];//和之前一样,把上一个结点的状态赋给下一个结点,用来增加长度
			snakey[len] = snakey[len - 1];
			len++;
		}
		creat_food();//被吃掉重新生成食物
	}
}

void left()//上下左右都是一个道理
{
	uchar i, x1, x2, y1, y2;
	x1 = snakex[0];//保留上一结点的x轴状态
	snakex[0]--;//坐标减1
	if (snakex[0] == 0)//这里是判定是否碰到边界了,这里设定的是可以从另一边出来,当然也可以设定为碰到就死
		snakex[0] = 8;
	y1 = snakey[0];//保留上一结点的y轴状态
	for (i = 1; i < len; i++)
	{
		y2 = snakey[i];//进行各个结点的状态移动,形成蛇运动的效果
		snakey[i] = y1;
		y1 = y2;

		x2 = snakex[i];
		snakex[i] = x1;
		x1 = x2;
	}
}

void up()
{
	uchar i, x1, x2, y1, y2;
	y1 = snakey[0];
	snakey[0]--;
	if (snakey[0] == 0)
		snakey[0] = 8;
	x1 = snakex[0];
	for (i = 1; i < len; i++)
	{
		x2 = snakex[i];
		snakex[i] = x1;
		x1 = x2;

		y2 = snakey[i];
		snakey[i] = y1;
		y1 = y2;
	}
}

void down()
{
	uchar i, x1, x2, y1, y2;
	y1 = snakey[0];
	snakey[0]++;
	if (snakey[0] == 9)
		snakey[0] = 1;
	x1 = snakex[0];
	for (i = 1; i < len; i++)
	{
		y2 = snakey[i];
		snakey[i] = y1;
		y1 = y2;

		x2 = snakex[i];
		snakex[i] = x1;
		x1 = x2;
	}
}

void right()
{
	uchar i, x1, x2, y1, y2;
	x1 = snakex[0];
	snakex[0]++;
	if (snakex[0] == 9)
		snakex[0] = 1;
	y1 = snakey[0];
	for (i = 1; i < len; i++)
	{
		x2 = snakex[i];
		snakex[i] = x1;
		x1 = x2;

		y2 = snakey[i];
		snakey[i] = y1;
		y1 = y2;
	}
}

void CheckDead()
{
	uchar i;
	for (i = 2; i < len; i++)
	{
		if (snakex[0] == snakex[i] && snakey[0] == snakey[i])
		{
			while (1);
		}
	}
}

void snakemove()
{
	if (key == 1 && m == 100)//这里是判断按键值并且m要达到100,也就是500ms移动一次
	{
		left();
		m = 0;//要清一下零
	}
	if (key == 2 && m == 100)
	{
		up();
		m = 0;
	}
	if (key == 3 && m == 100)
	{
		down();
		m = 0;
	}
	if (key == 4 && m == 100)
	{
		right();
		m = 0;
	}
}

void timer0Init()
{
	EA = 1;
	ET0 = 1;
	TR0 = 1;
	TMOD = 0X01;
	TH0 = 0XED;
	TL0 = 0XFF;
}

void main()
{
	timer0Init();//定时器0初始化
	snakex[0] = 5;//蛇体初始x坐标
	snakey[0] = 5;//蛇初始y坐标
	creat_food();
	while (1)
	{
		snakemove();
		FoodAnd();
	}
}

void timer0() interrupt 1
{
	TH0 = 0XED;
	TL0 = 0XFF;
	m++;//每加到一百蛇体移动一次,速度可以自己调
	keyscan();//键盘扫描
	for (d = 0; d < len; d++)
	{
		SendByte(snakex[d], snakey[d]);//将蛇体显示在点阵屏上,参数是xy坐标
	}
	SendByte(foodx, foody);//显示食物
	CheckDead();//检验是否死亡
}

总结

代码由于本人实力问题还有部分不足之处希望支持。文章来源地址https://www.toymoban.com/news/detail-721764.html

到了这里,关于51单片机实现贪吃蛇(清翔单片机)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 嵌入式51单片机04-矩阵按键系列

    一、矩阵按键基础知识 矩阵按键工作原理 : 逐行扫描 :通过高四位轮流输出低电平来对矩阵键盘进行扫描,当低四位接收到的数据不全为1的时候,说明有按键按下,然后通过判断低四位数据中哪一位为零来判断哪一个按键被按下。 逐列扫描 :通过低四位轮流输出低电平来

    2024年02月07日
    浏览(61)
  • 嵌入式硬件与51单片机:演变、挑战与未来

    导言:         嵌入式硬件及其代表之一的51单片机在电子领域扮演着至关重要的角色。本文将深入剖析这一领域的发展历程,包括初期的崛起、面临的挑战、重大公关危机、核心业务、当前研究方向、采用的技术、实际应用场景、未来展望,并提供相关链接,为读者呈现

    2024年01月24日
    浏览(49)
  • 【单片机毕设选题】stm32实现车牌识别系统 -物联网 嵌入式 单片机

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月20日
    浏览(55)
  • 嵌入式单片机——60秒计时器的实现

    1.设计秒计时器,要求实现60秒计时,用2位LED数码管显示。 2.按键K1,实现秒表的停止和启动。

    2024年02月03日
    浏览(46)
  • 毕业设计 - 基于单片机的智能饮水机系统设计与实现 (物联网 嵌入式 单片机)

    Hi,大家好,学长今天向大家介绍一个 单片机项目 基于单片机的智能饮水机系统设计与实现 大家可用于 课程设计 或 毕业设计 这次设计的智能饮水机就是单片机结合传感器的一个应用。 该系统设计综合单片机以及电子技术理论,从生活实际出发,完善了饮水机的功能。整个

    2024年02月03日
    浏览(105)
  • 单片机项目分享 单片机自动写字机器人设计与实现 - 物联网 嵌入式 stm32

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月21日
    浏览(89)
  • 【单片机毕设选题】 单片机自动写字机器人设计与实现 - 物联网 嵌入式 stm32

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月02日
    浏览(59)
  • 【Proteus仿真】【51单片机】贪吃蛇游戏

    本项目使用Proteus8仿真51单片机控制器,使用8*8LED点阵、按键模块等。 主要功能: 系统运行后,可操作4个按键控制小蛇方向。 B站演示视频:https://space.bilibili.com/444388619 视频地址:https://space.bilibili.com/444388619/video 专注于51单片机、STM32、国产32、DSP、Proteus、arduino、ESP32、物联

    2024年02月06日
    浏览(46)
  • 嵌入式毕设分享 基于单片机的智能音响设计与实现 -物联网 嵌入式 stm32

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月22日
    浏览(58)
  • 物联网项目分享 stm32实现车牌识别系统 -物联网 嵌入式 单片机

    🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天

    2024年02月21日
    浏览(69)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包