我就负责编,刚开始因为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); • } • } • }