错误如下
Build target 'Target 1'
assembling STARTUP.A51...
compiling exp.c...
EXP.C(214): warning C206: 'CLEAR': missing function-prototype
EXP.C(214): error C267: 'CLEAR': requires ANSI-style prototype
EXP.C(563): error C202: 'dengji': undefined identifier
Target not created
程序
/************************************************************************/
#include "reg51.h"
#define uchar unsigned char
#define uint unsigned int
void DelayINms(uint k); //函数原型声明
void chekbusy12864();
void choose12864(uchar SlctScreen);
void cmd_w12864(uchar cmd);
void dat_w12864(uchar dat);
void clear12864();
void init_lcd();
void Play8(uchar SlctScreen,uchar Column,uchar Page,uchar *pAdr);
void Play16(uchar SlctScreen,uchar Column,uchar Page,uchar *pAdr);
uchar dat_r12864(uchar Page,uchar Column);
void vertical(uchar RowStart,uchar RowStop,uchar Column);
void dot(uchar x,uchar y);
void cleardot(uchar x,uchar y);
void DisplayBodyCell(uchar *x,uchar *y);
void ClearBodyCell(uchar *x,uchar *y);
//文字点阵数据
uchar code shu0[]=
{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00};/*"0"*/
uchar code shu1[]=
{0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00};/*"1"*/
uchar code shu2[]=
{0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00};/*"2"*/
uchar code shu3[]=
{0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00};/*"3"*/
uchar code shu4[]=
{0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00};/*"4"*/
uchar code shu5[]=
{0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00};/*"5"*/
uchar code shu6[]=
{0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00};/*"6"*/
uchar code shu7[]=
{0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00};/*"7"*/
uchar code shu8[]=
{0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00};/*"8"*/
uchar code shu9[]=
{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00};/*"9"*/
uchar code GameOverWord[]=
{
0x00,0x20,0x44,0x08,0x20,0xE0,0x92,0x94,0x10,0x28,0xAE,0x68,0x24,0x04,0x00,0x00,
0x00,0x0C,0x03,0x04,0x02,0x19,0x0C,0x03,0x02,0x12,0x22,0x1F,0x01,0x01,0x01,0x00,/*"游"*/
0x00,0x20,0xA0,0x90,0x10,0xF0,0x00,0x40,0x7F,0xC0,0x20,0x24,0x88,0x00,0x00,0x00,
0x10,0x08,0x04,0x02,0x01,0x02,0x14,0x10,0x08,0x05,0x06,0x09,0x10,0x20,0x38,0x00,/*"戏"*/
0x00,0x60,0x50,0xCC,0x40,0x30,0x40,0x40,0x40,0xFE,0x20,0x20,0x20,0x20,0x00,0x00,
0x00,0x12,0x13,0x0A,0x09,0x05,0x00,0x3A,0x2A,0x25,0x25,0x15,0x1D,0x00,0x00,0x00,/*"结"*/
0x00,0x00,0x00,0x60,0xA8,0xA8,0xA8,0xFF,0x94,0x54,0x70,0x00,0x00,0x00,0x00,0x00,
0x10,0x10,0x08,0x08,0x04,0x02,0x01,0x7F,0x02,0x04,0x08,0x08,0x10,0x10,0x10,0x00 /*"束"*/
};
uchar code fen[]=
{
0x80, 0x40, 0x20, 0x98, 0x87, 0x82, 0x80, 0x80, 0x83, 0x84, 0x98, 0x30, 0x60, 0xc0, 0x40, 0x00,
0x00, 0x80, 0x40, 0x20, 0x10, 0x0f, 0x00, 0x00, 0x20, 0x40, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00/*"分"*/
};
uchar code shu[]=
{
0x10, 0x92, 0x54, 0x38, 0xff, 0x38, 0x54, 0x52, 0x80, 0xf0, 0x1f, 0x12, 0x10, 0xf0, 0x10, 0x00,
0x42, 0x42, 0x2a, 0x2e, 0x13, 0x1a, 0x26, 0x02, 0x40, 0x20, 0x13, 0x0c, 0x33, 0x60, 0x20, 0x00/*"数"*/
};
/*贪食蛇身体最小单位为4*4像素,活动空间被划分成多个4*4的小方块,共有16行25列,用x表示列,y表示行的话我们可以(X,Y)来表示蛇身体的一个单元的位置,从蛇头开始,我们将蛇的身体所有单元置于一个数组内,该数组为SnakeBody, SnakeBody[0] 存蛇尾。食物也是4*4的,处理方法类似*/
uchar SnakeBody[80]={0,8,1,8};
sbit deep=P2^5;
bit IsMovInVetical=0; //IsMovInVetical为0表示当前蛇头移动是水平向,1表垂直向
bit IsNotEatSelf; //为0表蛇头碰到蛇身,为1表未碰到。
bit IsToStep=0; //步进标志,主循环发现此位为1,让蛇进一步且将该位置0.
bit IsT0GenNewFood; //是否需要重新产生食物(重置食物)
uchar SnakeLength=2; //蛇体当前长度
uchar p=20; //定时次数
uchar ButtonNum,MovDirection=1; //k是按键号,MovDirection是移动方向
//液晶显示器相关全局变量
sbit E=P2^0;
sbit RW=P2^1;
sbit RS=P2^2;
sbit CS2=P2^3;
sbit CS1=P2^4;
/*************************************************************************
函数名:main
说明: 液晶屏初始化,定时器初始化后进入一个主循环,在主循环内等待到定时中
断服务程序将全局变量IsToStep置1,控制蛇产生步进。判断是否碰到食物,若碰到
食物则将蛇身与食物合并,并产生新的食物。每步进一次,主循环内还要判断蛇是否
吃到自己,若是,则退出主循环提示结束程序。
***************************************************************************/
void main()
{
uchar food[2]={12,8}; //食物的位置(位于哪个4*4小格)
uchar i,x,y;
choose12864(2); //选定左右屏幕
init_lcd(); //初始化
clear12864(); //清屏
vertical(1,61,30); //画左垂直边框线
vertical(1,61,127); //画右垂直边框线
for(i=0;i<98;i++) //画上下水平边框线
{
dot(30+i,1);
dot(30+i,62);
}
Play16(0,0,1,fen); //在屏幕左侧显示"分数"字样
Play16(0,0,2,shu);
DisplayBodyCell(SnakeBody,(SnakeBody+1));//显示贪食蛇
DisplayBodyCell((SnakeBody+2),(SnakeBody+3));//显示食物
DisplayBodyCell(food,food+1);
TMOD=0x01; //定时器工作方式
IT0=1; //边延有效
EX0=1; //开外部中断
TL0=0x00;
TH0=0x00; //定时器初值
TR0=1; //启动定时器
ET0=1; //开定时器中断
IP=0x01; //设置中断优先级
EA=1; //开CPU中断
do
{
while(!IsToStep);//等待到定时中断给步进标记置位后,控制蛇身向前一步
x=*(SnakeBody); //暂存蛇尾位置
y=*(SnakeBody+1);
switch(MovDirection)//东
{
case 1:
{
//蛇步进,原次尾单元变成尾单元。SnakeBody向前挪两个字节。
for(i=0;i<SnakeLength-1;i++)
{
*(SnakeBody+(i<<1))=*(SnakeBody+(i<<1)+2);
*(SnakeBody+(i<<1)+1)=*(SnakeBody+(i<<1)+3);
}
(*(SnakeBody+(SnakeLength<<1)-2))++; //设定新蛇头的位置
IsMovInVetical=0;
break;
}
case 2: //南
{ //蛇步进,原次尾单元变成尾单元。SnakeBody向前挪两个字节。
for(i=0;i<SnakeLength-1;i++) {
*(SnakeBody+(i<<1))=*(SnakeBody+(i<<1)+2);
*(SnakeBody+(i<<1)+1)=*(SnakeBody+(i<<1)+3);
}
(*(SnakeBody+(SnakeLength<<1)-1))++;
IsMovInVetical=1;
break;
}
case 3: //西
{//蛇步进,原次尾单元变成尾单元。SnakeBody向前挪两个字节。
for(i=0;i<SnakeLength-1;i++) {
*(SnakeBody+(i<<1))=*(SnakeBody+(i<<1)+2);
*(SnakeBody+(i<<1)+1)=*(SnakeBody+(i<<1)+3);
}
(*(SnakeBody+(SnakeLength<<1)-2))--;//设定新蛇头的位置
IsMovInVetical=0;
break;
}
case 4:
{ //北, 蛇步进,原次尾单元变成尾单元。SnakeBody向前挪两个字节。
for(i=0;i<SnakeLength-1;i++) {
*(SnakeBody+(i<<1))=*(SnakeBody+(i<<1)+2);
*(SnakeBody+(i<<1)+1)=*(SnakeBody+(i<<1)+3);
}
(*(SnakeBody+(SnakeLength<<1)-1))--;//设定新蛇头的位置
IsMovInVetical=1;
break;
}
}
if(((*(SnakeBody+(SnakeLength<<1)-2))==food[0])&&
((*(SnakeBody+(SnakeLength<<1)-1))==food[1]))
{ //若碰到食物,调整蛇体
for(i=SnakeLength;i>0;i--)
{
*(SnakeBody+(i<<1))=*(SnakeBody+(i<<1)-2);
*(SnakeBody+(i<<1)+1)=*(SnakeBody+(i<<1)-1);
}
*SnakeBody=x;
*(SnakeBody+1)=y;
SnakeLength++;//蛇体长度加
do //产生新的有效的食物
{
IsT0GenNewFood=0;
food[0]=TL0%24; //产生食物
food[1]=TL0%15;
//检查Food位置是否被蛇身覆盖,若是需重置食
for(i=0;i<SnakeLength-1;i++)
{
if((*(SnakeBody+(i<<1)))==food[0]&&
((*(SnakeBody+(i<<1)+1))==food[1]))
{
IsT0GenNewFood=1;
break;
}
}
}
while(IsT0GenNewFood);
DisplayBodyCell(food,food+1); //显示食物
}
IsNotEatSelf=1;
for(i=0;i<SnakeLength-1;i++)
{ //判断是否吃到自己,蛇头坐标与身体某单元相同
if(*(SnakeBody+(i<<1))==*(SnakeBody+(SnakeLength<<1)-2)
&&(*(SnakeBody+(i<<1)+1)==*(SnakeBody+(SnakeLength<<1)-1)))
{
IsNotEatSelf=0;//吃到自己
break;
}
}
IsNotEatSelf=IsNotEatSelf&&*(SnakeBody+(SnakeLength<<1)-2)>=0
&&*(SnakeBody+(SnakeLength<<1)-2)<24; IsNotEatSelf=IsNotEatSelf&&*(SnakeBody+(SnakeLength<<1)-1)>=0
&&*(SnakeBody+(SnakeLength<<1)-1)<15;
if(IsNotEatSelf) //如果未吃到自己
{
CLEAR(&x,&y);
for(i=0;i<SnakeLength;i++)//显示蛇身
{
DisplayBodyCell(SnakeBody+(i<<1),SnakeBody+(i<<1)+1);
}
IsToStep=0;
Play8(0,0,3,shu0+((SnakeLength/10)<<4));//显示得分
Play8(0,1,3,shu0+(((SnakeLength)%10)<<4));
}
}
while(IsNotEatSelf);
//如果吃到自己,则上面大循环结束,游戏结束。
TR0=0;
DelayINms(450);
DelayINms(450);
choose12864(2);
clear12864();
Play16(0,4,1,GameOverWord); //显示“游戏结束”字样。
Play16(0,6,1,GameOverWord+32);
Play16(1,0,1,GameOverWord+64);
Play16(1,2,1,GameOverWord+96);
while(1);
}
/***********************************************************************
函数名:DelayINms
说 明: 延时
输入参数:uint k,要延时的ms数
************************************************************************/
void DelayINms(uint k)
{
k=k*125;
while(k--);
}
/***********************************************************************
函数名:chekbusy12864
说 明: 检查液晶是否忙,若忙,等到其空闲再退出函数
************************************************************************/
void chekbusy12864()
{
uchar dat;
EX0=0;
RS=0; //指令模式
RW=1; //读数据
do
{
P0=0x00;
E=1;
dat=P0&0x80;
E=0;
}
while(dat!=0x00);
EX0=1;
}
/***********************************************************************
函数名:choose12864
说 明: 选择要写的屏幕
输入参数:uchar SlctScreeni是要写的屏.0是左屏,1是右屏,2是双屏
************************************************************************/
void choose12864(uchar SlctScreen)
{
switch (SlctScreen)
{
case 0: CS1=0;CS2=1;break;
case 1: CS1=1;CS2=0;break;
case 2: CS1=0;CS2=0;break;
default: break;
}
}
/***********************************************************************
函数名:cmd_w12864
说 明: 液晶写命令
输入参数:uchar cmd 要写的命令字
************************************************************************/
void cmd_w12864(uchar cmd)
{
chekbusy12864();
EX0=0;
RS=0; //指令模式
RW=0; //写模式
E=1;
P0=cmd;
E=0;
EX0=1;
}
/***********************************************************************
函数名:dat_w12864
说 明: 写数据
输入参数:uchar dat 要写的数据
/************************************************************************/
void dat_w12864(uchar dat)
{
chekbusy12864();
EX0=0;
RS=1;
RW=0;
E=1;
P0=dat;
E=0;
EX0=1;
}
/***********************************************************************
函数名:clear12864
说 明: 清屏
************************************************************************/
void clear12864()
{
uchar Page,Column;
for(Page=0xb8;Page<0xc0;Page++)
{
cmd_w12864(Page);
cmd_w12864(0x40);
for(Column=0;Column<64;Column++) dat_w12864(0x00);
}
}
/***********************************************************************
函数名:init_lcd
说 明: 初始化液晶
************************************************************************/
void init_lcd()
{
chekbusy12864();
cmd_w12864(0xc0);
cmd_w12864(0x3f);
}
/***********************************************************************
函数名:Play8
说 明: 8X16字符的显示
输入参数: uchar SlctScreen, 左右屏幕选择 uchar Column,显示位置的起始列号
uchar Page, 显示位置的起始页号 uchar *pAdr,指向显示的内容
************************************************************************/
void Play8(uchar SlctScreen,uchar Column,uchar Page,uchar *pAdr)
{
uchar i;
choose12864(SlctScreen);
Page=Page<<1;
Column=Column<<3;
cmd_w12864(Column+0x40);
cmd_w12864(Page+0xb8);
for(i=0;i<8;i++) dat_w12864(*(pAdr+i));
cmd_w12864(Column+0x40);
cmd_w12864(Page+0xb9);
for(i=8;i<16;i++) dat_w12864(*(pAdr+i));
}
/***********************************************************************
函数名:Play16
说 明: 该函数可用于在液晶屏指定位置输出一个分辨率为16*16的汉字
输入参数: uchar SlctScreen, 左右屏幕选择 uchar Column,显示位置的起始列号
uchar Page, 显示位置的起始页号 uchar *pAdr,指向显示的内容
************************************************************************/
void Play16(uchar SlctScreen,uchar Column,uchar Page,uchar *pAdr)
{
uchar i;
choose12864(SlctScreen);
Page=Page<<1;
Column=Column<<3;
cmd_w12864(Column+0x40);
cmd_w12864(Page+0xb8);
for(i=0;i<16;i++) dat_w12864(*(pAdr+i)); //写起始页的16列
cmd_w12864(Column+0x40);
cmd_w12864(Page+0xb9);
for(i=16;i<32;i++) dat_w12864(*(pAdr+i)); //写下一页的16列
}
/***********************************************************************
函数名:dat_r12864
说 明: 读12864数据
输入参数: uchar Page,页地址 uchar Column,列地址
************************************************************************/
uchar dat_r12864(uchar Page,uchar Column)
{
uchar dat;
chekbusy12864();
cmd_w12864(Page+0xb8);
cmd_w12864(Column+0x40);
EX0=0;
P0=0xff;
RW=1;
RS=1;
E=1;
E=0;
E=1;
dat=P0;
E=0;
return(dat);
EX0=1;
}
/***********************************************************************
函数名:vertical
说 明: 该函数可用于在液晶屏指定位置输出一个分辨率为16*16的汉字
输入参数: uchar RowStart,竖线上端点所在行 uchar RowStop, 竖线下端点所在行
uchar Column, 竖线所在列
************************************************************************/
void vertical(uchar RowStart,uchar RowStop,uchar Column)
{
uchar i,sum=0;
if(Column>63) //若列号大于63选择在右屏画竖线
{
choose12864(1);
Column=Column-64;
}
else choose12864(0); //若列号小于63选择在左屏画竖线
if((RowStart/8)!=(RowStop/8))//如果上下端点在不同页
{
for(i=0;i<(8-RowStart%8);i++) sum=sum|((2<<((RowStart%8)+i)));
cmd_w12864(Column+0x40);
cmd_w12864(RowStart/8+0xb8);
dat_w12864(sum);
sum=0;
for(i=0;i<(RowStop/8-RowStart/8-1);i++)
{
cmd_w12864(Column+0x40);
cmd_w12864((RowStart/8)+0xb9+i);
dat_w12864(0xff);
}
for(i=0;i<=(RowStop%8);i++) sum=sum|(2<<i);
cmd_w12864(Column+0x40);
cmd_w12864(RowStop/8+0xb8);
dat_w12864(sum|1);
sum=0;
}
else//如果上下端点在同一页
{
for(i=0;i<=RowStop-RowStart;i++) sum=sum|(2<<(i+(RowStart%8)));
cmd_w12864(0x40|Column);
cmd_w12864(0xb8|(RowStart/8));
dat_w12864(sum);
}
}
/***********************************************************************
函数名:dot
说 明: 点的显示
输入参数: uchar x,X坐标;uchar y,y坐标
************************************************************************/
void dot(uchar x,uchar y)
{
uchar dat;
if(x>63)
{
choose12864(1);
x=x-64;
}
else choose12864(0);
dat=dat_r12864(y/8,x);
cmd_w12864(0x40|x);
cmd_w12864(0xb8|y/8);
dat_w12864((1<<(y%8))|dat);
}
/***********************************************************************
函数名:cleardot
说 明: 清除一个点
输入参数: uchar x,X坐标;uchar y,y坐标
************************************************************************/
void cleardot(uchar x,uchar y)
{
uchar dat,j;
if(x>63)
{
choose12864(1);
x=x-64;
}
else choose12864(0);
dat=dat_r12864(y/8,x);
cmd_w12864(0x40|x);
cmd_w12864(0xb8|y/8);
j=~(1<<y%8);
dat_w12864(dat&j);
}
/***************************************************************************
函数名:DisplayBodyCell
说 明: 显示一个4*4单元格
输入参数: uchar x,X坐标,uchar y,Y坐标(指屏幕被分成4*4小格后的坐标,第几格)
***************************************************************************/
void DisplayBodyCell(uchar *x,uchar *y) //x<24 y<15
{
uchar i,m,n;
if(*x<24&&*y<15)
{
m=(*x)<<2;
n=((*y)<<2)+2;
for(i=0;i<4;i++)
{
dot(31+m,n+i);
dot(34+m,n+i);
}
dot(32+m,n);
dot(32+m,n+1);
dot(32+m,n+3);
dot(33+m,n);
dot(33+m,n+2);
dot(33+m,n+3);
}
}
/*************************************************************************
函数名:ClearBodyCell
说 明: 清楚一个4*4单元格
输入参数: uchar x,X坐标,uchar y,Y坐标(指屏幕被分成4*4小格后的坐标,第几格)
***************************************************************************/
void ClearBodyCell(uchar *x, uchar *y)
{
uchar i,m,n;
m=((*x)<<2)+31;
n=((*y)<<2)+2;
for(i=0;i<4;i++)
{
cleardot(m,n+i);
cleardot(m+1,n+i);
cleardot(m+2,n+i);
cleardot(m+3,n+i);
}
}
/***********************************************************************
函数名:ExtInterrupt
说明: 外部中断处理函数,点击键盘后进入本服务程序,程序用于判断点击的按键。
************************************************************************/
void ExtInterrupt() interrupt 0
{
ButtonNum=(P2>>6);
ButtonNum=ButtonNum&0x03;
if(IsMovInVetical)
{ //当前方向为垂直方向,则不处理上下方向键的按下。
if(ButtonNum==1) MovDirection=3;//左
if(ButtonNum==2) MovDirection=1;//右
}
else
{ //当前方向为水平方向,则不处理左右方向键的按下。
if(ButtonNum==0) MovDirection=4;//上
if(ButtonNum==3) MovDirection=2;//下
}
}
/***********************************************************************
函数名:timer1
说明: 定时中断,产生步进信号
************************************************************************/
void timer1() interrupt 1
{
if(p--)
{
TL0=0;
TH0=0xa0;
IsToStep=0;
}
else
{
deep=0;
IsToStep=1;
TL0=0;
TH0=0x00;
p=20-(dengji<<1);
deep=1;
}
}
|