历史上的今天
返回首页

历史上的今天

今天是:2025年04月01日(星期二)

正在发生

2020年04月01日 | 基于51单片机开发板8*8LED矩阵的贪吃蛇程序

2020-04-01 来源:eefocus

引语:过年的时候闲着无聊,恰好也刚学了点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矩阵显示的是乱码。

推荐阅读

史海拾趣

Crocus公司的发展小趣事

XXXX年,Crocus迎来了发展的重要转折点——与Allegro MicroSystems达成合并协议。这次合并不仅为Crocus带来了雄厚的资金支持和更广阔的市场空间,还实现了双方在技术、产品和市场等方面的优势互补。合并后的Crocus在TMR传感器领域取得了更加显著的成果,进一步巩固了市场地位。

晨晶电子(Chenjing Electronics)公司的发展小趣事

晨晶电子始终将品质放在首位,坚持以客户为中心的服务理念。公司建立了严格的质量管理体系,从原材料采购到生产过程控制,再到产品出厂检验,每一个环节都严格把关,确保产品的品质稳定可靠。正是凭借这种对品质的执着追求,晨晶电子赢得了客户的广泛认可和好评,也为企业赢得了良好的口碑。

Ericsson Power Modules公司的发展小趣事

在创立初期,Ericsson Power Modules就展现出了强大的技术创新能力。公司团队通过深入研究电源技术、电路板应用和系统知识,成功开发出了一系列高性能、高效率的电源模块产品。其中,DC-DC转换器、中级和先进总线转换器、POL稳压器等产品因其卓越的性能和稳定性,在市场上赢得了广泛好评。这些技术突破和产品创新为Ericsson Power Modules的后续发展奠定了坚实的基础。

GMT(致新科技)公司的发展小趣事
如果电源正常,应检查时间控制芯片或MCU是否工作正常。可以使用万用表等工具测量其供电电压、输出信号等是否正常。
Comax Industrial Co Ltd公司的发展小趣事

在电子产品市场竞争日益激烈的背景下,Comax Industrial Co Ltd公司始终坚持品质至上的原则。公司建立了严格的质量管理体系,从原材料的采购到生产制造的每一个环节都进行严格把控。通过持续改进和优化生产流程,公司不断提升产品的品质与性能。这种对品质的执着追求,使得Comax的产品在市场上赢得了广泛的认可与信赖。

General Instrument Corp公司的发展小趣事
ML2281系列变换器的转换时间低至6µs,适用于需要快速数据采集的系统。

问答坊 | AI 解惑

AMD开始实行“轻晶圆”战略

AMD有可能在本月末宣布其奉行“轻晶圆厂”策略的大动作,包括转手其Dresden晶圆厂,接受来自一家中东财团的投资组建一家新公司。 在Austin美国发言人John Lau和Jefferies共同发表一份投资分析报道中指出,其智囊团认为AMD正寻找买主,打算抛售其在D ...…

查看全部问答>

multisim10中AD转换求助

我用max1183做AD转换的仿真时,芯片输出始终是0,百思不得其解,求高手们帮帮忙看看啊,谢谢! xuwq2@163.com…

查看全部问答>

急!!!如何让我开发的WDM驱动程序在双核的机器中只运行在单核上?

我们一张PCI卡里面一块芯片的读写只支持在单核上运行,这样在双核机器上要强制让操作系统运行在单CPU模式下才可正确使用,我用的操作系统是Windows Vista. 请问我应该怎样通过编程的方式让我的驱动程序能内在的指定运行在单核上?…

查看全部问答>

高粘度液位传感器&耐压接近开关~求解决方案!

大虾们好!最近最一个产品,测试一个润滑脂的低液位报警,就是提醒要加料了! 装在直径200mm,高度75mm(这个很小)还有高度250mm的塑料桶里面。桶底有一个直流电机带动的刮板。 润滑脂粘度很大,类似于黄油,稍微稀一点,流动性很小。 用音叉肯 ...…

查看全部问答>

LPC11C14 IO口输出问题

我有一块LPC11C14的板子,但是0.5和0.4都不能作为IO口输出,请大家帮忙分析有哪些硬件上的影响。代码没问题,芯片没问题…

查看全部问答>

请问STM32在休眠模式下怎么使用看门狗?

城主及大家好. 请问STM32在休眠模式下怎么使用独立看门狗? 手册上说可以在休眠模式下工作,但看门狗需要喂吧?在停止模式下怎么喂呢? 应用中要用到休眠模式,但又要用到看门狗,该怎样解决呢? 另外.独立看门狗打开后能否关闭呢? 谢谢大家.…

查看全部问答>

【求助】中断函数为什么不能修改全局变量的值

定义了全局变量,在中断函数中赋值。在主程序中全局变量的值为何没有变。请各位大侠指教,不胜感激!结果是 ser=0!!!!! #include <msp430x14x.h> unsigned char a[6]; unsigned char b[6]; unsigned char n; unsigned char pt; unsigned ...…

查看全部问答>

【项目外包】飞思卡尔I.MX53软硬件平台

飞思卡尔I.MX53软硬件平台 项目预算:¥ 50,000~80,000 开发周期: 90天 项目分类: android 竞标要求: 项目标签: java ANDROID ...…

查看全部问答>

那位朋友推荐SOP8 单片机第8脚VCC的吗?

那位朋友推荐SOP8  单片机第4脚地,第8脚VCC的吗??急的呀???有多少推多少的?小弟谢谢的啦…

查看全部问答>

STM32 IAP

调试基本正常,现在遇到一个问题,下载好应用程序后,跳转到应用程序,好像进入了hardfault,不跑应用程序. 下载程序后,必须重新启动单片机才一切正常,能正常跑应用程序.我想了办法,下载完程序后,打开单片机的看门狗,让单片机的看没看复位单片机,还是不 ...…

查看全部问答>