基于51单片机开发板8*8LED矩阵的贪吃蛇程序

2020-04-01来源: eefocus关键字:51单片机  8*8  LED矩阵  贪吃蛇程序

引语:过年的时候闲着无聊,恰好也刚学了点51开发板的东西,所以就想写一个贪吃蛇的小程序。在网上总结了一些关于贪吃蛇的算法,于是就有了以下的程序。


先来说以一下算法的原理:将8*8LED看作是直角坐标系,将左上角定为坐标原点。定义两个数组  snake_x[],snake_y[]用来存储蛇的x,y轴坐标。因此,我们的核心算法就是小蛇惯性保持自己的运动姿态,产生食物,以及小蛇吃到食物后长度增加。


再来看一下我的开发板,我的开发板是德飞莱51开发板,这里不再讲解其8*8LED的工作原理,直接上代码


void Hc595SendByte()

{

unsigned char a;

SRCLK=0;

RCLK=0;

for(a=0;a<8;a++)

{

SER=CHARCODE[p_now][a];

SRCLK=1;

_nop_();

_nop_();

SRCLK=0;

}

 

 RCLK=1;

 _nop_();

 _nop_();

 RCLK=0;

}

void Display()

{

 unsigned int tab;

 for(tab=0;tab<8;tab++) //扫描8列

{

Hc595SendByte_clean(0x00); //消隐

COMMONPORTS= TAB[tab]; //输出字码

Hc595SendByte(); //写入一个直字节数据 

p_now++; //扫描下一行

if(p_now == 8) //扫描8行后归零

{

p_now = 0; //伪指针归零

}

}

}


这里定义了两个函数 Hc595SendByte ()和Display()两个函数,其中CHARCODE[x][y]数组是用来存放LED的状态值的。0x00代表灭,0x01代表亮。因此,在整个程序中,如果想将小蛇或食物显示在LED上,只需将相关点的坐标作为数组括号内的两个常量表达式,并将其赋值0x00或0x01即可。


在void Auto_Move()函数中,


void Auto_Move()

