**

基于51单片机的贪吃蛇小程序(8*8LED点阵实现)by_jy

**

一直很想写一个贪吃蛇的小程序,这两天终于抽空完成了,这里把我的思路分享给大家,仅供参考!

代码如下:
先放段主函数压压惊

void main()
{   x_s[0] = 2;               //初始化三个点y_s[0] = 3;x_s[1] = 3;y_s[1] = 3;x_s[2] = 4;y_s[2] = 3;Timer0Init();suijishu();while(1){appear();if(flag_a)     //蛇身移动位{if(!flag_s)   //蛇身死亡位{auto_move();HC_595(0x00);     //消隐P0 = 0xFF;      //消隐   shensi();chiguo();delay(1000);flag_a = 0;}}                }
}

/*
本程序核心程序:
appear函数,显示蛇身
auto_move函数,控制蛇身惯性移动 ,同时里面附了判断是否穿墙的一段代码
direction函数,控制蛇的移动方向
suijishu(随机数)函数,随机生成果子
chiguo(吃果)函数,判断是否吃到果子
shensi(身死)函数,碰到自己身体则死亡

*/

#include<reg51.h>
#include<intrins.h>
#include<stdlib.h>
#define M 12        //难度系数,12中等,越小越难
typedef unsigned char uchar;
typedef unsigned int uint;sbit SRCLK = P3^6;         //595芯片
sbit RCLK = P3^5;
sbit SER = P3^4;sbit LSA=P2^2;             //138译码器
sbit LSB=P2^3;
sbit LSC=P2^4;uchar code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//显示0~F的值//定义方向键
sbit K1 = P3^1;        //上
sbit K2 = P3^0;        //下
sbit K3 = P3^2;        //左
sbit K4 = P3^3;        //右 uchar m;            //储存果子的X坐标
uchar n;            //储存果子的Y坐标uchar snakelong = 3;    //初始化蛇长
char flag_x = 1;          //初始化运动方向
char flag_y = 0;          //初始化运动方向
uchar flag_gg = 0;        //生成果子的重复性标志
uchar flag_c = 0, sheshen = 0;      //吃果标志
uchar flag_a = 0;      //移动标志
uchar flag_s = 0;      //死亡标志
uchar x_s[32] = {0},y_s[32] = {0};       //定义蛇的最大长度
uchar code X_[8] = {0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD,0xFE};
uchar code Y_[8] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};     /*  y1               //定义x,y坐标y2           //如,我想让(4,2)亮,只需要P0 = X_[4];HC_595 = Y_[2];y3y3y5y6y7y8x1    x2   x3   x4  x5   x6   7   x8
*/

一个小的延时函数:


void suijishu();                   //提前定义随机数生成函数
void delay(uint i)                 //简单的delay函数,对于51单片机,delay(1)约等于9微秒
{while(i--);
}

定时器初始化:


void Timer0Init()                 //定时器初始化函数       模式1,16位定时器
{TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。TH0=0XFC;   //给定时器赋初值,定时1msTL0=0X18;    ET0=1;//打开定时器0中断允许EA=1;//打开总中断TR0=1;//打开定时器
}

两个显示函数,分别控制点阵和数码管;

void HC_595(uchar date)               //595例程,这里就不详细解释了
{   uchar a;SRCLK = 0;RCLK = 0;for(a=0;a<8;a++){SER = date>>7;date<<=1;SRCLK = 1;_nop_();_nop_();SRCLK = 0;}RCLK = 1;_nop_();_nop_();RCLK = 0;
}void display()                     //数码管显示,用来显示蛇长
{uchar i,b=2;HC_595(0x00);     //消隐_nop_();P0=0x00;         //因为我用的板子上数码管和点阵共用的P0口,所以这里消隐的时候需要特别注意。_nop_();for(i=0;i<2;i++){ while(b) {         //这里循环两次是为了让数码管显示更清楚一点。switch(i)  //位选,选择点亮的数码管{case(0):LSA=0;LSB=0;LSC=0; P0=smgduan[(snakelong%10)];delay(10);P0=0x00;break;   case(1):LSA=1;LSB=0;LSC=0; P0=smgduan[(snakelong/10)];delay(10);P0=0x00;break;}    _nop_();b--;}       }LSA=1;LSB=1;LSC=1; P0=0xFF;     //还是为了消隐。以一个数码管常亮为代价,以求不影响点阵和数码管显示蛇长
}

