2021.12创客杯大一组题目 基于51的贪吃蛇小游戏

 如图所示为原理图,@小华同学画的

测试出的点阵相应引脚,很乱……

 

话不多说直接上代码,添加了一些注释

#include "reg52.h"
#include "stdlib.h"

typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;

sbit KEY_IN_1 = P2^7; //上
sbit KEY_IN_2 = P2^4; //下
sbit KEY_IN_3 = P2^6; //左
sbit KEY_IN_4 = P2^5; //右

u8 T0RH = 0;
u8 T0RL = 0;
u8 keysta[4] = {1,1,1,1};
u8 FoodPosition[2] = {4,5};   //初始化果子
u8 snake_x[32] = {0},snake_y[32] = {0};  //蛇身最大长度
u8 snakelong = 3;   //全局变量蛇长
u8 flag_x = 1;   //初始化移动方向,共有四种情况  1,0  -1,0  0,1  0,-1
u8 flag_y = 0;
u8 flag_g = 1; //初始化果子标志位
u8 flag_c = 0;   //吃到自己身体游戏结束
u8 flag_m = 1;  //蛇身移动位
u8 score = 0;//吃果分数
u8 code mtable[10]={0x01,0xb7,0x42,0x12,0x34,0x18,0x08,0xb3,0x80,0x10};//控制数码管显示0-9

void ConfigTimer0(unsigned int ms)//定时器配置,设置成1ms进入一次中断
{
	unsigned long tmp;
	
	tmp = 12000000/12;
	tmp = (tmp*ms)/1000;
	tmp = 65535 - tmp;
	T0RH = (unsigned char)(tmp>>8);
	T0RL = (unsigned char)tmp;
	EA = 1;
	TMOD &= 0XF0;
	TMOD |=0x01;
	TH0 = T0RH;
	TL0 = T0RL;
	ET0 = 1;    //T0中断使能
	TR0 = 1;
}