{

 unsigned char i;

 if(Time==10) //蛇500ms移动一下

temp_x = snake_x[0]; //蛇尾坐标临时存储

temp_y = snake_y[0];

for(i=0;i

{

snake_x[i] = snake_x[i+1];

snake_y[i] = snake_y[i+1];

}

snake_x[snake_long] = x; //蛇头坐标临时存储

snake_y[snake_long] = y;

switch(direction_flag)

{

case 16:

{//默认移动-向右即一开始适时,舍

x++;

temp_direction=direction_flag;

break;

         }

                case 1:

{//惯性制导-向上

y--;

temp_direction=direction_flag;

break;

                  }

                 case 4

                 {//惯性制导-向左                

                        x--;

                        temp_direction=direction_flag;

                        break;

                  }

                 case 6:{//惯性制导-向右 

                 x++;

                 temp_direction=direction_flag;

                 break;

                 }

                 case 9:{//惯性制导-向下

                 y++;

                 temp_direction=direction_flag;

                 break;

                 }

                 default:

                 {direction_flag=temp_direction;//按键按错时修正运动方向

switch(direction_flag)

 {

 case 1:{y--;break; //修正-向上

}

case 4:{x--;break; //修正-向左

}

case 6:{x++;break; //修正-向右

}

case 9:{y++;break; //修正-向下

}

case 16:{x++;break; //修正-默认

}

 }

break;

 }

 }


Auto_move()函数是本程序的核心,关于他具体怎么实现小蛇的移动,程序的注释已经写的很清楚。


接下来就是定义产生食物的函数。这个函数内部运用了rand()随机函数,用来产生随机的食物位置。food_x和food_y是食物的横纵坐标。


void Food()

{

 if(food_flag>0)

 {

food_x=rand()%7; //伪随机数-食物横坐标(0-7之间)

food_y=rand()%7; //伪随机数-食物纵坐标(0-7之间)

CHARCODE[food_x][food_y]=0x01;//在地图中显示食物

food_flag=-food_flag; //食物产生标志翻转

}

}


接下来是小蛇长度变长的函数


void Eating()

{

 if(food_flag<0&&snake_x[snake_long]==food_x&&snake_y[snake_long]==food_y)//小蛇的头部坐标如果等于食物的坐标,那么则说明小蛇吃到食物

{

snake_long++; //蛇身加长,即增加小蛇数组常量表达式的值

switch(direction_flag)

{

 case 1:{

 snake_x[snake_long]=food_x; //将惯性运动下一个坐标点亮增加蛇长

snake_y[snake_long]=food_y-1;

 break;

 }

 case 4:{

 snake_y[snake_long]=food_y; //将惯性运动下一个坐标点亮增加蛇长

snake_x[snake_long]=food_x-1;

 break;

 }

 case 6:{

 snake_y[snake_long]=food_y; //将惯性运动下一个坐标点亮增加蛇长

snake_x[snake_long]=food_x+1;

 break;

 }

 case 9:{

 snake_x[snake_long]=food_x; //将惯性运动下一个坐标点亮增加蛇长

snake_y[snake_long]=food_y+1;

 break;

 }

 }

 

CHARCODE[food_x][food_y]=0x00;//清除食物

 

food_flag=-food_flag; //产生新的食物

 

}


仅看注释已经可以明白该段程序。


下面是程序相关变量的定义以及函数的声明部分。


#ifndef _DEFINITION_H

#define _DEFINITION_H

#include //库调用及宏

#include 

#include

#include

#define COMMONPORTS P0 //LED位码IO口

#define GPIO_KEY P1 //矩阵键盘IO口

 

sbit SRCLK=P3^6; //74HC595控制端口

sbit RCLK=P3^5;

sbit SER=P3^4; 

int x=1,y=3; //蛇头初始坐标

int temp_x=0,temp_y=0; //蛇尾初始坐标

int food_x,food_y; //食物坐标

int food_flag=1; //食物产生标志

unsigned char temp_direction; //方向矫正

unsigned char snake_long=1; //蛇身长-初始为2 

unsigned char Time=0; //用于定时累计

unsigned char p_now=0; //伪指针(点阵需横向扫描8次) 

unsigned char KeyValue=16; //矩阵键盘键值存储

unsigned char direction_flag=16; //惯性移动方向标志

 

unsigned char snake_x[10]={0,1}; //蛇的横坐标 蛇的最长长度为10

unsigned char snake_y[10]={3,3}; //蛇的纵坐标

 

unsigned char code TAB[8] = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};//LED位码

unsigned char CHARCODE[8][8]= //地图

{

{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},

{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},

{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},

{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},

{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},

{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},

{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},

{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}

};

#endif

#ifndef _FUNCTION_H

#define _FUNCTION_H

void Hc595SendByte();

void Hc595SendByte_clean(unsigned char);//消隐函数,SER=0x00

void Delay10ms();

void KeyDown();//按键扫描函数,上下左右四个方向键

void WALL();//小蛇撞到墙后,从另一边出来

void Direction();//上下左右四个方向键,对应四个direction_flag

void Auto_Move();

void Food();

void Eating();

void INIT();//定时器函数,用于扫描LED

void Display();

void Distory();//小蛇的头部坐标等于蛇身的某处坐标时,则触发bee()函数,并停止小蛇移动

void bee();//蜂鸣器函数

#endif


好了,现在你应该可以将剩下的代码完成了。


现在这个代码还有不够完善的地方,比如在实际运行的时候,小蛇的长度达到定义的长度以后就无法继续向下移动,或者是LED矩阵显示的是乱码。

关键字:51单片机  8*8  LED矩阵  贪吃蛇程序 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic493113.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:使用51单片机和MAX7219控制点阵滚动显示
下一篇:51单片机---点亮LED灯

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

51单片机串行口及存储器工作原理分析
一、 51单片机串行口工作原理MCS-51系列单片机片内有一个串行I/O端口,通过引脚RXD(P3.0)和TXD(P3.1)可与外设电路进行全双工的串行异步通信。1.串行端口的基本特点8031单片机的串行端口有4种基本工作方式,通过编程设置,可以使其工作在任一方式,以满足不同应用场合的需要。其中,方式0主要用于外接移位寄存器,以扩展单片机的I/O电路;方式1多用于双机之间或与外设电路的通信;方式2,3除有方式l的功能外,还可用作多机通信,以构成分布式多微机系统。串行端口有两个控制寄存器,用来设置工作方式、发送或接收的状态、特征位、数据传送的波特率(每秒传送的位数)以及作为中断标志等。串行端口有一个数据寄存器SBUF(在特殊
发表于 2020-06-07
51单片机串行口及存储器工作原理分析
51单片机1s延时程序设计
; 号}//=======以下非代码==========//原理,利用h,i,j,k循环指令消耗掉一定时间来达到延时,为什么利用循环延时的做法,在12M晶振延时1秒中需要h,i,j,k四个变量,且各变量的值是上面代码中那样呢?这要从单片机的周期说起,单片机有指令周期,机器周期,状态周期,时钟周期;时钟周期:也就晶振的振荡周期,以12MHz为例,时钟周期为 1/ 12000000 = 1/12us;机器周期:1个机器周期=6个状态周期=12个时钟周期=1us;指令周期:单片机执行一条指令所需要的时间称为指令周期,指令周期是以机器周期为单位的,不同的指令所需要的机器周期不一定相同(1-4个),单片机执行一条单周期指令需要1us,执行
发表于 2020-06-06
51单片机1s延时程序设计
MCS-51单片机的程序状态寄存器PSW有什么用?
PSW是一个8位寄存器,用于设定CPU的状态和指示指令执行后的状态。CY(PSW.7):进位标志。在执行加减运算指令时,如果运算结果的最高位(D7)发生了进位或借位,则CY由硬件自动置1。AC(PSW.6):半进位标志位,也称为辅助标志位。在执行加减运算指令时,如果运算结果的低半字节(D3)发生了向高半字节进位或借位,则AC由硬件自动置1。F0、F1(PSW.5 和PSW.1):用户标志位。用户可以根据需要对F0、F1赋予一定的含义,由用户置1和清0,作为软件标志。RS1、RS0(PSW.4 和PSW.3):工作寄存器组选择控制位。通过对这两位设定,可以从4个工作寄存器组中选择一组作为当前工作寄存器。OV(PSW.2):溢出标志位,
发表于 2020-06-04
MCS-51单片机的程序状态寄存器PSW有什么用?
键盘电路实例分析:上拉电阻错误导致51单片机无法正常运行
在电路设计中,为了将电阻钳位维持在高电平,会借助上拉电阻来实现电阻的稳定,因此上拉电阻开始大量出现在电路设计中。本文从以键盘电路实例为切入点,为大家分析一种由于上拉电阻位置原因导致51单片机电路无法正常运行的情况。首先让我们来看一看这个键盘电路的原理图,如图1所示。图1在按键没有被按下时,端口为低电平,按下按键的时候端口上接高电平。但电路却没有正常工作,出现了问题。下面就来分析一下问题所在。首先,将电源直接接到端口上是绝对不可以的。当按下按键时,会有很大的电流进入单片机。在工程上,这种往往应该加限流电阻,一般选择1K即可。但也不能选择太大的电阻,因为电阻上面压降太大,造成输入低于应有的高电平,造成错误。其次,即便添加限流,电路也是
发表于 2020-06-04
键盘电路实例分析:上拉电阻错误导致51单片机无法正常运行
51单片机扩充串行口的方法
基本的 51 单片机有四个并行口,其中还包含了一个串行口。当接口不够用的时候,大家就会想到,使用什么外接芯片来扩充。但是,各种教材、参考书、网络文章,介绍扩充并行口的花样不少,扩充串行口的方法,几乎无人问津。偶尔见到一个,也是使用 8250、8251 等“巨型”芯片来扩充的使用这些芯片,就要占用单片机很多的更为紧缺的并行口,基本上就是得不偿失。更别说还要设置复杂的控制字了。使用简单的三态门,即可为单片机扩充串行口,仅仅占用单片机的一、二个引脚作为控制引线而已。实际上是很简单的,就像使用 74LS373、74LS244 扩充并行口一样,为串行口,配上合适三态门就行了。选用 74LS125(低电平开门)、74LS126
发表于 2020-06-04
51单片机扩充串行口的方法
用软件编程的方法来模拟51单片机产生PWM波
65536个数,假设我们转入的初值为65534,那么定时器计两个数就会进入中断,这样会使程序紊乱而其他功能无法正常地执行,所以一般要留50-100个数的裕量。2.2 定时器工作方式在定时器工作方式的选择上,可以选择定时器的工作方式0、1、2都可以,本文采用的是工作方式1,即16位定时器,这样可以获得较宽的调频范围。2.3 定时器初值的计算设占空比为α,频率为f产生高电平时装入定时器高8位的值应为产生高电平时装入定时器低8位的值应为显然,产生低电平时的公式只要把α换成(1-α)就行了。然而在51单片机中,浮点数运算需要消耗cpu很长的时间,为了提高程序效率,通常用100倍的占空比来计算。同时,要注意数据类型,避免超出范围,影响计算结果
发表于 2020-06-04
用软件编程的方法来模拟51单片机产生PWM波
小广播
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2020 EEWORLD.com.cn, Inc. All rights reserved