Atmega16单片机贪吃蛇小游戏
程序原创,好用!
缺少财富值的可以私信我,我发给你。代码中有qq
代码基于Atmega16 芯片,晶振采用8M,LCD12864采用并行通信,四个独立按键,以下是相关的原理图。
控制贪吃蛇前进的核心思路是:点亮头部,熄灭尾部。
关于蛇身子的点可以采用一个数组来存储。把数组变成一个循环队列,前进头部数据入队,尾部数据出队,这种方法控制起来简单一些,但是比较消耗内存(嗯,有点奢侈)单片机RAM仅1k,蛇的最大长度500左右。
另外我们可以只存下蛇身子的拐点,记录下拐点的方向,就可以得出蛇身子位置信息。(本代码采用此种记录方式)。
现在举例说明一下数据的值,如图所示表示一条蛇,2表示蛇头,1表示蛇尾 structsnake_type //定义一个砖块的结构体每次只写八位数据 {
unsigned char x_head; //头x坐标 0~63
unsigned char y_head; //头y坐标 0~63(为偶数) unsigned char direc_head; //头前进的方向
unsigned char x_end; //尾x坐标 0~63 unsigned char y_end; //尾y坐标 0~63 unsigned char direc_end; //尾前进的方向 } snake;
则数据值如下:
snake.x_head = 1; snake.y_head = 4 ;snake.direc_head = 2; Snake.x_end = 2; snake.y_end = 0;snake.direc_end = 1;
三大重要函数,这三个函数与硬件打交道,为上层游戏编写提供了便利。 snake_data_add()点亮两个像素点 snake_data_dele()熄灭两个像素点
snake_read_data()读取像素点是否已经点亮
简单演示一下效果
VID_20180304_123454.mp4
行了,不多说了,上干货吧!
******************************************************************************************************************************************
Main.c
****************************************************************************************************************************************** #include
#define uchar unsigned char #include\#include\#include\
voiddelay_nms(uintnms) { uinti,j; for(i=0;i voidscan_deal(void) { //返回值:0 不可移动 // 1 可以移动 // 2 吃到苹果 switch(move_forward()) { case 0: show_picture(game_over); //死亡,游戏结束 break; case 2: //可以在此嵌入计分数据代码并减小times的值可以提高难度的功能 appel_add(suiji_data); //产生苹果,游戏继续 break; default: break; } } void main(void) { uchari=0,b=8; lcd_init(); lcd_delay_nms(10); display(); //画空图 snake_init(); snake_data_add(0,0); snake_data_dele(0,0); while(1) { snake_move_scan(100); //多次扫描按键, scan_deal(); } } ****************************************************************************************************************************************** 12864_bing_xing.h ****************************************************************************************************************************************** /******************************************************************************/ /* Name: LCD12864(St7920/St7921) */ /* */ /* Designed by : Date:2016/5/9 */ /* 开发环境:ICCAVR */ /* QQ:1460467003 飘 */ /******************************************************************************/ #define set_bit(register1,bits) (register1|=(1<<(bits))) #define clr_bit(register1,bits) (register1&=~(1<<(bits))) #define get_bit(register1,bits) (register1&=(1<<(bits))) #define lcd_clr 0x01 #define lcd_rs_hset_bit(PORTA,0) #define lcd_rs_lclr_bit(PORTA,0) #define lcd_rw_hset_bit(PORTA,1) #define lcd_rw_lclr_bit(PORTA,1) #define lcd_en_hset_bit(PORTA,2) #define lcd_en_lclr_bit(PORTA,2) #define lcd_data_i PINB #define lcd_data_o PORTB #include\ voidlcd_delay_nms(uintnms) { uinti,j; for(i=0;i //读状态 voidlcd_check_busy(void) { DDRB=0X00; lcd_data_o=0xFF; //lcd_delay_nms(1); lcd_rs_l; lcd_rw_h; lcd_en_l; lcd_en_h; } while (lcd_data_i&0X80); //检测忙信号 lcd_en_l; DDRB=0XFF; lcd_data_o=0xff; // lcd_delay_nms(1); // 1表示数据 0表示命令 void lcd_write_data(ucharon_data,uchar data) //发送指令或数据 { lcd_check_busy(); if(on_data) lcd_rs_h; else lcd_rs_l; lcd_rw_l; lcd_data_o=data; lcd_delay_nms(2);//等待当前工作完成 lcd_en_h; lcd_delay_nms(2);//等待当前工作完成 lcd_en_l; } //读数据 ucharlcd_read_data(void) { uchar data; lcd_check_busy(); lcd_data_o=0xFF; DDRB=0X00; lcd_rs_h; lcd_rw_h; lcd_en_h; lcd_delay_nms(1); data=lcd_data_i; lcd_en_l; return(data); } /* 以屏幕的左上角为原点,X 左——右增大 0——7 两个字节为单位 Y 上——下增大 0——63 位为单位 */ voidlcd_set_xy(ucharx,uchar y) { if(y>31) { lcd_write_data(0,0x80+y-32); //y 轴 lcd_write_data(0,0x88+x); //x 轴 } else { lcd_write_data(0,0x80+y); //y 轴 lcd_write_data(0,0x80+x); //x 轴 } } void lcd_init(void) //LCM初始化 { DDRA|=0X7; PORTA|=0X07; DDRB=0XFF; PORTB=0XFF; set_bit(DDRC,0); set_bit(PORTC,0); //并行模式 lcd_write_data(0,0x30); //八位数据端口,进入基本指令集 lcd_write_data(0,0x01); //显示清屏 lcd_write_data(0,0x06); //光标自增,画面不动 lcd_write_data(0,0x0c); //整体显示,游标关,不反白 } //写内存,为空 void display(void) //图形方式12864显示字模逐行式顺向 { unsigned char i,j; lcd_write_data(0,0x34); //图形方式 for(i=0;i<32;i++) { lcd_write_data(0,0x80+i); //Y lcd_write_data(0,0x80); //X for(j=0;j<16;j++) { lcd_write_data(1,0x00); } } } for(i=0;i<32;i++) { lcd_write_data(0,0x80+i);//Y lcd_write_data(0,0x88); //X for(j=0;j<16;j++) { lcd_write_data(1,0x00); } } //lcd_write_data(0,0x80+22); //lcd_write_data(0,0x88); //for(j=0;j<16;j++) // lcd_write_data(1,0xff); lcd_write_data(0,0x36); //显示图片,逐行式顺向 voidshow_picture(const unsigned char tu[]) { unsigned char i,j; uint k=0; } lcd_write_data(0,0x34); //图形方式 for(i=0;i<32;i++) { lcd_write_data(0,0x80+i); //Y lcd_write_data(0,0x80); //X for(j=0;j<16;j++) { lcd_write_data(1,tu[k]); k++; } } for(i=0;i<32;i++) { lcd_write_data(0,0x80+i);//Y lcd_write_data(0,0x88); //X for(j=0;j<16;j++) { lcd_write_data(1,tu[k]); k++; } } lcd_write_data(0,0x36); /* void LCDClear(void) //清屏 { lcd_write_data(0,0x01); //显示清屏 } void LCDFlash(void) //闪烁效果 { lcd_write_data(0,0x08); //显示清屏 lcd_delay_nms(4); lcd_write_data(0,0x0c); // 显示开及光标设置 lcd_delay_nms(4); lcd_write_data(0,0x08); //显示清屏 lcd_delay_nms(4); lcd_write_data(0,0x0c); // 显示开及光标设置 lcd_delay_nms(4); lcd_write_data(0,0x08); //显示清屏 lcd_delay_nms(4); } voidlcd_draw_jpg(void) { lcd_write_data(0,0x34); //绘图模式设置 lcd_set_xy(0,34); //设置坐标 x y lcd_write_data(1,0xff); //高八位 lcd_write_data(1,0xf1); //低八位 lcd_write_data(0,0x36); } */ /* 并行通信开始信号代码发送数据:0XFA 发送命令:0XF8 接收数据:0XFE 指令代码 进入基本指令集 0x30 清屏 0x01 光标右移 0x06 显示打开游标关游标位置关 0x0c 进入扩充指令集设定状态、关闭显示 开启绘图显示 0x36 配置lcd必须先进入相关的指令集 0X34 设置地址先垂直后水平读写都会改变AC的值 显示图片之前必须对对所有的GDRAM赋值,否则乱码 据网友说,读取数据只支持并行通信,试了多次,感觉网友说的没有错 读取数据之前必须空读一次 */ ****************************************************************************************************************************************** game.h ****************************************************************************************************************************************** /******************************************************************************/ // Name: 游戏主函数 */ */ /* Designed by : Date:2016/5/25 */ /* 开发环境:ICCAVR */ /* QQ:1460467003 飘 */ /******************************************************************************/ //坐标点设定方块的左上方点 //方向参考屏幕正放 structsnake_type //定义一个砖块的结构体每次只写八位数据 { unsigned char x_head; //头x坐标 0~63 unsigned char y_head; //头y坐标 0~63 unsigned char direc_head; //头前进的方向 unsigned char x_end; //尾x坐标 0~63 unsigned char y_end; //尾y坐标 0~63 unsigned char direc_end; //尾前进的方向 } snake; //随机数据的缓存指针 unsignedintsuiji_num=0; #define DOT_NUMBER_MAX 40 //x 0~63 两位为单位 y(偶数) 0~63 //点亮坐标对应的像素点 voidsnake_data_add(ucharx,uchar y) { uchardata_h,data_l; switch(x & 0x07) { case 0: { lcd_set_xy(x >> 3, y); lcd_read_data(); data_h=lcd_read_data(); //data_l=lcd_read_data(); lcd_set_xy(x >> 3,y); lcd_write_data(1,data_h|0xc0); //lcd_write_data(1,data_l|(data<<6)); break; } case 1: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); //data_l=lcd_read_data(); lcd_set_xy(x >> 3,y); lcd_write_data(1,data_h|0x30); //lcd_write_data(1,data_l|(data<<6)); break; } case 2: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); //data_l=lcd_read_data(); lcd_set_xy(x >> 3,y); lcd_write_data(1,data_h|0x0c); //lcd_write_data(1,data_l|(data<<6)); break; } case 3: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); //data_l=lcd_read_data(); lcd_set_xy(x >> 3,y); lcd_write_data(1,data_h|0x03); //lcd_write_data(1,data_l|(data<<6)); break; } case 4: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); data_l=lcd_read_data(); lcd_set_xy(x >> 3,y); lcd_write_data(1,data_h); lcd_write_data(1,data_l|0xc0); break; } case 5: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); data_l=lcd_read_data(); lcd_set_xy(x >> 3,y); lcd_write_data(1,data_h); lcd_write_data(1,data_l|0x30); break; } case 6: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); data_l=lcd_read_data(); lcd_set_xy(x >> 3,y); lcd_write_data(1,data_h); lcd_write_data(1,data_l|0x0c); break; } case 7: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); data_l=lcd_read_data(); lcd_set_xy(x >> 3,y); lcd_write_data(1,data_h); lcd_write_data(1,data_l|0x03); break; } default : break; } } //x 0~63 两位为单位 y(偶数) 0~63 //熄灭坐标对应的像素点 voidsnake_data_dele(ucharx,uchar y) { uchardata_h,data_l; switch(x & 0x07) { case 0: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); //data_l=lcd_read_data(); lcd_set_xy(x >> 3,y); lcd_write_data(1,data_h&0x3f); //lcd_write_data(1,data_l&(~(data<<6))); break; } case 1: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); //data_l=lcd_read_data(); lcd_set_xy(x >> 3,y); lcd_write_data(1,data_h&0xcf); //lcd_write_data(1,data_l&(~(data<<6))); break; } case 2: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); //data_l=lcd_read_data(); lcd_set_xy(x >> 3,y); lcd_write_data(1,data_h&0xf3); //lcd_write_data(1,data_l&(~(data<<6))); break; } case 3: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); //data_l=lcd_read_data(); lcd_set_xy(x >> 3,y); lcd_write_data(1,data_h&0xfc); //lcd_write_data(1,data_l&(~(data<<6))); break; } case 4: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); data_l=lcd_read_data(); lcd_set_xy(x >> 3,y); lcd_write_data(1,data_h); lcd_write_data(1,data_l&0x3f); break; } case 5: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); data_l=lcd_read_data(); lcd_set_xy(x >> 3,y); lcd_write_data(1,data_h); lcd_write_data(1,data_l&0xcf); break; } case 6: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); data_l=lcd_read_data(); lcd_set_xy(x >> 3,y); lcd_write_data(1,data_h); lcd_write_data(1,data_l&0xf3); break; } case 7: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h = lcd_read_data(); data_l = lcd_read_data(); lcd_set_xy(x >> 3,y); lcd_write_data(1,data_h); lcd_write_data(1,data_l&0xfc); break; } default : break; } } //x 0~63 两位为单位 y(偶数) 0~63 //读取坐标对应的像素点的值数据长度 2 ucharsnake_read_data(ucharx,uchar y) { uchardata_h,data_l; switch(x & 0x07) { case 0: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); return (data_h>>6); break; } case 1: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); return ((data_h>>4)&0x03); break; } case 2: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); return ((data_h>>2)&0x03); break; } case 3: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); return (data_h&0x03); break; } case 4: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); data_l=lcd_read_data(); return (data_l>>6); break; } case 5: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); data_l=lcd_read_data(); return ((data_l>>4)&0x03); break; } case 6: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); data_l=lcd_read_data(); return ((data_l>>2)&0x03); break; } case 7: { lcd_set_xy(x >> 3,y); lcd_read_data(); data_h=lcd_read_data(); data_l=lcd_read_data(); return (data_l&0x03); break; } default : return 0; break; } } //判断是否为障碍物返回值: 0无数据 // 1 苹果 // 2 障碍物 ucharcheck_down(ucharx,uchar y) { if(snake_read_data(x,y+2)==0) return 0; else { if(x>1&&snake_read_data(x-1,y+2)==3) return 2; if(x<63&&snake_read_data(x+1,y+2)==3) return 2; if(y<60&&snake_read_data(x,y+4)==3) return 2; return 1; } } //判断是否为障碍物返回值: 0无数据 // 1 苹果 // 2 障碍物 ucharcheck_up(ucharx,uchar y) { if(snake_read_data(x,y-2)==0) return 0; else { if(x>1&&snake_read_data(x-1,y-2)==3) return 2; if(x<63&&snake_read_data(x+1,y-2)==3) return 2; if(y>3&&snake_read_data(x,y-4)==3) return 2; return 1; } } //判断是否为障碍物返回值: 0无数据 // 1 苹果 // 2 障碍物 ucharcheck_right(ucharx,uchar y) { if(snake_read_data(x+1,y)==0) return 0; else { if(y>1&&snake_read_data(x+1,y-2)==3) return 2; if(y<62&&snake_read_data(x+1,y+2)==3) return 2; if(x<62&&snake_read_data(x+2,y)==3) return 2; return 1; } } //判断是否为障碍物返回值: 0无数据 // 1 苹果 // 2 障碍物 ucharcheck_left(ucharx,uchar y) { if(snake_read_data(x-1,y)==0) return 0; else { if(y<62 &&snake_read_data(x-1,y+2)==3) return 2; if(y>1&&snake_read_data(x-1,y-2)==3) return 2; if(x>1&&snake_read_data(x-2,y)==3) return 2; return 1; } } //记录转折点的位置及转折方向 //方向值 0,1,2,3 表示的方向为上左下右 struct { unsigned char xy[DOT_NUMBER_MAX][4];//反指向正指向 x坐标 y坐标 signed char num_start; //指向蛇尾要更新的位置num_start与num_end一致时说明没有没有了转折点 signed char num_end; //指向下次新的转折点存储的位置 unsigned char dir; //值 0:反指向,数据递减更新 1:正指向,数据递增更 新 } p; //蛇初始化 voidsnake_init(void) { uchari; p.num_start = 0; p.num_end = 0; p.dir = 1; //正向存储 for(i=0; i<3; i++) //画蛇 { snake_data_add(i,62); snake_data_add(i,63); } snake.x_head=2; snake.y_head=62; //x轴 0~63 //y轴 snake.direc_head=3; snake.x_end=0; snake.y_end=62; snake.direc_end=3; snake_data_add(10,62);//增加苹果 snake_data_add(10,63); } //求两个数的差的绝对值 uchardiat(uchara,uchar b) { if(a < b) return b - a; else return a - b; } //交换数据 voidswap_data(uchar *p1, uchar *p2) { uchar data; data = *p1; *p1 = *p2; *p2 = data; } //指针自加运算,越界处理 voiddata_add(signed char *p) { ++*p; if(*p > DOT_NUMBER_MAX - 1) *p = 0; } //指针自减运算,越界处理 voiddata_dec(signed char *p) { --*p; if(*p < 0) *p = DOT_NUMBER_MAX - 1; } //头尾互换 void head_end_swap(void)//头尾互换 { swap_data(&snake.x_head, &snake.x_end); //互换头尾的x swap_data(&snake.y_head, &snake.y_end); //互换头尾的y swap_data(&snake.direc_head, &snake.direc_end); //互换头尾的方向 snake.direc_head=(snake.direc_head + 2) & 0x03; //头方向取反 snake.direc_end=(snake.direc_end + 2) & 0x03; //尾方向取反 } //添加一个转折点 voidp_add(uchardir) { if(p.dir) //正向移动 { //加载数据 p.xy[p.num_end][0] = (snake.direc_head + 2) & 0x03; //反指向 p.xy[p.num_end][1] = dir; //正指向 p.xy[p.num_end][2] = snake.x_head; //加载x坐标 p.xy[p.num_end][3] = snake.y_head; //加载y坐标 //更新缓存指针 data_add(&p.num_end); } else //反向移动 { //加载数据 p.xy[p.num_start][0] = dir; //反方向 p.xy[p.num_start][1] = (snake.direc_head + 2) & 0x03; //正方向 p.xy[p.num_start][2] = snake.x_head; //加载x坐标 p.xy[p.num_start][3] = snake.y_head; //加载y坐标 //更新缓存指针 data_dec(&p.num_start); } } //转折点顺序取反 voidp_inverse(void) { //更新缓存指针 if(p.dir) //之前正向移动 { data_dec(&p.num_start); data_dec(&p.num_end); } else { data_add(&p.num_start); data_add(&p.num_end); } p.dir ^= 0x01; //取反 } //输入:按键值 3 4 5 6 //表示的方向为上左下右 //改变方向,不改变坐标 ucharsnake_head_change(uchar key) { uchar temp; temp = diat(key, snake.direc_head); //获得方向差switch(temp) { //同向 case 0: return 1; //左转或右转 case 1: p_add(key);//把当前数据加载到拐点缓存区 snake.direc_head = key; //更新蛇头方向 return 0; //反方向 0 同向 1 左右拐2 反向 case 2: p_inverse();//更改转折点 head_end_swap();//更换蛇头和蛇尾 return 0; //左转或右转 case 3: p_add(key);//把当前数据加载到拐点缓存区 snake.direc_head = key; //更新蛇头方向 return 0; default : return 0; } } //熄灭尾灯,更新尾部坐标 voidsnake_end_deal(void) { //熄灭当前位置的点 snake_data_dele(snake.x_end,snake.y_end); snake_data_dele(snake.x_end,snake.y_end+1); if(p.dir) //正方向 { if(snake.x_end == p.xy[p.num_start][2] && snake.y_end == p.xy[p.num_start][3] && p.num_end != p.num_start) //蛇尾处在转折点处 { snake.direc_end = p.xy[p.num_start][1]; //赋值改变尾巴方向 data_add(&p.num_start); } } else //反方向 { if(snake.x_end == p.xy[p.num_end][2] && snake.y_end == p.xy[p.num_end][3] && p.num_end != p.num_start) //蛇尾处在转折点处 { snake.direc_end = p.xy[p.num_end][0]; //赋值改变尾巴方向 data_dec(&p.num_end); } } //改变坐标 switch(snake.direc_end) { case 0: snake.y_end-=2; break; case 1: snake.x_end--; break; case 2: snake.y_end+=2; break; case 3: snake.x_end++; break; } } //方向值 0,1,2,3 表示的方向为上左下右 /* 函数功能:移动蛇遇到苹果则吃苹果遇到障碍物停下来 返回值:0 不可移动 1 可以移动 2 吃到苹果 */ ucharmove_forward(void) { uchar data , flag = 2; switch(snake.direc_head) { case 0: //头朝上 data=check_up(snake.x_head,snake.y_head); if(snake.y_head< 1 || data==2)//不能移动 flag = 0; else { snake.y_head -= 2; if(data==0) //可以移动 { snake_data_add(snake.x_head,snake.y_head); snake_data_add(snake.x_head,snake.y_head+1); snake_end_deal(); flag = 1; } } break; case 1: //头朝左 data=check_left(snake.x_head,snake.y_head); if(snake.x_head< 1 || data == 2)//不能移动 flag = 0; else { snake.x_head--; if(data == 0)//可以移动 { snake_data_add(snake.x_head,snake.y_head); snake_data_add(snake.x_head,snake.y_head+1); snake_end_deal(); flag = 1; } } break; case 2: //头朝下 data=check_down(snake.x_head,snake.y_head); if(snake.y_head>61 || data==2)//不能移动 flag = 0; else { snake.y_head+=2; if(data==0)//可以移动 { snake_data_add(snake.x_head,snake.y_head); snake_data_add(snake.x_head,snake.y_head+1); snake_end_deal(); flag = 1; } } break; case 3: //头朝右 data=check_right(snake.x_head,snake.y_head); if(snake.x_head>62 || data == 2)//不能移动 flag = 0; else { snake.x_head++; if(data==0)//可以移动 { snake_data_add(snake.x_head,snake.y_head); snake_data_add(snake.x_head,snake.y_head+1); snake_end_deal(); flag = 1; } } break; default: break; } return flag; } /* 函数功能: 画一个有效的苹果然后退出 */ voidappel_add(constuint *data) { ucharxx,yy; while(1) { xx = data[suiji_num] & 0x1f; //获得新的苹果的坐标x yy = data[suiji_num+1] & 0x1f; //获得新的苹果的坐标y if(yy& 0x01) yy--; //判断新的苹果所在位置是否已经点亮,已经点亮:重新计算获得坐标 // 熄灭:画苹果,退出while(1) if(snake_read_data(xx,yy)==0) { snake_data_add(xx,yy); snake_data_add(xx,yy+1); break; } suiji_num++; if(suiji_num==125) suiji_num=0; } } ****************************************************************************************************************************************** key.h ****************************************************************************************************************************************** /******************************************************************************/ /* Name: key */ /* PD2 PD3 PA4 PA5 对应S1~S4 */ /* Designed by : Date:2016/5/25 */ /* 开发环境:ICCAVR */ /* QQ:1460467003 飘 */ /******************************************************************************/ #define uchar unsigned char #define uint unsigned int uchar times=14; //产生延迟函数 voids_us(unsigned int t) { for(;t>1;t--); } ucharkey_scan(void) { uchar key; DDRD|=0X0C; PORTD|=0X0C; DDRD&=0XF3; DDRA|=0X30; PORTA|=0X30; DDRA&=0XCF; key=(PINA&0X30)|(PIND&0x0c); if(key==0x3c) return 0; else return 1; } ucharkey_press(void) { uchar key1; if(key_scan) s_us(500); key1=(PINA&0X30)|(PIND&0x0c); switch(key1) { case 0x38:s_us(500); //while(key_scan()); return 0; //key3 上 case 0x34: s_us(500); } } //while(key_scan()); return 2; //key4 下 case 0x2c:s_us(500); //while(key_scan()); return 1; //key5 左 case 0x1c: s_us(500); //while(key_scan()); return 3; //key6 右 default : // s_us(100); return 4; //循环多次扫描按键,在此期间,蛇没有发生变化,所以只进行一次数据读取,有效数据为 //最后按下的按键 voidsnake_move_scan(uchar time) { uint i,j,k1 = 5,k2 = 4; for(j=0;j