说明:使用hc595驱动双色点阵
使用德飞莱51单片机开发板(DOFLY-V2.3)
依据程序中的管脚定义用杜邦线接好管脚
程序可以直接使用。
程序部分参考自网上和学习板配套资料
------------------------------------------------*/
#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include <intrins.h>
/*------------------------------------------------
硬件端口定义
------------------------------------------------*/
sbit LATCH= P1^0; //锁存
sbit SRCLK= P1^1; //时钟
sbit SER = P1^2; //数据
sbit LATCH_B= P2^2; //锁存
sbit SRCLK_B= P2^1; //时钟
sbit SER_B= P2^0; //锁存
sbit LED=P1^3; //结束提示灯
//sbit key1=P3^0; //上
//sbit key2=P3^1; //下
//sbit key3=P3^2; //左
//sbit key4=P3^3; //右
//sbit key5=P3^4; //暂停
/*------------------------------------------------
全局变量定义
------------------------------------------------*/
unsigned char x[30],y[30]; //蛇身坐标
unsigned char speed=10; //控制速度变量
unsigned char dx=0,dy=1; //控制转向变量,初始化为向左运动
bit stop_start,inverse; //开始/暂停标志位,颜色显示标志位
bit up=1,down=1,left=1,right=1;//上下左右使能控制位
unsigned char tab[8]; //显示缓冲数组
unsigned char segout[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //8列扫描
/*------------------------------------------------
uS延时函数,含有输入参数 unsigned char t,无返回值
unsigned char 是定义无符号字符变量,其值的范围是
0~255 这里使用晶振12M,精确延时请使用汇编,大致延时
长度如下 T=tx2+5 uS
------------------------------------------------*/
void DelayUs2x(unsigned char t)
{
while(--t);
}
/*------------------------------------------------
mS延时函数,含有输入参数 unsigned char t,无返回值
unsigned char 是定义无符号字符变量,其值的范围是
0~255 这里使用晶振12M,精确延时请使用汇编
------------------------------------------------*/
void DelayMs(int t) //大致延时1mS
{
while(t--)
{
DelayUs2x(245);
DelayUs2x(245);
}
}
/*------------------------------------------------
发送字节程序
------------------------------------------------*/
void SendByte(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
SRCLK=0;
SER=dat&0x80;
dat<<=1;
SRCLK=1;
}
}
/*------------------------------------------------
发送双字节程序
595级联,n个595,就需要发送n字节后锁存
------------------------------------------------*/
void Send2Byte(unsigned char dat1,unsigned char dat2)
{
SendByte(dat1);
SendByte(dat2);
}
/*------------------------------------------------
595锁存程序
595级联发送数据后,锁存有效
------------------------------------------------*/
void Out595(void)
{
LATCH=0;
_nop_();
LATCH=1;
}
/*------------------------------------------------
发送位码字节程序
使用另外一片单独595
------------------------------------------------*/
void SendSeg(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++) //发送字节
{
SRCLK_B=0;
SER_B=dat&0x80;
dat<<=1;
SRCLK_B=1;
}
LATCH_B=0; //锁存
_nop_();
LATCH_B=1;
}
/*--------------------------------------------------------------
按键扫描函数
--------------------------------------------------------------*/
void key_scan()
{
switch(P3)
{
case 0xfe: if(up) //up
{
dx=-1;dy=0; //执行向上功能
down=0;left=1;right=1; //向下功能失效,其他功能可用
}
break;
case 0xfd: if(down) //down
{dx=1;dy=0;up=0;left=1;right=1;} //
break;
case 0xfb: if(left) //left
{dx=0;dy=1;down=1;up=1;right=0;} //
break;
case 0xf7: if(right) //right
{dx=0;dy=-1;down=1;left=1;up=1;} //
break;
case 0xef: //暂停/开始键
DelayMs(10); //延时去抖
if(P3==0xef) //再次确认按键是否按下
stop_start=~stop_start; //暂停/开始标志位取反(按一下暂停再按一下开始)
while(P3==0xef); //等待按键释放
break;
case 0xbf:
DelayMs(10); //延时去抖
if(P3==0xbf) //再次确认按键是否按下
speed+=2; //速度增大
while(P3==0xbf); //等待按键释放
break;
case 0x7f: DelayMs(10); //延时去抖
if(P3==0x7f) //再次确认按键是否按下
speed-=2; //速度减小
while(P3==0x7f); //等待按键释放
break;
default: break;
}
}
/*--------------------------------------------------------------
清除显示缓冲区,即清屏
--------------------------------------------------------------*/
void clr_ram(void)
{
unsigned char i;
for(i = 0; i < 8; i++)
tab[i] = 0x00; //逐个清除数组内容
}
/*--------------------------------------------------------------
画点函数,擦点或者绘点
点阵左上角坐标为(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) tab[y] |= 0x01 << x; //保留原始点,绘制新点
else tab[y] &= ~(0x01 << x); //保留其它点,只擦其中一个点
}
/*------------------------------------------------------------
定时器0初始化
--------------------------------------------------------------*/
void T0_init(void)
{
TMOD|= 0x01;
TH0 = 0xf8; //2ms
TL0 = 0x36;
IE |= 0x82;
TR0 = 1;
}
/*--------------------------------------------------------------
定时器1初始化
--------------------------------------------------------------*/
void T1_init(void)
{
TMOD|= 0x01;
TH1 = 0x00; //65ms
TL1 = 0x00;
IE |= 0x88;
TR1 = 1;
}
/*------------------------------------------------
主程序
------------------------------------------------*/
void main()
{
unsigned char i=0,foodx, foody; //食物坐标
unsigned char num=2; //蛇长度
bit food,over; //食物和结束标志位
IT0 = 1; //外部中断0(即P3^2脚)选择边沿触发,下降沿有效
EX0 = 1; //打开外部中断0
T0_init(); //定时器0初始化
T1_init(); //定时器1初始化
stop_start=0; //开始/暂停标志位置为开始
while(1)
{
x[0] += dx; y[0] += dy; //根据dxdy不同的值来使蛇头移动
x[0] &= 0x07; y[0] &= 0x07; //作用穿墙,x或y加到8时变为7
if(!food) //放置食物
{
again: foodx = TL0&0x07; //随机取食物坐标,0~7,但不会超过7
foody = TH0&0x07;
for(i = 0; i < num; i++)
{
if(foodx==x[i]&&foody==y[i]) //若食物与蛇身重叠,
goto again; //则重放食物。
}
// inverse=0; //颜色标志位置0,显示红色
point1(foodx, foody, 1); //显示食物
food = 1; //置食物标志位
}
if(x[0] == foodx && y[0] == foody) //吃到食物
{
num++; //蛇长增加1节
food = 0; //清食物标志位
}
for(;stop_start;); //按下暂停键程序在此进入死循环
// inverse=1; //颜色标志位置1,显示绿色
for(i = 0; i < num; i++) //显示蛇身
point1(x[i], y[i], 1);
point1(x[i], y[i], 0); //清蛇尾
for(i = 1; i < num; i++) //判断是否自撞
{
if((x[0]==x[i])&&(y[0]==y[i]))
over = 1; //置结束标志位
}
for(i=0;i<speed;i++) DelayMs(15); //蛇运动速度
for(i = 0; i < num; i++) //蛇移动蛇身
{
x[num-i] = x[num-i-1];
y[num-i] = y[num-i-1];
}
if(over) //判断是否结束
{
for(i=0;i<10;i++) //LED闪5次
{
LED=~LED;
DelayMs(100);
}
clr_ram(); //清除屏幕
num = 2; //重新设定蛇长
point1(foodx, foody, 1); //重新放置食物
x[0] = 0; y[0] = 0; //起点位置
dx=0;dy=1; //向左运动
over = 0; //清除结束标志
}
}
}
/*--------------------------------------------------------------
定时器1中断服务
--------------------------------------------------------------*/
void T1_intservice(void) interrupt 3
{
TH1 = 0x00;
TL1 = 0x00;
key_scan();
}
/*--------------------------------------------------------------
定时器0中断服务
--------------------------------------------------------------*/
void T0_intservice(void) interrupt 1
{
static unsigned char n; //定义静态变量
TR1 = 0; //关闭定时器1
TH0 = 0xf8;
TL0 = 0x36; //重装初值,2ms
SendSeg(segout[n]); //发送列码(相当于数码管中的位码)
if(inverse)
Send2Byte(0xff,~tab[n]);//发送点码(相当于数码管中的段码),显示绿色,交换两个量可改变颜色
else
Send2Byte(~tab[n],0xff);//发送点码(相当于数码管中的段码),显示红色,交换两个量可改变颜色
Out595(); //595锁存程序
DelayMs(1);
Send2Byte(0xff,0xff); //防止重影
Out595();
n++; if(n == 8) n = 0; //循环扫描
TR1 = 1; //打开定时器1
}
|