void delay(u16 i)//没有任何技术含量的延时函数
{
	while(i)
	{
		i--;
	}
}
//点阵坐标显示,因为引脚太乱了只能如此,一共64个坐标
void leddot(u8 snake_x,u8 snake_y)
{
	switch(snake_x){
	case 1:
	{
	    switch(snake_y){
			case 1 :P1 =  0xea;P3 =  0x2c ;break;
			case 2 :P1 =  0xe9;P3 =  0x2c ;break;
			case 3 :P1 =  0xcb;P3 =  0x2c ;break;
			case 4 :P1 =  0xeb;P3 =  0x0c ;break;
			case 5 :P1 =  0xab;P3 =  0x2c ;break;
			case 6 :P1 =  0xeb;P3 =  0x24 ;break;
			case 7 :P1 =  0xeb;P3 =  0x28 ;break;
			case 8 :P1 =  0xe3;P3 =  0x2c ;break;
			default:break;
		}
		break;
	}
	case 2:
	{
		switch(snake_y){
			case 1 :P1 =  0x6e;P3 =  0x2c ;break;
			case 2 :P1 =  0x6d;P3 =  0x2c ;break;
			case 3 :P1 =  0x4f;P3 =  0x2c ;break;
			case 4 :P1 =  0x6f;P3 =  0x0c ;break;
			case 5 :P1 =  0x2f;P3 =  0x2c ;break;
			case 6 :P1 =  0x6f;P3 =  0x24 ;break;
			case 7 :P1 =  0x6f;P3 =  0x28 ;break;
			case 8 :P1 =  0x67;P3 =  0x2c ;break;
			default:break;
		}
		break;
	}
	case 3:
	{
		switch(snake_y){
			case 1 :P1 =  0x6a;P3 =  0xac ;break;
			case 2 :P1 =  0x69;P3 =  0xac ;break;
			case 3 :P1 =  0x4b;P3 =  0xac ;break;
			case 4 :P1 =  0x6b;P3 =  0x8c ;break;
			case 5 :P1 =  0x2b;P3 =  0xac ;break;
			case 6 :P1 =  0x6b;P3 =  0xa4 ;break;
			case 7 :P1 =  0x6b;P3 =  0xa8 ;break;
			case 8 :P1 =  0x63;P3 =  0xac ;break;
			default:break;
		}
		break;
	}
	case 4:
	{
		switch(snake_y){
			case 1 :P1 =  0x7a;P3 =  0x2c ;break;
			case 2 :P1 =  0x79;P3 =  0x2c ;break;
			case 3 :P1 =  0x5b;P3 =  0x2c ;break;
			case 4 :P1 =  0x7b;P3 =  0x0c ;break;
			case 5 :P1 =  0x3b;P3 =  0x2c ;break;
			case 6 :P1 =  0x7b;P3 =  0x24 ;break;
			case 7 :P1 =  0x7b;P3 =  0x28 ;break;
			case 8 :P1 =  0x73;P3 =  0x2c ;break;
			default:break;
		}
		break;
	}
	case 5:
	{	
	   switch(snake_y){
			case 1 :P1 =  0x6a;P3 =  0x2d ;break;
			case 2 :P1 =  0x69;P3 =  0x2d ;break;
			case 3 :P1 =  0x4b;P3 =  0x2d ;break;
			case 4 :P1 =  0x6b;P3 =  0x0d ;break;
			case 5 :P1 =  0x2b;P3 =  0x2d ;break;
			case 6 :P1 =  0x6b;P3 =  0x25 ;break;
			case 7 :P1 =  0x6b;P3 =  0x29 ;break;
			case 8 :P1 =  0x63;P3 =  0x2d ;break;
		    default:break;
		}
	   break;
	}
	case 6:
	{
		switch(snake_y){
			case 1 :P1 =  0x6a;P3 =  0x6c ;break;
			case 2 :P1 =  0x69;P3 =  0x6c ;break;
			case 3 :P1 =  0x4b;P3 =  0x6c ;break;
			case 4 :P1 =  0x6b;P3 =  0x4c ;break;
			case 5 :P1 =  0x2b;P3 =  0x6c ;break;
			case 6 :P1 =  0x6b;P3 =  0x64 ;break;
			case 7 :P1 =  0x6b;P3 =  0x68 ;break;
			case 8 :P1 =  0x63;P3 =  0x6c ;break;
			default:break;
		}
		break;
	}
	case 7:
	{
	    switch(snake_y){
		    case 1 :P1 =  0x6a;P3 =  0x2e ;break;
			case 2 :P1 =  0x69;P3 =  0x2e ;break;
			case 3 :P1 =  0x4b;P3 =  0x2e ;break;
			case 4 :P1 =  0x6b;P3 =  0x0e ;break;
			case 5 :P1 =  0x2b;P3 =  0x2e ;break;
			case 6 :P1 =  0x6b;P3 =  0x26 ;break;
			case 7 :P1 =  0x6b;P3 =  0x2a ;break;
			case 8 :P1 =  0x63;P3 =  0x2e ;break;
			default:break;
		}
		break;
	}
	case 8:
	{
		switch(snake_y){
		    case 1 :P1 =  0x6a;P3 =  0x3c ;break;
			case 2 :P1 =  0x69;P3 =  0x3c ;break;
			case 3 :P1 =  0x4b;P3 =  0x3c ;break;
			case 4 :P1 =  0x6b;P3 =  0x1c ;break;
			case 5 :P1 =  0x2b;P3 =  0x3c ;break;
			case 6 :P1 =  0x6b;P3 =  0x34 ;break;
			case 7 :P1 =  0x6b;P3 =  0x38 ;break;
			case 8 :P1 =  0x63;P3 =  0x3c ;break;
			default:break;
		}
		break;
	}
	default:break;
  }
}

void appearsnake()  //显示蛇身
{
	u8 i = 0;
	for(i=0;i<snakelong;i++)					 //snakelong 是用来控制数组的全局关键变量
	{
		if((snake_x[i] != 0)||(snake_y[i] != 0))
		{
           leddot(snake_x[i],snake_y[i]);
	       delay(300);	   //延时,一次只显示一个点,利用视觉停留
		   P1 = 0x6b;
		   P3 = 0x2c;
	    }
     }
}

void keyaction(u8 dat)      //控制蛇头上下左右移动
{
	if(dat == 0)  //上
	{
		if(flag_x != -1){
			flag_x = 1;
			flag_y = 0;
		}
	}
	else if(dat == 1)   //下
	{
		if(flag_x != 1){
			flag_x = -1;
			flag_y = 0;
		}
	}
	else if(dat == 2)  //左
	{
		if(flag_y != -1){
			flag_x = 0;
			flag_y = 1;
		}
	}
	else if(dat == 3)  //右
	{
		if(flag_y != 1){
			flag_x = 0;
			flag_y = -1;
		}
	}
}

