当前位置:首页 > 单片机 > 单片机
[导读]基于51单片机的贪吃蛇实例

 一、元器件

1、AT89C51

关于51单片机就不在啰嗦了,相信大家都已经很熟悉了。

2、8x8点阵

点阵里面就是一些二极管啦,通过纵横交叉连接,横8竖8,每个交叉点都接一个二极管。这里给大家找到一个点阵的实物图

 


 

我想大家看到这个图就应该知道如何去点亮一个点阵了。假如要点亮最左上角那个,那么9号引脚拉高,13号引脚拉低,这样既可。

二、原理图

 


 

 


 

三、项目分析

1、首先定义一个结构体

struct snake{

unsigned char x[20];

unsigned char y[20];

unsigned char length;

unsigned char direction;

}snk;

数组x,y分别存放每一个点的横纵坐标,length为蛇的长度,direction为蛇前进的方向

2、坐标系:点阵的左下角为点(0,0),横纵坐标都是正向增长,P2控制横坐标;P0控制纵坐标。通过坐标可以找到点阵中点的位置,然后将其点亮

假设现在有第2个点的坐标x[2] = 1, y[2] = 2,那么点亮这个点的方式为

P2 = 0x04; //0000 0100

P0 = 0xfb; //1111 1011

3、按键产生外部中断,在中断里判断按下那个方向get_direction(),并且同时设置坐标set_location()

4、定时器每隔1s就应该更新位置,因为蛇要不停的前进。定时器不需要更新方向,因为方向只有按键才会改动,定时器用前一步的方向

5、关于点的位置更新方式

1)、向上移动

后面的点去覆盖前面的点,第一个点用新坐标表示x[0]不变,y[0]+1

2)、向下移动

后面的点去覆盖前面的点,第一个点用新坐标表示x[0]不变,y[0]-1

3)、向左移动

后面的点去覆盖前面的点,第一个点用新坐标表示x[0]-1,y[0]不变

4)、向右移动

后面的点去覆盖前面的点,第一个点用新坐标表示x[0]+1,y[0]不变

6、关于边界问题:

1)、任何一个点的横坐标 0 <= x[i] < 8

2)、任何一个点的纵坐标 0 <= y[i] < 8

3)、第一个点在移动的时候不能和其他点重复,否则就自己追尾了

7、关于原理图按键的设计

贪吃蛇要求系统能迅速响应按键,因此轮询的方式并不可取,只有靠外部中断。然而51只有2个外部中断,我们起码需要4个方向键,这样就不能一个按键配一个外部中断,通过使用4输入与门,将所有按键状态集合在一起,然后送给外部中断0。我们将4个按键都接在与门,只要有一个按下,那么与门的输出就会产生一个下降沿,从而产生外部中断。

四、源代码

main.c

#include "snake.h"

int error = 0;

int time=0;

void interrupt_init()

{

EA = 0; //关闭总中断

IT0 = 1; //外部中断0方式 下降沿

EA = 1; //开启总中断

EX0 = 1; //开启外部中断

}

void timer_init()

{

EA = 0; //关总中断

ET0 = 1; //开定时器0中断

TMOD = 0x02; //定时器0工作方式2

TL0 = 6; //定时250us

TH0 = 6;

EA = 1; //开总中断

TR0 = 1; //开始定时

}

int main()

{

// unsigned char tempx, tempy;

// unsigned char i,j;

interrupt_init();

timer_init();

snk_init();

while(1)

{

//如果位置错了就重新初始化蛇

if(error)

snk_init();

//点亮点阵

matrix();

}

}

void inter0() interrupt 0

{

//按键产生外部中断,获取新的方向

get_direction();

//设置新的位置

error = set_location();

// matrix();

}

void timer0() interrupt 1

{

time++;

//定时器为250us 积累4000次就是1s

if(time == 4000)

{

//每隔1s都需要重新设置位置,让蛇前进

error = set_location();

time = 0;

}

}

