/*--------------------------------------------------------------*/
//LED8*8显示
//573输出数据,CPU进行列扫描,列扫描,低电平有效
#include <reg52.h>
/*--------------------------------------------------------------*/
//接口定义
sfr DB = 0x90;
sbit LE = P3^7;
sbit OE = P3^6;
sbit K1 = P3^2;
sbit K2 = P3^3;
sbit K3 = P3^4;
sbit K4 = P3^5;
sbit K5 = P3^1;
sbit BP = P0^0;
sbit MT = P0^1;
/*--------------------------------------------------------------*/
//全局变量定义
#define len 30 //最大长度
unsigned char disram[8]; //显示缓冲区
unsigned char x[len],y[len];//蛇身坐标
bit on_off; //显示开关,0--关闭;1--开启
bit inverse; //反色显示,0--关闭;1--开启
char dx, dy;
unsigned char ID;
unsigned char speed; //移动速度
unsigned char level; //关数
unsigned char life; //生命值
void key_scan(void);
/*--------------------------------------------------------------*/
//定时器初始化
void T0_init(void)
{
TMOD |= 0x01;
TH0 = 0xf8; //2ms
TL0 = 0x36;
IE |= 0x82;
PT0 = 1;
TR0 = 1;
}
/*--------------------------------------------------------------*/
//定时器初始化
void T1_init(void)
{
TMOD |= 0x10;
TH1 = 0x00; //65ms
TL1 = 0x00;
IE |= 0x88;
TR1 = 1;
}
/*-------------- ------------------------------------------------*/
//清除显示缓冲区,即清屏
void clr_ram(void)
{
unsigned char i;
for(i = 0; i < 8; i++)
disram[i] = 0x00;
}
/*--------------------------------------------------------------*/
//画点函数,一次只显示一个点
//点阵左上角坐标为(0, 0) 右下角坐标为(7, 7)
//横坐标为x:0~7 纵坐标为y:0~7
/*void gotoxy(unsigned char x, unsigned char y)
{
clr_ram();
disram[y] = 0x01 << x;
}
/*--------------------------------------------------------------*/
//画点函数,保留上次绘图
//点阵左上角坐标为(0, 0) 右下角坐标为(7, 7)
//横坐标为x:0~7 纵坐标为y:0~7
/*void point(unsigned char x, unsigned char y)
{
disram[y] |= 0x01 << x;
}
/*--------------------------------------------------------------*/
//画点函数,擦点或者绘点
//点阵左上角坐标为(0, 0) 右下角坐标为(7, 7)
//横坐标为x:0~7 纵坐标为y:0~7
//k = 1 --绘点 k = 0 --擦点
void point1(unsigned char x, unsigned char y, bit k)
{
if(k) disram[y] |= 0x01 << x; //绘点
else disram[y] &= ~(0x01 << x); //擦点
}
/*--------------------------------------------------------------*/
//定时器中断服务
void T0_intservice(void) interrupt 1 //每次只扫描一行的数据,每秒扫描500次(行),一页扫描要16次,每秒扫31.25
{ //页(帧)
static unsigned char n;
TR1 = 0;
TH0 = 0xf8; //2ms
TL0 = 0x36;
OE = 1; //高阻(高阻态)
if(on_off) DB = 0x01 << n; //开始列扫描
else DB = 0x00; //关闭显示
LE = 1; //传送
LE = 0; //锁存
if(inverse) DB = disram[n]; //反色显示
else DB = ~disram[n]; //正常显示(n代表第几行,即y)
OE = 0; //输出显示
n++; if(n == 8) n = 0; //循环扫描
TR1 = 1;
}
/*--------------------------------------------------------------*/
//定时器中断服务
void T1_intservice(void) interrupt 3
{
TH1 = 0x00;
TL1 = 0x00;
key_scan();
}
/*--------------------------------------------------------------*/
//延时100000+1us 函数定义
void delay(void)
{
unsigned char i,j,k;
for(i=156;i>0;i--)
for(j=58;j>0;j--)
for(k=4;k>0;k--);
}
/*--------------------------------------------------------------*/
//蜂鸣器
void beep(void)
{
BP = 0;
delay();
BP = 1;
}
/*--------------------------------------------------------------*/
//按键扫描
void key_scan(void)
{
if(K1 == 0) //上
{
if(ID == 0) {dx = 0; dy = -1;}
if(ID == 1 && speed > 1) //加速
{
speed--;
beep(); //声音指示
while(K1 == 0);
}
if(ID == 2 && level < 17) //选关
{
level++;
beep(); //声音指示
while(K1 == 0);
}
}
if(K2 == 0) //下
{
if(ID == 0) {dx = 0; dy = 1;}
if(ID == 1 && speed < 15) //减速
{
speed++;
beep(); //声音指示
while(K2 == 0);
}
if(ID == 2 && level > 0) //选关
{
level--;
beep(); //声音指示
while(K2 == 0);
}
}
if(K3 == 0) //左
{
if(ID == 0) {dy = 0; dx = -1;}
if(ID == 1) inverse = 0; //正常显示
if(ID == 2) on_off = 1; //开启显示
}
if(K4 == 0) //右
{
if(ID == 0) {dy = 0; dx = 1;}
if(ID == 1) inverse = 1; //反色显示
if(ID == 2) on_off = 0; //关闭显示
}
if(K5 == 0) //中
{
ID++; if(ID == 4) ID = 0;
beep(); //声音指示
while(K5 == 0);
}
}
/*--------------------------------------------------------------*/
//定点显示,一次只显示一个点
void gotoxy(unsigned char x, unsigned char y)
{
OE = 1; //高阻
DB = (0x01 << y);
LE = 1; //传送
LE = 0; //锁存
DB = ~(0x01 << x);
OE = 0; //输出显示
beep(); //声音指示
delay();
}
/*--------------------------------------------------------------*/
//通关演示
void congrate(void)
{
char i, j;
TR0 = 0;
TR1 = 0;
for(j = 0; j < 5; j++)
{
for(i = j ; i < 8-j; i++)gotoxy(j, i);
for(i = j+1 ; i < 8-j; i++)gotoxy(i, 7-j);
for(i = j+1 ; i < 8-j; i++)gotoxy(7-j, 7-i);
for(i = j+1 ; i < 7-j; i++)gotoxy(7-i, j);
}
for(j = 4; j >= 0; j--)
{
for(i = 6-j ; i >= j+1; i--)gotoxy(7-i, j);
for(i = 7-j ; i >= j+1; i--)gotoxy(7-j, 7-i);
for(i = 7-j ; i >= j+1; i--)gotoxy(i, 7-j);
for(i = 7-j ; i >= j; i--)gotoxy(j, i);
}
}
/*--------------------------------------------------------------*/
//主函数
void main (void)
{
unsigned char i; //通用循环变量
unsigned char num; //蛇的长度
bit food, over; //食物和结束标志位
unsigned char foodx, foody; //食物坐标
life = 3;
speed = 8;
num = 2;
T0_init(); //定时器初始化
T1_init();
on_off = 1; //开显示
inverse = 0; //正常显示
clr_ram(); //清显示缓冲区
x[0] = 1; //初始化位置
y[0] = 2;
dx = 1; //向右运动
while(1)
{
x[0] += dx; y[0] += dy; //蛇头
x[0] &= 0x07; y[0] &= 0x07; //穿墙
if(!food) //放置食物
{
again: foodx = TL0&0x07; //随机
foody = TH0&0x07;
for(i = 0; i < num; i++)
{
if(foodx == x[i] && foody == y[i])
goto again;
}
point1(foodx, foody, 1); //显示食物
food = 1; //置食物标志位
}
if(x[0] == foodx && y[0] == foody) //吃到食物
{
beep(); //声音指示
num++; //蛇长增加1节
food = 0; //清食物标志位
}
for(i = 0; i < num; i++) //显示蛇身
point1(x[i], y[i], 1);
point1(x[i], y[i], 0); //清蛇尾,也可以写成point1(x[num], y[num], 0);因前面加了i=num成立
for(i = 1; i < num; i++) //判断是否自撞
{
if((x[0] == x[i]) && (y[0] == y[i]))
over = 1; //置结束标志位
}
for(i = 0; i < speed; i++) delay(); //蛇运动速度
for(i = 0; i < num; i++) //蛇移动蛇身
{
x[num-i] = x[num-i-1];
y[num-i] = y[num-i-1];
}
/* if(x[0]>7||y[0]>7) //判断是否撞墙
{
over = 1; //置结束标志位
}
*/
if(num > 5 + level) //过关
{
if(num > 8) //通关!!!
{
while(1){congrate();inverse = ~inverse;}
}
delay(); beep(); //声音指示
MT = 0; delay(); MT = 1; //振动指示
if(speed > 1) speed--; //速度加一
num = 2; //重定蛇长
level += 1; //总的蛇长增加1
clr_ram(); //清除屏幕
goto again; //新的一关开始
}
if(over) //判断是否结束
{
MT = 0; delay(); MT = 1; //振动指示
clr_ram(); //清除屏幕
num = 2; //重新设定蛇长
point1(foodx, foody, 1); //重新放置食物
x[0] = 1; y[0] = 2; //起点位置
dx = 1; //向右运动
over = 0; //清结束标志位
life--; //生命值减1
}
if(!life) congrate();
}
}