void keydriver()
{
	u8 i;
	static u8 backup[4] = {1,1,1,1};
	for(i = 0;i<4;i++)
	{
		if(keysta[i] != backup[i])
		{
			if(backup[i]!=0)   //上一次是弹起状态,则执行响应动作
			   keyaction(i);//这里才是执行动作的部分
			backup[i] = keysta[i];//更新按键状态
		}
	}
}

void KeyScan()//按键检测函数,软件消抖
{
	u8 i = 0;
	static u8 keybuf[4] = {0xFF,0xFF,0xFF,0xFF};
	
	keybuf[0] = (keybuf[0]<<1)|KEY_IN_1;
	keybuf[1] = (keybuf[1]<<1)|KEY_IN_2;
	keybuf[2] = (keybuf[2]<<1)|KEY_IN_3;
	keybuf[3] = (keybuf[3]<<1)|KEY_IN_4;
	
	for(i=0;i<4;i++)
	{
		if(keybuf[i] == 0x00)
			keysta[i] = 0;  //按键按下
		else if(keybuf[i] == 0xFF)
			keysta[i] = 1;  //按键弹起
	}
}

void appearguo()   
{
	u8 i,m,n;
	do{
		flag_g = 0;
		m = rand()%8+1;   //显示下一个果子
	  n = rand()%8+1;
		for(i=0;i<snakelong;i++)
		{	
			if((m == snake_x[i])&&(n == snake_y[i]))	 //如果果子和蛇身有重复,则flag_g置1,再生成一次                    
					flag_g = 1;		
		}
	}while(flag_g);
	FoodPosition[0] = m;
	FoodPosition[1] = n;
}

void move()//蛇移动,改变蛇的坐标
{
	u8 i;
	for(i = 0;i<snakelong-1;i++)
	{
		snake_x[i] = snake_x[i+1];
		snake_y[i] = snake_y[i+1];	
	}
	snake_x[i] += flag_x;	
	snake_y[i] += flag_y;	
	
	if(snake_x[snakelong-1]>8)			//穿墙判断  
		snake_x[snakelong-1] = 1;
	else if(snake_x[snakelong-1]<1)
		snake_x[snakelong-1] = 8;

	if(snake_y[snakelong-1]>8)
		snake_y[snakelong-1] = 1;
	else if(snake_y[snakelong-1]<1)
		snake_y[snakelong-1] = 8;
	flag_m = 0;
}

void chiguo()
{
	if((snake_x[snakelong-1]) == FoodPosition[0] && (snake_y[snakelong-1]) == FoodPosition[1])
	{
		TR0 = 0;
		snakelong++;
		score++;
		P0 = mtable[score];
		snake_x[snakelong-1] = FoodPosition[0]+flag_x;
		snake_y[snakelong-1] = FoodPosition[1]+flag_y;
		appearguo();
		TR0 = 1;
	}
}

void eatself()
{
	u8 i;
	
	for(i = 3;i<snakelong-1;i++)//判断蛇是否吃到自己的身体
	{
		if(snake_x[snakelong-1] == snake_x[i]&&snake_y[snakelong-1] == snake_y[i])
		{
			flag_c = 1;
			break;
		}
	}
}

int main()
{
	snake_x[0] = 1;
	snake_x[1] = 2;
	snake_x[2] = 3;
	snake_y[0] = 1;
	snake_y[1] = 1;
	snake_y[2] = 1;//初始化蛇身
	P0 = mtable[0];
	ConfigTimer0(1);//定时器0开始计时
	while(1)
	{
		if(!flag_c)		//蛇身移动位
		{
		  appearsnake();
		  keydriver();
		  if(flag_m)	  //蛇身死亡位
		   {
				move();
				chiguo();
				eatself();
				delay(300);
		   }
	    }
     }
 }

void Timer0() interrupt 1   //刷新点阵,按键
{
	static u16 index = 0;
	static u16 count = 0;
	TH0 = T0RH;
	TL0 = T0RL;

	KeyScan();
	index++;
	count++;
	if( index >= 400)//蛇移动的速度
	{
		flag_m = 1;
		index = 0;
	}
	if(!flag_c&&count>30)//果子显示频率
	{
		count = 0;
		leddot(FoodPosition[0],FoodPosition[1]);
	}
}

 稍微简单写了点,建议学弟学妹们先去学习一下C语言,数码管和点阵的显示原理以及单片机的定时器等,然后能更好的理解程序。另外希望大家保持一颗热爱的心,不管比赛结果如何,都能继续继续努力下去,唯有时间不会辜负你

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>