基于51单片机的贪吃蛇小程序(8*8LED点阵实现)by_jy
**
基于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相关推荐
- 基于51单片机的贪吃蛇小游戏8X8点阵 proteus仿真原理图程序
硬件设计 基于C51作为MCU 一块8X8点阵作为游戏的显示器 四个按键作为操控按键 仿真图: 程序设计 #include <at89x51.h> #include "18b20 ...
- 基于51单片机的贪吃蛇小游戏
#include <reg52.h>// 点阵寄存器定义 sbit LOAD = P1 ^ 0; sbit CLK = P1 ^ 1; sbit DATA = P1 ^ 2;sbit mK ...
- 基于51单片机的贪吃蛇游戏设计
1绪 论 1.1本课题研究的背景及意义 随着当今社会的发展,人们的生活节奏变得越来越快,人们开始逐渐的融入全球化的世界.人们已经不再局限于一小块天地,加班,出差已经占据了现代人生活的绝大部分.这个时候 ...
- 共阳极数码时钟c语言程序,基于51单片机C语言数字钟程序.doc
基于51单片机C语言数字钟程序 基于51单片机C语言数字钟程序 数字电子钟的设计 一. 绪论 (一)引言 20世纪末,电子技术获得了飞速的发展,在其推动下,现代电子产品几乎渗透了社会的各个领域,有力地 ...
- 软件保障与测试课程实践记录:贪吃蛇小程序
对象:贪吃蛇小程序 (原代码见 https://blog.csdn.net/leslie5205912/article/details/78980006) 测试过程: 程序改动部分: 1.bug修复 ...
- 简易电子钟c语言程序,(最新整理)基于51单片机的电子钟C语言程序
<(最新整理)基于51单片机的电子钟C语言程序>由会员分享,可在线阅读,更多相关<(最新整理)基于51单片机的电子钟C语言程序(9页珍藏版)>请在人人文库网上搜索. 1.完整) ...
- 51单片机的电子钟c语言程序,基于51单片机的电子钟C语言程序
基于单片机C语言的电子钟程序代码与仿真 基于51单片机的电子钟C语言程序: 程序代码 #include #include #define uchar unsigned char #define uin ...
- 基于51单片机的温度报警系统(程序分装)
文章目录 目录 前言 一.程序结构 1.1.1 全局变量 1.1.2 静态本地变量 1.2 预处理命令 1.3.1 函数原型 1.3.2 头文件 标准头文件结构. 1.4 *声明和定义* 二.错误示 ...
- 基于51单片机的出租车计价器(程序+仿真+论文)
1.主要功能 设计要求 : ①.不同情况具有不同的收费标准. 白天,晚上,途中等待(>10min 开始收费): ②.能进行手动修改单价 : ③.具有数据的复位功能: ④.具有启动计时开关.白天/ ...
最新文章
- Android AsyncTask 深度理解、简单封装、任务队列分析、自定义线程池
- 【物联网】 AR9344开发环境的搭建和编译固件
- 18.外部相机校准——旋转(Rotation),R是什么样子的,绕Z轴旋转的例子,齐次坐标旋转_2
- oracle 测试坚挺,access数据库用户依然坚挺,但是面临新的对手挑战
- 【情感分析】华为云细粒度文本情感分析及应用
- 5. php 基本数据类型
- 华三交换机链路聚合的几点思考
- java结合opencv进行照片人脸检测
- Freescale PowerPC系列架构 处理器 种类介绍 型号发展
- 十年前加入互联网改变世界,十年后加入顶级微信团队一起炸屎
- 大一结业项目之一(C#晨曦超市管理系统 )
- 信息技术前言讲座报告
- UML各种箭头的含义
- 【数据去噪】SG-多项式平滑算法
- vm-install vmware tools安装
- htons(), htonl(), ntohs(), ntohl()
- MySQL连接不了本地服务器原因
- 游戏服务器中pvp、pve、rppvp、ffa-pvp的含义
- Mysql | MariDB | 导入导出数据库 | 常见问题 | ASCII ‘\0‘ appeared in the statement
- qq引流有哪些模式? QQ引流的几种方法