基于STC89C52的贪吃蛇(用74hc595和P1口。P1口可用74hc138代替)

(代码的话我其实是基本复制了一位网友的代码)
说法一:其实单色点阵LED本无所谓共阳还是共阴,如此命名多半是因为行业习惯造成的。市面上对8*8点阵LED所谓的共阳还是共阴的说法一般是根据点阵第一个引脚的极性所定义的,第一个引脚为阳极则为共阳,反之则为共阴。

说法二:卖家所说的共阴或者共阳确切的说应该是行共阴或者行共阳
在这里插入图片描述
在这里插入图片描述

从这两张图片上我们看到第一脚是在第一行的,所以这两种说法其实是一样的

下面说说点阵的一些基本知识

管脚的定义:

有的点阵后面标有第一脚,但是有的没有标,现在大家默认跟IC的管脚顺序一样,读法是第1脚一般在侧面有字的那一面,字是正向时左边第一脚为1,然后按逆时针排序至16脚,如图示:

共阴共阳的疑问解答以及8*8点阵基础知识讲解

行列定义
在这里插入图片描述
在这里插入图片描述

8*8点阵内部结构

行共阴
在这里插入图片描述

行共阳
在这里插入图片描述

上图中也标出了ark sz410788k点阵每行每列对应的管脚号,我目前不敢确定的是是否所有的8*8点阵管脚对应的行列都和ark 点阵是一样的,但是我目前使用过的两三种点阵的对应顺序都和上面两个图示一样的!

共阴共阳的疑问解答以及8*8点阵基础知识讲解

如果确实搞不定管脚顺序,可以拿一个指针式万用表检测

具体测定引脚步骤如下(可使用万用表或其他电压源测试,我使用的是机械式的万用表)

1.【定正负极】把万用表拨到电阻档×10,先用黑色探针(输出高电平)随意选择一个引脚,红色探针碰余下的引脚,看点阵有没发光,没发光就用黑色探针再选择一个引脚,红色探针碰余下的引脚,当点阵发光,则这时黑色探针接触的那个引脚为正极,红色探针碰到就发光的7个引脚为负极,剩下的6个引脚为正极。

2.【引脚编号】先把器件的引脚正负分布情况记下来,正极(行)用数字表示,负极(列)用字母表示,先定负极引脚编号,黑色探针选定一个正极引脚,红色点负极引脚,看是第几列的二极管发光,第一列就在引脚写A,第二列就在引脚写B,第三列…以此类推。 这样就点阵的一半引脚都编号了。剩下的正极引脚用同样的方法,第一行的亮就在引脚标1,第二行就在引脚标2,第三行…以此类推。

#include<reg51.h>//51头文件
#include<intrins.h>//使用到_nop_()延时函数要包括这个头文件
#include<stdlib.h>//使用到了rand()函数(要用这个头文件)

#define u16 unsigned int //用u16  代替unsigned int(简化)
#define u8 unsigned char //用u8  代替unsigned char(简化)

//595IO口定义
sbit SER=P3^7;
sbit RCLK=P3^6;
sbit SRCLK=P3^5;
//按键IO口定义
sbit up=P2^1;
sbit down=P2^2;
sbit lt=P2^3;
sbit rt=P2^0;

u8	code Hc595_Coordx[]={
    
    0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};//给0
u8	code Hc595_Coordy[]={
    
    0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};//给1
u8	 foodx;//食物的X坐标
u8   foody;	//食物的y坐标
u8   snake_x[20]={
    
    0};//最大长度
u8   snake_y[20]={
    
    0};
u8 length;//储存蛇长
u8 direction;//方向	(2为向下,1位向上,3向左,4向右)

void initSnake();//初始化函数
void delay(u16 i);//延时函数
void Hc595SendByte(u8 dat);//595发送数据函数
void move();//移动
void Keypros();//按键控制函数
void creatFood();//创建食物函数
void snake_Grow(void);//长大函数
void drawsnake();//点亮食物和蛇的函数
void JudgeDeath(void);//判断是否撞到自己或者墙
void Timer0Init();//定时器0初始化函数

void initSnake()
{
    
    
  	snake_x[0]=0;//初始话蛇的位置为第0行第0列
	snake_y[0]=0;
	length=1;//初始化长度为两个点
	direction=2;//初始化运动方向为向下
}

void delay(u16 i)
{
    
    
  while(i--);
}

void Hc595SendByte(u8 dat)
{
    
    
	u8 a;
	SRCLK=0;
	RCLK=0;
	for(a=0;a<8;a++)
	{
    
    
		SER=dat>>7;//从高位开始发送(把低7位移走,以此类推)
		dat<<=1; //左移一位把最高位去掉,发送次高位(以此类推)

		SRCLK=1;//srclk一个上升沿数据进入移位寄存器
		_nop_();
		_nop_();
		SRCLK=0;	
	}

	RCLK=1;	//rclk一个上升沿将数据输出到并行串口
	_nop_();
	_nop_();
	RCLK=0;
}