snake.c

点击(此处)折叠或打开

#include "snake.h"

//蛇的结构体,x为横坐标,y为纵坐标,length为蛇的长度,direction为蛇的前进方向

struct snake{

unsigned char x[20];

unsigned char y[20];

unsigned char length;

unsigned char direction;

}snk;

void matrix()

{

unsigned char i;

int count=500;

//关闭所有的点

P2 = 0x00;

P0 = 0xff;

//根据蛇每一个点的坐标,将对应的点阵点亮

for(i=0; i

{

P2 = 1<

P0 = ~(1<

}

}

void snk_init()

{

//初始化坐标,总共4个点(3,0) (2,0) (1,0) (1,0)

snk.x[0] = 3;

snk.y[0] = 0;

snk.x[1] = 2;

snk.y[1] = 0;

snk.x[2] = 1;

snk.y[2] = 0;

snk.x[3] = 0;

snk.y[3] = 0;

//初始长度4

snk.length = 4;

//初始移动方向 向右

snk.direction = RIGHT;

//点亮点阵

matrix();

}

void get_direction()

{

//通过按键的状态获取方向

if(!up)

snk.direction = UP;

if(!down)

snk.direction = DOWN;

if(!left)

snk.direction = LEFT;

if(!right)

snk.direction = RIGHT;

}

int set_location()

{

unsigned char i;

int err = 0;

if(snk.direction == UP)

{

for(i=snk.length-1; i>0; i--)

{

snk.x[i] = snk.x[i-1];

snk.y[i] = snk.y[i-1];

}

//如果向上运动,第0个点的横坐标不变,纵坐标加1

snk.x[0] = snk.x[0];

snk.y[0] = snk.y[0] + 1;

}

else if(snk.direction == DOWN)

{

for(i=snk.length-1; i>0; i--)

{

snk.x[i] = snk.x[i-1];

snk.y[i] = snk.y[i-1];

}

//如果向下运动,第0个点的横坐标不变,纵坐标减1

snk.x[0] = snk.x[0];

snk.y[0] = snk.y[0] - 1;

}

else if(snk.direction == LEFT)

{

for(i=snk.length-1; i>0; i--)

{

snk.x[i] = snk.x[i-1];

snk.y[i] = snk.y[i-1];

}

//如果向左运动,第0个点的横坐标减1,纵坐标不变

snk.x[0] = snk.x[0] - 1;

snk.y[0] = snk.y[0];

}

else

{

for(i=snk.length-1; i>0; i--)

{

snk.x[i] = snk.x[i-1];

snk.y[i] = snk.y[i-1];

}

//如果向右运动,第0个点的横坐标加1,纵坐标不变

snk.x[0] = snk.x[0] + 1;

snk.y[0] = snk.y[0];

}

err = is_location_error();

return err;

}

int is_location_error()

{

unsigned char i;

//如果第0个点的坐标和其他任意一个点重复,那么蛇就自己撞自己,出错

for(i=1; i

{

if((snk.x[0]==snk.x[i]) && (snk.y[0]==snk.y[i]))

return 1;

}

//如果蛇的坐标超出范围,也出错

if(snk.x[0]>7 || snk.y[0]>7)

return 1;

return 0;

}

snake.h

#include

//定义四个方向按键

sbit up = P3^4;

sbit down = P3^5;

sbit left = P3^6;

sbit right = P3^7;

//定义1个游戏级别按键

sbit level = P3^0;

//定义一个复位按键

sbit reset = P3^1;

//定义4个方向的值

#define RIGHT 0

#define UP 1

#define LEFT 2

#define DOWN 3

void delay_us();

void delay_10us();

void delay_ms();

void delay_10ms();

void delay_100ms();

void delay_s();

int is_location_error();

void matrix();

void snk_init();

void set_direction();

int get_location();

int is_location_error();

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