
我就负责编,刚开始因为12864他把管脚插错了,总是不行,刚开始我还比较急躁。
觉得他连硬件电路都搭不好我怎么编,而且眼看着只剩两三天时间就验收了。
好在后来电路搭好了(就一个管脚接错了而已!),而且我编程顺利,最后验收效果不错。
我觉得玩起来挺爽的,加速键用着爽。
算一个纪念吧。
• #include<avr/io.h>
• #include<avr/interrupt.h>
• #define uchar unsigned char
• #define uint unsigned int
• /********************端口************************/
• #define RS_0 PORTB&=~(1<<0)
• #define RS_1 PORTB|=(1<<0)
• #define RW_0 PORTB&=~(1<<1)
• #define RW_1 PORTB|=(1<<1)
• #define E_0 PORTB&=~(1<<2)
• #define E_1 PORTB|=(1<<2)
• #define RESET_0 PORTB&= ~(1<<4)
• #define RESET_1 PORTB|= (1<<4)
• /**************** 常用操作命令和参数定义 *****************/
•
• #define DisplayClear 0x01 //清屏指令(00000001)
• #define ReturnHome 0x02 //光标回到"00H"(0000001X)
• #define EntryMode 0x06 //进入点设定,光标右移,AC加1(00000110)
• #define DisplayOn 0x0c //整体显示开,游标显示关,反白显示关
• #define DisplayOff 0x08 //整体显示关
• #define CursorOn 0x0e //光标显示开
• #define Reverse 0x0d //反白显示开
• #define Basic 0x30 //基本指令
• #define FAST 0x03;
• #define SLOW 0x05;
• #define NORM 0x04;
• #define Up 0
• #define Down 1
• #define Left 2
• #define Right 3
• /******************************延迟函数***********************************/
• uchar snakex1[16]={32,31,30,29,28,27,26,25,0,0};
• uchar snakey1[16]={16,16,16,16,16,16,16,16,0,0};
• uchar snakex2[16]={82,81,80,79,78,77,26,25,0,0};
• uchar snakey2[16]={16,16,16,16,16,16,16,16,0,0};
• uchar count1,count2;
• uchar stonex1[9]={31,50,10,15,20,2,22,44,47/*,8,5,55,12,34,10*/};
• uchar stoney1[9]={3,21,22,20,35,40,24,11,22/*,41,35,10,5,27,33*/};
• uchar stonex2[9]={70,77,80,100,120,112,90,99,88/*,78,96,111,122,64,100*/};
• uchar stoney2[9]={3,13,11,20,35,15,24,11,22/*,39,25,10,5,41,33*/};
• uchar len1,len2;
• uchar nowdir1,nowdir2;
• uchar flag1;//游戏结束的标志
• uchar flag2;
• uchar stop1,stop2;
• uchar Movex[4]={0,0,-1,1};//依次是上下左右
• uchar Movey[4]={-1,1,0,0};
• uchar speed;
• uchar player;
• void delay(uint ms)
• {
• uint i,j;
• for(i=0;i<ms;i++)
• {
• for(j=0;j<1141;j++);
• }
• }
• /************************检测LCD是否忙***************************/
• void check_busy(void)
• {
• DDRD =0xff;
• RS_0;
• RW_1;
• E_1;
• DDRD =0x00;
• delay(1);
• while(PIND&0x80);
• E_0;
• DDRD =0xff;
•
• }
•
• /***********************************写指令**********************************/
• void write_com(uchar com)
• {
• check_busy();
• RS_0;
• RW_0;
• PORTD=com;
• E_1;
• delay(1);
• E_0;
•
• }
• /***********************************写数据*********************/
• void write_data(uchar write_data)
• {
• check_busy();
• RS_1;
• RW_0;
• PORTD=write_data;
• E_1;
• delay(1);
• E_0;
•
• }
• void DisplayCLR()//GDRAM清屏,如果没有清屏,会出现花屏现象。
• {
• uchar i,j,k;
• write_com(0x36);
• delay(1);
• for(i=0;i<2;i++)
• {
• for(j=0;j<32;j++)
• {
• write_com(0x80+j);
• delay(1);
• if(i==0)
• {
• write_com(0x80);
• delay(1);
• }
• else//写下半屏
• {
• write_com(0x88);
• }
• for(k=0;k<16;k++)
• {
• write_data(0x00);
• delay(1);
• }
• }
• }
• write_com(0x30);
• }
• /********************************初始化**********************************/
• void init(void)
• {
• DDRD=0XFF;
• DDRB|=0x1f;
• E_0;
• RESET_1;
• len1=5;
• len2=5;
• nowdir1=Right;
• nowdir2=Right;
• flag1=0;
• flag2=0;
• count1=0;
• count2=0;
• delay(50);
• RESET_1;
• RESET_0;
• RESET_1;
• delay(50);
• write_com(Basic);
• delay(50);
• write_com(Basic);
• delay(50);
• write_com(DisplayOn);//开显示
• delay(500);
• write_com(DisplayClear);//清屏
• delay(50);
• write_com(EntryMode);//显示模式
• delay(50);
•
• }
• uchar read_write_dataa()
• {
• uchar i;
• check_busy();
• RW_1;
• RS_1;
• delay(1);
• E_0;
• delay(1);
• E_1;
• delay(1);
• DDRD=0X00;
• delay(1);//缺了这句话则不行!!!
• i=PIND;
• delay(1);
• E_0;
• delay(1);
• DDRD=0XFF;
• return i;
• }
• void Showdot(uchar x, uchar y,uchar i)//在128*64的lcd矩阵中显示单个像素点
• {
• uchar x_byte,x_bit;
• uchar y_byte,y_bit;
• x_byte=x/16;
• x_bit=x%16;
• y_byte=y/32;
• y_bit=y%32;
• write_com(0x36);//开扩展指令集
• delay(1);
• write_com(0x80+y_bit);
• delay(1);
• write_com(0x80+x_byte+8*y_byte);
• delay(1);
• read_write_dataa();
• delay(1);
• uchar check_busy1;
• uchar check_busy2;
• check_busy1=read_write_dataa();
• delay(1);
• check_busy2=read_write_dataa();
• delay(1);
•
• if(x_bit<8)
• {
• if(i==1)
• {
• check_busy1 |=(0x01<<(7-x_bit));
• delay(1);
• }
• else
• {
• check_busy1 &= ~(0x01<<(7-x_bit));
• delay(1);
• }
• }
• else
• {
• if(i==1)
• {
• check_busy2|=0x01<<(15-x_bit);
• delay(1);
• }
• else
• {
• check_busy2 &=~(0x01<<(15-x_bit));
• delay(1);
• }
• }
• write_com(0x80+y_bit);
• delay(1);
• write_com(0x80+x_byte+8*y_byte);
• delay(1);
• write_data(check_busy1);
• delay(1);
• write_data(check_busy2);
• delay(1);
• write_com(0x30);
• delay(1);
• }
• /********************************设置xy*******************************************/
• void set_position(uint x,uint y)
• {
• uint adr;
• switch(y)
• {
• case 0: adr = 0x80 + x;
• break; //在第1行y列显示
• case 1: adr = 0x90 + x;
• break; //在第2行y列显示
• case 2: adr = 0x88 + x;
• break; //在第3行y列显示
• case 3: adr = 0x98 + x;
• break; //在第4行y列显示
• default:;
• adr=0x80;
• break;
• }
• write_com(adr);
• }
• /********************************写字符串*******************************************/
• void write_string(uint x,uint y,uchar *a) //显示字符串
• {
• uint i=0;
• set_position(x,y);
• delay(1);
• while(a[i]!='\0')
• {
• write_data(a[i]);
• delay(1);
• i++;
• }
• }
• void Showsnake(uchar * sx,uchar * sy,uchar len)//显示整条蛇
• {
• uchar i;
• for(i=0;i<len;i++)
• {
• Showdot(sx[i],sy[i],1);
• }
• }
• uchar Meetwall(uchar x,uchar y,uchar i)//撞到墙
• {
• if(i==0)
• {
• if(x>0&&x<59&&y>0&&y<45)
• return (0);
• else
• return (1);
• }
• else
• {
• if(x>68&&x<127&&y>0&&y<45)
• return (0);
• else
• return (1);
• }
• }
• uchar Meetself(uchar *sx,uchar *sy,uchar len,uchar x,uchar y)//撞到自己
• {
• uchar i;
• for(i=0;i<len;i++)
• {
• if(sx[i]==x&&sy[i]==y)
• {
• return (1);
• }
• }
• return (0);
• }
• void Move(uchar * sx,uchar * sy,uchar *len,uchar dir,uchar add)//蛇移动函数
• {
• uchar i;
• if(add==1)//add==1时增加尾巴。
• {
• sx[(*len)]=sx[(*len)-1];
• sy[(*len)]=sy[(*len)-1];
• (*len)++;
• }
• else
• Showdot(sx[(*len)-1],sy[(*len)-1],0);
• for(i=(*len)-1;i!=0;i--)
• {
• sx[i]=sx[i-1];
• sy[i]=sy[i-1];
• }
• sx[0]+=Movex[dir];
• sy[0]+=Movey[dir];
• Showdot(sx[0],sy[0],1);
• }
• void write_count(uchar i)//显示分数
• {
• uchar arr[2]="0";
• if(i==1)
• {
• arr[0]+=count1;
• write_string(3,3,arr);
• }
• else
• {
• arr[0]+=count2;
• write_string(7,3,arr);
• }
• }
• void write_result(uchar i)//显示结果
• {
• uchar str1[]="You";
• uchar str21[]="Win!";
• uchar str22[]="Lose!";
• uchar str3[]="Game Over";
• switch(i)
• {
• case 1:
• write_string(1,0,str1);
• write_string(1,1,str22);
• break;
• case 2:
• write_string(5,0,str1);
• write_string(5,1,str22);
• break;
• case 3:
• write_string(2,2,str3);
• break;
• case 4:
• write_string(1,0,str1);
• write_string(1,1,str21);
• break;
• case 5:
• write_string(5,0,str1);
• write_string(5,1,str21);
• break;
• }
• }
• void Frame()
• {
• uchar i;
• for(i=0;i<60;i++)
• {
• Showdot(i,0,1);
• Showdot(i,45,1);
• if(player==2)
• {
• Showdot(i+68,0,1);
• Showdot(i+68,45,1);
• }
• }
• for(i=1;i<45;i++)
• {
• Showdot(0,i,1);
• Showdot(59,i,1);
• if(player==2)
• {
• Showdot(68,i,1);
• Showdot(127,i,1);
• }
• }
• uchar str[]="Count:";
• write_string(0,3,str);
• write_count(1);
• if(player==2)
• {
• write_string(4,3,str);
• write_count(2);
• }
• }
• void Starttimer0()
• {
• TCNT0=0;
• TIMSK |=(1<<TOIE0);
• SREG|=0X80;
• TCCR0 |=speed;
• }
• void Starttimer2()
• {
• TCNT2=0;
• TIMSK |=(1<<TOIE2);
• SREG|=0X80;
• TCCR2|=speed+2;
• }
• uchar key_press()
• {
• uchar i;
• DDRA=0XFF;
• PORTA=0XF0;
•
• DDRA=0X0F;
•
• i=PINA;
• if(i==0XF0)
• {
• DDRA=0XFF;
• return 0;
• }
• else
• {
• DDRA=0XFF;
• return 1;
• }
• }
•
• uchar key_scan()//8个管脚全部接在PINA上
• {
• uchar key,i=0X7F,j;//
• delay(10);//消抖
• if(key_press())
• {
• do
• {
• i=(i<<1|i>>7);//因为每次都只能给一个IO口赋值为0,所以这行语句目的是对这个0循环移位。
• PORTA=i;
• DDRA=0X0F;
•
• key=PINA;
• j=key&0XF0;//读取高4位(高4位为输入,低4位为输出)
•
• }while(j==0XF0);
• switch(key)
• {
• case 0xDE://0b11011110
• key=0x1;
• if(nowdir2!=Left&&flag2==0)
• nowdir2=Right;
• break;
• case 0x7E:
• TCCR2 &=~(0x07);
• TCCR2|=FAST;
• TCCR2+=2;
• while(key_press());//直到按键松开才跳出这个语句。
• TCCR2 &=~(0x07);
• TCCR2|=(speed);
• TCCR2+=2;
• key=0x3;
• break;
• case 0xED:
• key=0x4;
• if(nowdir2!=Up&&flag2==0)
• nowdir2=Down;
• break;
• case 0xDD:
• key=0x5;
• if(nowdir1!=Left&&flag1==0)
• nowdir1=Right;
• break;
• case 0xBD:
• key=0x6;
• if(nowdir2!=Down&&flag2==0)
• nowdir2=Up;
• break;
• case 0x7D:
• TCCR0 &=~(0x07);
• TCCR0 |=FAST;
• while(key_press());//直到按键松开才跳出这个语句。
• TCCR0 &=~(0x07);
• TCCR0|=(speed);
• key=0x7;
•
• break;
• case 0xEB:
• key=0x8;
• if(nowdir1!=Up&&flag1==0)
• nowdir1=Down;
• break;
• case 0xDB:
• key=0x9;
• if(nowdir2!=Right&&flag2==0)
• nowdir2=Left;
• break;
• case 0xBB:
• key=0xA;
• if(nowdir1!=Down&&flag1==0)
• nowdir1=Up;
• break;
• case 0x7B:
• while(key_press());
• stop2=stop2^1;
• key=0xB;
•
• break;
• case 0xD7:
• if(nowdir1!=Right&&flag1==0)
• nowdir1=Left;
•
• break;
• case 0x77://暂停键
• while(key_press());
• stop1=stop1^1;
• key=0xF;
•
• break;
• default:
• key=16;
• }
• }
• else
• {
• key=16;
• }
• return key;
• }
•
• uchar Meetstone(uchar x,uchar y,uchar i)
• {
• if(i==1)
• {
• if(x==stonex1[count1]&&y==stoney1[count1])
• {
• count1 ++;
• if(count1==9)
• {
• flag1=1;
• write_result(4);
• }
• write_count(1);
• return 1;
• }
• else
• return 0;
• }
• else
• {
• if(x==stonex2[count2]&&y==stoney2[count2])
• {
• count2 ++;
• if(count2==9)
• {
• flag2=1;
• write_result(5);
• }
• write_count(2);
• return 1;
• }
• else
• return 0;
• }
• }
• void choose(int i)
• {
• uchar arr0[]="*";
• uchar arr[4][7]={"Hard","Easy","Single","Double"};
• uchar pos=1;
• uchar *arr1;
• uchar *arr3;
• if(i==1)
• {
• arr1=arr[0];
• arr3=arr[1];
• }
• else
• {
• arr1=arr[2];
• arr3=arr[3];
• }
• uchar arr5[]=" ";
• write_string(1,pos,arr0);
• write_string(2,1,arr1);
• write_string(2,2,arr3);
• uchar flag=1;
• while(flag)
• {
• if(key_press())
• {
• switch(key_scan())
• {
• case 7://按键D
• write_string(1,pos,arr5);
• pos=(pos)%2+1;
• delay(1);
• write_string(1,pos,arr0);
• break;
• case 3://按F键确认
• flag=0;
•
• break;
• }
• }
• }
• switch(pos)
• {
• case 1:
• if(i==1)
• { speed=NORM;}
• else
• { player=pos;}
• break;
• default:
• if(i==1)
• { speed=SLOW;}
• else
• { player=pos;}
• break;
• }
• write_com(0x01);//清屏命令
• }
• void write_welcome()
• {
• uchar a1[]="Welwrite_come";
• uchar a2[]=" To";
• uchar a3[]="Greedy Snake";
• write_string(2,1,a1);
• write_string(3,2,a2);
• write_string(1,3,a3);
• while(key_press()==0);
• write_com(0x01);
• }
• int main(void)
• {
•
• init();//初始化驱动12864液晶屏和初始化相关参数。
• write_welcome();//欢迎界面
• choose(1);//选择难易程度
• choose(2);//选择单人或者双人模式
• DisplayCLR();//清屏
• Frame();//显示边框
• Showsnake(snakex1,snakey1,len1);//显示蛇
• Showdot(stonex1[count1],stoney1[count1],1);//显示小豆
• Starttimer0();//启动定时器1
• if(player==2)//双人模式时
• {
• Starttimer2();//启动定时器2
• Showdot(stonex2[count2],stoney2[count2],1);
• Showsnake(snakex2,snakey2,len2);
• }
• while(flag1==0||flag2==0)//循环读取键盘,蛇的转向和加速和暂停等案件处理已经写在key_scan()内部。
• {
• if(key_press())
• {
• key_scan();
• }
• };
• write_result(3);//显示game over
• SREG&=0x7f;//关全局中断,即关定时器,让蛇停止爬行。
• DisplayCLR();//将蛇和小豆和边框清除,而字符型不会清楚。即游戏结果还显示着。
• return 0;
• }
•
• SIGNAL(SIG_OVERFLOW0)//定时器来实现蛇的不断前进
• {
•
• uchar x=snakex1[0]+Movex[nowdir1];//蛇头前进的下一个坐标
• uchar y=snakey1[0]+Movey[nowdir1];//蛇头前进的下一个坐标
• if(flag1==0&&stop1==0)
• {
• if(Meetwall(x,y,0)||Meetself(snakex1,snakey1,len1,x,y))//两个判断函数
• {
• flag1=1;//flag1置1使这条蛇“死了”,即不再动了不再受控制了。
• write_result(1);//显示you lose
•
• }
• else if(Meetstone(x,y,1))//判断有没有吃到小豆
• {
• Move(snakex1,snakey1,&len1,nowdir1,1);//这里move最末一个参数为1,代表move的同时,蛇身体增长一个单位
• Showdot(stonex1[count1],stoney1[count1],1);//显示出新的一个小豆
• }
• else
• {
• Move(snakex1,snakey1,&len1,nowdir1,0);//没有吃到小豆的话则move最末参数为0,即蛇身体长度不变。
• }
• }
•
• }
• SIGNAL(SIG_OVERFLOW2)//同理SIGNAL(SIG_OVERFLOW0)
• {
• if(flag2==0&&stop2==0)
• {
• uchar x=snakex2[0]+Movex[nowdir2];
• uchar y=snakey2[0]+Movey[nowdir2];
• if(Meetwall(x,y,1)||Meetself(snakex2,snakey2,len2,x,y))
• {
• flag2=1;
• write_result(2);
• }
• else if(Meetstone(x,y,2))
• {
• Move(snakex2,snakey2,&len2,nowdir2,1);
• Showdot(stonex2[count2],stoney2[count2],1);
• }
• else
• {
• Move(snakex2,snakey2,&len2,nowdir2,0);
• }
• }
• }
畅学电子