void move()
{
    
    
     
    u8 len = length- 1;
	//length减一的原因(设长度为7,则len为6到1,蛇头不算)
    for(len; len > 0; len--)
    {
    
    
        snake_x[len] = snake_x[len - 1];//将蛇尾后的点移动到前一个点
        snake_y[len] = snake_y[len - 1];//一直到蛇头
    }
    switch(direction)
    {
    
    
	    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 Keypros()
{
    
    
	if(up==0)
	{
    
    
		delay(1000);  //消抖处理
		if(up==0)
		{
    
    
		  if(direction==3|direction==4)//如果是向左或是向右移动的情况下
		  direction=1;             //在地址1内写入数据num
		}
		while(!up);//判断按键是否松开
	}
	if(down==0)
	{
    
    
		delay(1000);  //消抖处理
		if(down==0)
		{
    
    	if(direction==3|direction==4)//如果是向左或是向右移动的情况下
			direction=2;	  
		}
		while(!down);
	}
	if(lt==0)
	{
    
    
		delay(100);  //消抖处理
		if(lt==0)
		{
    
    
		    if(direction==1|direction==2)//如果是向下或是向上移动的情况下
			direction=3; 
		}
		while(!lt);
	}
	if(rt==0)
	{
    
    
		delay(1000);  //消抖处理
		if(rt==0)
		{
    
    
		   if(direction==1|direction==2)//如果是向下或是向上移动的情况下
		   direction=4; 
		}
		while(!rt);
	}		
}

void creatFood()	 //随机创造食物
{
    
    
    u8 i;
    foodx=rand()%8;//随机取数为0到8给食物的x的坐标
    foody=rand()%8;//随机取数为0到8给食物的y的坐标
	delay(0);//延时一会
    for(i=0; i<length; i++)//在蛇长范围内如果食物与蛇身重叠(小于等于蛇长)
    {
    
    
        if((foodx==snake_x[i])&&(foody==snake_y[i]))	
        {
    
    	//如果食物与蛇的身体重叠,要重新创建
            creatFood();
        }       
    }
}

void snake_Grow(void)
{
    
    
    if(snake_x[0] == foodx && snake_y[0] == foody)
    {
    
    	//如果蛇头碰到食物蛇长+1,然后重新创建食物
		//将蛇尾加长
        creatFood();
        snake_x[length] = snake_x[length - 1];
        snake_y[length] = snake_y[length - 1];
        length++;//长度加一
    }
}


void drawsnake()   //点亮蛇和食物
{
    
    
     u8	i;
     for(i=0;i<length;i++)
	{
    
    
	  	Hc595SendByte(Hc595_Coordy[snake_y[i]]);//595控制x坐标(发送y坐标)
		P1=Hc595_Coordx[snake_x[i]];//P0口控制x坐标(发送x坐标)
		//P0口可以改用74hc138译码器,同样有效
        delay(0);//延时一会
		P1=0xff;//消影

	    Hc595SendByte(Hc595_Coordy[foody]);   
	    P1=Hc595_Coordx[foodx];
		delay(0);//延时一会
	    P1=0xff;//消影		
	}
}

void JudgeDeath(void)
{
    
    
    u8 i;

    // 判断蛇撞墙死亡
    if((snake_x[0]>7)||(snake_y[0]>7))
    {
    
    
         Hc595SendByte(0x00);
        while(1);
    }

    // 判断蛇撞到自己身体死亡
    for(i=5; i<length; i++)//为什么i要大于4?
    {
    
    
		//当蛇的长度超过4的时候才会有可能撞到自己
        if((snake_x[0]==snake_x[i])&&(snake_y[0]==snake_y[i]))
        {
    
    
            P1=0xFF;
            while(1);
        }
    }
}


void Timer0Init()
{
    
    
	TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。

	TH0=0XD8;	//给定时器赋初值,定时10ms
	TL0=0XF0;	
	ET0=1;//打开定时器0中断允许
	EA=1;//打开总中断
	TR0=1;//打开定时器	
			
}

void main()
{
    
       
   
	Timer0Init();
	initSnake();	
	while(1)
	{
    
     
		drawsnake();
		JudgeDeath();
		snake_Grow();
		Keypros();
	}

}

void Timer0() interrupt 1
{
    
    
	static u16 i;
	TH0=0XD8;	//给定时器重新赋初值,定时10ms
	TL0=0XF0;
	i++;
	if(i==50)//当到达500ms时移动一下(改变这里可以改变速度)
	{
    
    
		i=0;
		move();
	}	
}

猜你喜欢

转载自blog.csdn.net/qq_45774073/article/details/109037075