显示蛇身,核心函数之一:

void appear()            // viod 蛇身出现
{
/*  x_s[0] = 2;             //初始化三个点y_s[0] = 3;x_s[1] = 3;y_s[1] = 3;x_s[2] = 4;y_s[2] = 3;    *///uint t = 150;  //t越小越难,越大越简单        //这里也可以控制难度,经测试也有效。
//while(t)
//{ uchar i;for(i=0;i<snakelong;i++)                   //snakelong 是用来控制数组的全局关键变量{if((x_s[i]!=0)&&(y_s[i]!=0)){P0 = X_[x_s[i]-1];HC_595(Y_[y_s[i]-1]);delay(100);         //延时P0 = 0xFF;       //消隐   HC_595(0x00);     //消隐}}
//  t--;
//}}

自动惯性移位函数:

void auto_move()     // viod 自动移动          核心程序之一
{   uchar i;                    for(i=0;i<(snakelong-1);i++){x_s[i] = x_s[i+1];y_s[i] = y_s[i+1];}x_s[snakelong-1] += flag_x;y_s[snakelong-1] += flag_y;if(x_s[snakelong-1]>8)         // void 穿墙判断  x_s[snakelong-1] = 1;else if(x_s[snakelong-1]<1)x_s[snakelong-1] = 8;if(y_s[snakelong-1]>8)y_s[snakelong-1] = 1;else if(y_s[snakelong-1]<1)y_s[snakelong-1] = 8;}

键盘扫描(独立键盘),控制蛇的移动方向:

void direction()     // void 方向控制
{if(!K1) {delay(1000);if(!K1){if(flag_y == 1)    //是否正在下降  ,若是,则点击上升无用。{flag_y = 1;}else{flag_x = 0;flag_y = -1; //shang}}}else if(!K2) {delay(1000);if(!K2){if(flag_y == -1)     //是否正在上升{flag_y = -1;}else{flag_x = 0;flag_y = 1;     //xia}}}else if(!K3) {delay(1000);if(!K3){if(flag_x == 1)    //是否正在右移{flag_x = 1;}else{flag_x = -1; //zuoflag_y = 0;   }}}else if(!K4) {delay(1000);if(!K4){if(flag_x == -1)    //是否正在左移{flag_x = -1;}else{flag_x = 1;     //youflag_y = 0;   }}}
}

吃果函数,吃到果子蛇头增长

void chiguo()            // void 吃果判断
{if(((x_s[snakelong-1]+flag_x)==m)&&((y_s[snakelong-1]+flag_y)==n)  ){    flag_c = 1;        }else if(((x_s[snakelong-1]+flag_x)==m)&&((y_s[snakelong-1]+flag_y)==n)  ) //重复两次防止程序bug——穿过果子但不去吃     {  flag_c = 1;        }else if(((x_s[snakelong-2]+flag_x)==m)&&((y_s[snakelong-2]+flag_y)==n)  )     //放宽吃果判定,以防止出现bug——穿过果子但不去吃               { flag_c = 1;    sheshen = 1;    }else if(((x_s[snakelong-3]+flag_x)==m)&&((y_s[snakelong-3]+flag_y)==n)  ){  flag_c = 1;    sheshen = 2;    }          if(flag_c){flag_c = 0;TR0 = 0;//关闭定时器snakelong++;if(sheshen == 1){x_s[snakelong-1] = m+flag_x;y_s[snakelong-1] = n+flag_y;sheshen = 0;   }else if(sheshen == 2){x_s[snakelong-1] = m+2*flag_x;y_s[snakelong-1] = n+2*flag_y;sheshen = 0;  }else{                           //这才是吃果的正常情况x_s[snakelong-1] = m;y_s[snakelong-1] = n;sheshen = 0;}suijishu();        //再生成一个果子P0 = 0xFF;       //消隐   HC_595(0x00);     //消隐appear();appear();P0 = 0xFF;      //消隐   HC_595(0x00);     //消隐TR0=1;//打开定时器}
}

碰到自己身体死亡函数

void shensi()             // void 身死    碰到自己身死
{uchar b,x_1,y_1;if(snakelong>4) {for(b=0;b<snakelong-4;b++)                  //对蛇头处的四个不用判断,也不能判断{  if(((x_s[snakelong-1])==x_s[b])&&((y_s[snakelong-1])==y_s[b])  )  {flag_s = 1; }}if(flag_s == 1){    P0 = 0x00;HC_595(0xFF);delay(2000);       //闪烁两次P0 = 0xFF;HC_595(0x00);delay(2000);P0 = 0x00;HC_595(0xFF);delay(3000);P0 = 0xFF;HC_595(0x00);delay(1000);x_1 = x_s[snakelong-1] ;y_1 = y_s[snakelong-1] ;            //卡在死亡状态的下一刻  snakelong++;x_s[snakelong-1] = x_1 + flag_x;y_s[snakelong-1] = y_1 + flag_y;}}
}

随机生成果子:


void suijishu()                     //随机数,生成果子
{uchar b,m_1,n_1;do{flag_gg = 0;m_1 = (rand()%8)+1;                  n_1 = (rand()%8)+1;for(b=0;b<snakelong;b++){    if((m_1==x_s[b])&&(n_1==y_s[b]))     //如果果子和蛇身有重复,则flag_gg置1,再生成一次                    flag_gg = 1;       }}while(flag_gg);       m = m_1;n = n_1;
}

主函数:

void main()
{   x_s[0] = 2;               //初始化三个点y_s[0] = 3;x_s[1] = 3;y_s[1] = 3;x_s[2] = 4;y_s[2] = 3;Timer0Init();suijishu();while(1){appear();if(flag_a)     //蛇身移动位{if(!flag_s)   //蛇身死亡位{auto_move();HC_595(0x00);     //消隐P0 = 0xFF;      //消隐   shensi();chiguo();delay(1000);flag_a = 0;}}                }
}

/*
果子的函数放在了中断里,1ms一次进行显示,同时键盘也是1mS一次进行扫描
通过调节M的大小来实现蛇的延时移动。
*/

void guozi() interrupt 1     // void 果子出现
{   uint a;uchar i=3;a++;direction();      //用中断去扫描键盘,1mS/次P0 = 0xFF;         //消隐   HC_595(0x00);     //消隐while(i)        //重复以增加亮度{P0 = X_[m-1];HC_595(Y_[n-1]);i--;}delay(100);P0 = 0xFF;        //消隐   ,因为我用的板子上数码管和点阵共用的P0口,所以这里消隐的时候需要特别注意HC_595(0x00);     //消隐_nop_();P0=0x00;  //数码管消隐_nop_();display();delay(100);HC_595(0x00);     //消隐_nop_();              LSA=1;LSB=1;LSC=1; P0 = 0xFF;if (a>M)          //蛇身移动控制位{a = 0;flag_a = 1;}
}

/*
编写过程中共累计进行了两次优化,第一次对1,随机生成果子,2,吃果判定的放宽,3,碰到蛇身死亡,以及4,正在上升/下降时,不能下降上升
正在左移/右移时,不能右移/左移 进行了加入以及优化
第二次对数码管显示问题,吃到果子延时增长问题进行了解决,同时对死亡时的效果进行了优化

调试经验:
建议初学者首先构思好程序框架,想清楚程序需要哪几个必要模块(因此建议程序书写模块化),然后
对几个必要模块进行相对独立的调试,进而进行整合,确保基础功能的实现。
在此之后,在对程序出现的问题进行解决和优化。

*/

基于51单片机的贪吃蛇小程序(8*8LED点阵实现)by_jy相关推荐

  1. 基于51单片机的贪吃蛇小游戏8X8点阵 proteus仿真原理图程序

    硬件设计 基于C51作为MCU 一块8X8点阵作为游戏的显示器 四个按键作为操控按键 仿真图: 程序设计 #include <at89x51.h> #include "18b20 ...

  2. 基于51单片机的贪吃蛇小游戏

    #include <reg52.h>// 点阵寄存器定义 sbit LOAD = P1 ^ 0; sbit CLK = P1 ^ 1; sbit DATA = P1 ^ 2;sbit mK ...

  3. 基于51单片机的贪吃蛇游戏设计

    1绪 论 1.1本课题研究的背景及意义 随着当今社会的发展,人们的生活节奏变得越来越快,人们开始逐渐的融入全球化的世界.人们已经不再局限于一小块天地,加班,出差已经占据了现代人生活的绝大部分.这个时候 ...

  4. 共阳极数码时钟c语言程序,基于51单片机C语言数字钟程序.doc

    基于51单片机C语言数字钟程序 基于51单片机C语言数字钟程序 数字电子钟的设计 一. 绪论 (一)引言 20世纪末,电子技术获得了飞速的发展,在其推动下,现代电子产品几乎渗透了社会的各个领域,有力地 ...

  5. 软件保障与测试课程实践记录:贪吃蛇小程序

    对象:贪吃蛇小程序 (原代码见 https://blog.csdn.net/leslie5205912/article/details/78980006) 测试过程: 程序改动部分: 1.bug修复 ...

  6. 简易电子钟c语言程序,(最新整理)基于51单片机的电子钟C语言程序

    <(最新整理)基于51单片机的电子钟C语言程序>由会员分享,可在线阅读,更多相关<(最新整理)基于51单片机的电子钟C语言程序(9页珍藏版)>请在人人文库网上搜索. 1.完整) ...

  7. 51单片机的电子钟c语言程序,基于51单片机的电子钟C语言程序

    基于单片机C语言的电子钟程序代码与仿真 基于51单片机的电子钟C语言程序: 程序代码 #include #include #define uchar unsigned char #define uin ...

  8. 基于51单片机的温度报警系统(程序分装)

    文章目录 目录 前言 一.程序结构 1.1.1 全局变量 1.1.2 静态本地变量 1.2 预处理命令 1.3.1 函数原型 1.3.2 头文件 标准头文件结构. 1.4  *声明和定义* 二.错误示 ...

  9. 基于51单片机的出租车计价器(程序+仿真+论文)

    1.主要功能 设计要求 : ①.不同情况具有不同的收费标准. 白天,晚上,途中等待(>10min 开始收费): ②.能进行手动修改单价 : ③.具有数据的复位功能: ④.具有启动计时开关.白天/ ...

最新文章

  1. Android AsyncTask 深度理解、简单封装、任务队列分析、自定义线程池
  2. 【物联网】 AR9344开发环境的搭建和编译固件
  3. 18.外部相机校准——旋转(Rotation),R是什么样子的,绕Z轴旋转的例子,齐次坐标旋转_2
  4. oracle 测试坚挺,access数据库用户依然坚挺,但是面临新的对手挑战
  5. 【情感分析】华为云细粒度文本情感分析及应用
  6. 5. php 基本数据类型
  7. 华三交换机链路聚合的几点思考
  8. java结合opencv进行照片人脸检测
  9. Freescale PowerPC系列架构 处理器 种类介绍 型号发展
  10. 十年前加入互联网改变世界,十年后加入顶级微信团队一起炸屎
  11. 大一结业项目之一(C#晨曦超市管理系统 )
  12. 信息技术前言讲座报告
  13. UML各种箭头的含义
  14. 【数据去噪】SG-多项式平滑算法
  15. vm-install vmware tools安装
  16. htons(), htonl(), ntohs(), ntohl()
  17. MySQL连接不了本地服务器原因
  18. 游戏服务器中pvp、pve、rppvp、ffa-pvp的含义
  19. Mysql | MariDB | 导入导出数据库 | 常见问题 | ASCII ‘\0‘ appeared in the statement
  20. qq引流有哪些模式? QQ引流的几种方法

热门文章

  1. 偏财入财库大富_八字有财库者大富
  2. 从0到1构建新闻长文本分类系统
  3. 嵌入式系统----原理与应用技术考点
  4. Winform自定义控件 —— 水印文本框
  5. 用HTML实现邮箱的注册页面
  6. Google的霸道:我就是要独享安卓源代码!
  7. MyBatis执行一次数据库操作的原理以及顺序
  8. 使用requests库豆瓣电影爬虫
  9. moba寻路_GitHub - ylmbtm/MoBaDemo: 用Unity做的一个类Moba游戏Demo
  10. 巨简单 在eclips上面新建一个网页动态项目