单片机制作的gamebox,包含射击游戏,赛车游戏,贪食蛇等,有led显示,2个8*8点阵 电路原理图如下:
元件清单:
可以到./src/config.h文件自由配置引脚
单片机源程序如下(有详细的代码注释):
- #include "config.h"
- #define ASPEED 28 //按加速键后的速度
- uint8 ucar=1; //你的车,1靠右,2靠左
- static void keyscan()
- {
- static bit r = 0;
- int8 k = Get_Kvuale(30);
- if(KEY_OK==0) {
- speeds = ASPEED;
- if(!sound_cnt_time | r) Sound_Tone(sound_ON,6,255);
- r=0;
- }
- else{ //随着分数的增加, 游戏速度逐渐加快
- speeds = 200 - scores/10;
- if(!sound_cnt_time | !r) Sound_Tone(sound_ON,1,255);
- r=1;
- }
- if(k==K_LEFT) ucar=1;
- if(k==K_RIGHT) ucar=2;
- }
- void RAC_Game()
- {
- int8 xcar[4][2]={0}; //[2] 0:左/右/无; 1:车的Y轴位置
- uint8 code carport[3][4]={{0,0,0,0},{0x50,0x20,0x70,0x20},{0x0a,0x04,0x0e,0x04}};
- uint8 code track[5]={0x81,0x81,0x81,0x00,0x00};
- uint8 carid=0,lastid=0,stp=0;
- uint8 p,i;
- Glife=1;
- speeds = 200;
- scores = 0;
- for(i=0;i<4;i++){
- xcar[i][1]=i*5;//其它赛车之间间隔控制,重要部分!
- xcar[i][0]=0;
- }
- /******************初始化完成,开始游戏***********************/
- while(Glife){
- // 分层扫描,将画面两边的赛道和赛车分为两次扫描,使跑道跟赛车产生画面对比度
- // uint8 xtmp[16];
- // for(p=0;p<16;p++)//刷新跑道
- // DispRAM[p]=track[(p+stp)%5];//动态跑道算法
- // for(p=0;p<16;p++){
- // xtmp[p]=0x00;
- // for(i=0;i<4;i++) //刷新其他赛车
- // if((0<=(p-xcar[i][1])) && (p-xcar[i][1])<4)
- // xtmp[p] = carport[xcar[i][0]][p-(xcar[i][1])];
- // if(p<4)
- // if(xtmp[p] & carport[ucar][p])//判断你的赛车是否与其它赛车碰撞
- // Glife=0;
- // else
- // xtmp[p] |= carport[ucar][p];
- // }
-
- //同步扫描
- for(p=0;p<16;p++)//刷新跑道
- {
- DispRAM[p]=0x00;
- DispRAM[p]=track[(p+stp)%5];//动态跑道算法
-
- for(i=0;i<4;i++)//刷新其他赛车
- if((0<=(p-xcar[i][1])) && (p-xcar[i][1])<4)
- DispRAM[p] |= carport[xcar[i][0]][p-(xcar[i][1])];
- if(p<4)
- {
- if(DispRAM[p] & carport[ucar][p])//判断你的赛车是否与其它赛车碰撞
- Glife=0;
- else DispRAM[p] |= carport[ucar][p];
- }
- }
- if(tms > speeds)//游戏速度节拍
- {
- stp++;
- if(stp==5) stp=0;//跑道动态算法标记位
- for(i=0;i<4;i++)
- {
- xcar[i][1]--; //其他车跟随跑道下移
- if(xcar[i][1]== -4){
- xcar[i][1]=15;
- if(lastid>0) //游戏规则,如果上次产生的不是空车位,则这一次产生一个空车位
- carid=0;
- else
- carid=rand()%3;//随机产生一辆车
- lastid = carid;
- xcar[i][0]=carid;
- scores ++;
- }
- }
- tms=0;
- }
- keyscan();
- MatxDisp(DispRAM,duty);
- SMG_Display(scores,duty);
- }
- TR2_OFF;
- }
复制代码
- /*
- 2014-1-26 00:00:00 :完成贪吃蛇游戏模型
- 2014-3-8 23:27:05 :增加游戏会随着吃的食物的增加而加快游戏速度
- 2014-3-15 20:06:15 :进行实体硬件测剩,运行良好,但贪吃蛇结构设置太耗RAM,将进行优化。
- */
- #include "config.h"
- #define NORSPEED 360
- #define ASPEED 100
- #define WIDTH 8 //游戏屏幕宽度
- #define LENGTH 16 //游戏屏幕长度
- static struct Food
- {
- uint8 x;//食物的横坐标
- uint8 y;//食物的纵坐标
- }food;
- struct Snake snake;
- enum direc{up, down, left, right};//蛇的运动方向
- static void Snake_Init(); //初始化游戏
- static void Snake_Disp(); //游戏显示
- static void Snake_Run(); //蛇向前走一步
- static void Create_Food(); //随机生成食物
- static void Create_Food()
- {
- uint8 i;
- food.x = rand() % WIDTH; //范围1-16;
- food.y = rand() % LENGTH; //获得随机数种子;//用计数器作为随机数发生器
- for(i=1;i<(snake.node);i++)//检测产生的食物是否与蛇本身重叠
- {
- if((food.x==snake.x[i])&&(food.y==snake.y[i]))
- Create_Food(); //重叠则重新成生
- }
- }
- static void Snake_Init()
- {
- uint8 c;
- for(c=0;c < MAX_SNAKE;c++)//清除内存数据
- {
- snake.x[c]=-1;
- snake.y[c]=-1;
- }
- snake.life = 1; //赋予蛇生命
- snake.node = 3; //默认长度3节
- snake.direc = up;//初始方向
- snake.x[0]=4;
- snake.y[0]=5;
- snake.x[1]=4;
- snake.y[1]=4;
- snake.x[2]=4;
- snake.y[2]=3;
- speeds = NORSPEED; //游戏速度
- tms = 0;
- scores = 0;
- Create_Food(); //生成第一个食物
- }
- static void Snake_Run() //蛇爬行算法
- {
- uint8 i;
- for(i=(snake.node-1);i>0;i--) //蛇头作为前进引导,长江后浪推前浪
- {
- snake.y[i]=snake.y[i-1];
- snake.x[i]=snake.x[i-1];
- }
- switch (snake.direc) //根据蛇的方向标前进
- {
- case up: snake.y[0]+=1; break;
- case down: snake.y[0]-=1; break;
- case left: snake.x[0]-=1; break;
- case right: snake.x[0]+=1; break;
- }
- }
- static void Snake_Disp() //游戏画面显示
- {
- uint8 p = 16;
- // for(p=0;p<snake.node;p++)//绘制蛇图像
- // {
- // delayus(500-duty);
- // DisPoint(snake.x[p],snake.y[p]);
- // delayus(duty/5);
- // cdata = 0xff;
- // }
- // DisPoint(food.x,food.y);//绘制食物图像
- // delayus(duty);
- // cdata = 0xff;
- //
- // for(i=0;i<16;i++)
- // {
- // DispRAM[i] = 0;
- // }
- while(p--) DispRAM[p]=0; //清除缓存
- for(p=0;p<snake.node;p++) //写入新缓存
- {
- DispRAM[snake.y[p]] |= 0x80 >> (snake.x[p]);
- }
- // DispRAM[food.y] |= 0x80 >> (food.x);
-
- MatxDisp(DispRAM,duty);
- DisPoint(7-food.x,food.y);
- delayus(duty);
- }
- void Snake_Game() //游戏过程
- {
- Snake_Init(); //初始化游戏
- Play_Music(sound_canon);
- while(snake.life) //有生命,便可玩
- {
- uint8 i;
- switch(keypad)//直接读取键值,贪吃蛇不需要消抖
- {
- case K_UP: if((snake.direc==left)||(snake.direc==right)) snake.direc=up;
- //按下UP键时,只有蛇在水平方向时才能改变
- break;
- case K_DOWN:if((snake.direc==left)||(snake.direc==right)) snake.direc=down;
- //按下DOWN键时,只有蛇在水平方向时才能改变
- break;
- case K_LEFT:if((snake.direc==up)||(snake.direc==down)) snake.direc=left;
- //按下left键时,只有蛇在垂直方向时才能改变
- break;
- case K_RIGHT:if((snake.direc==up)||(snake.direc==down)) snake.direc=right;
- //按下right键时,只有蛇在垂直方向时才能改变
- break;
- default :
- break;
- }
-
- if(KEY_OK==0) speeds = ASPEED;//加速键
- else speeds = NORSPEED;
- keypad = K_NULL;
-
- if(tms > speeds) //半秒前进一格
- {
- tms=0;
- Snake_Run(); //无聊散步
- }
- if((snake.x[0]==food.x) && (snake.y[0]==food.y))//是否吃到食物
- {
- Sound_Tone(sound_ON,4,5);
- // getfood=1;//直接在此增加蛇长度会在下一个显示扫描产生一个原有数据留影,故通过加长
- snake.node++;
- // game_speed-=10; //每吃一个食物增加10点速度
- Create_Food(); //产生新食物
- }
- if((snake.x[0]>WIDTH-1)||(snake.x[0]<0)||(snake.y[0]>LENGTH-1)||(snake.y[0]<0))//是否碰壁
- {
- snake.life=0; //蛇碰到墙壁死亡
- }
- for(i=3;i<snake.node;i++)//从蛇的第四节开始判断是否撞到自己了,因为蛇头不可能撞到二三四节
- {
- if((snake.x[i]==snake.x[0])&&(snake.y[i]==snake.y[0]))//是否自残
- snake.life=0; //蛇头碰到自身死亡
- }
- Snake_Disp(); //显示游戏图像
- scores = snake.node-3;
- SMG_Display(scores,duty);
- }
- scores = snake.node-3;
- TR2_OFF;
- }
复制代码- /*
- //作者:郑梓滨 Jaupin@126.com
- //日期:2014年10月27日14:04:35
- //功能:复古掌上俄罗斯方块游戏机源代码,包括游戏GUI,俄罗斯方块、贪吃蛇、经典赛车游戏、射击障碍物游戏
- v1.0:
- 2014-7-26 00:00:00 :完成有俄罗斯方块游戏基本模型;
- 2014-7-28 02:12:03 :将原先临时使用的延时键盘扫描改为外部中断状态位检测键;
- 2014-7-28 20:40:37 :完成俄罗斯方块分数计数及分数显示功能;
- 2014-8-1 01:01:54 :将较早之前完成贪吃蛇游戏代码合并植入;
- 2014-8-2 17:04:25 :整理之前的临时源码,使工程文件规范化;
- 2014-8-3 23:50:49 :构建游戏选择画面基本模型,完成画面平移效果;
- 2014-8-5 00:50:04 :改进LED点阵底层驱动,用软件PWM调节画面亮度;
- 2014-8-7 00:53:35 :完成赛车游戏,用PWM分层扫描画面,形成游戏画面对比度;
- 2014-8-8 02:16:44 :完成赛车游戏选择预览画面,并将三个游戏合并在一起;
- 2014-8-12 01:47:07 :将逐行扫描改为逐点扫描,使显示亮度均匀;增加亮度调节功能;
- 2014-9-9 00:32:40 :修改及优化若干细节;
- v1.1:
- 2014-9-18 0:57:23 :重新布局电路,修改原先不合理的地方,为制作PCB板作准备;
- 2014-9-19 22:02:36 :加入游戏音效,并且可以通过软件方式开关声音;
- 2014-9-21 14:59:39 :增加三位mini数码管,实时显示游戏分数,数码管共用点阵并行数据口;
- ~~~~~~~~~~~忘记备注
- 2014-10-20 21:30:15 :加入射击游戏,将GUI模块化,简化流程
- */
- #include "config.h"
- volatile uint8 data keypad = K_NULL; //键盘状态
- volatile uint8 data keycont = 0; //键盘检测消抖定时器
- volatile uint16 data tms = 0; //1ms T0定时器
- bit key_state = 0; //按键状态
- uint16 data speeds = 0; //游戏速度
- uint16 data scores = 0; //游戏计分
- bit Glife = 1; //游戏生命
- bit sound_ON = 1; //音效开关
- uint8 data duty = 80; //PWM,默认亮度
- uint8 data DispRAM[16]={0};
- uint8 code bitman[8]={1,2,4,8,16,32,64,128};//用于数字序号定位0~7bit位
- uint8 code num[10][5]= //阳码
- {
- {0x7,0x5,0x5,0x5,0x7},
- {0x2,0x6,0x2,0x2,0x7},
- {0x7,0x1,0x7,0x4,0x7},
- {0x7,0x1,0x7,0x1,0x7},
- {0x5,0x5,0x7,0x1,0x1},
- {0x7,0x4,0x7,0x1,0x7},
- {0x7,0x4,0x7,0x5,0x7},
- {0x7,0x1,0x1,0x1,0x1},
- {0x7,0x5,0x7,0x5,0x7},
- {0x7,0x5,0x7,0x1,0x7}
- };
- /*********************PORT_INIT********************/
- void Port_Init()
- {
- P0M0 = 0Xff;
- P0M1 = 0X00;
- P1M0 = 0Xff;
- P1M1 = 0X00;
- P2M0 = 0Xff;
- P2M1 = 0X00;
- P3M0 = 0X00;
- P3M1 = 0X00;
- P4M0 = 0Xff;
- P4M1 = 0X00;
- P5M0 = 0Xff;
- P5M1 = 0X00;
- }
- void Init_Timer()
- {
- /******************定时器0中断设置**********************/
- AUXR |= 0x80; //定时器0为1T模式
- TMOD = 0x00; //设置定时器为模式0(16位自动重装载)
- TL0 = T1MS; //初始化计时值
- TH0 = T1MS >> 8;
- TR0 = 1; //定时器0开始计时
- ET0 = 1; //使能定时器0中断
-
- /*****************外部中断设置*************************/
- IT0 = 1; //设置INT0下降沿触发
- EX0 = 1; //使能外部中断INT0
- IT1 = 1; //设置INT1下降沿触发
- EX1 = 1; //使能外部中断INT1
- INT_CLKO |= 0x70; //使能INT2,INT3,INT4(EX4 = 1,EX3 = 1,EX2 = 1
-
- EA = 1;
- }
- void Array_CLR(uint8 *p)
- {
- uint8 i=0;
- while(i!=16)
- {
- p[i] = 0x00;
- i++;
- }
- }
- void ShowScore(uint score)
- {
- uint8 i;
- uint8 qx,bx,sx,gx;
- qx = score /1000;
- bx = score %1000 /100;
- sx = score %100/10;
- gx = score %10;
- Array_CLR(DispRAM);
- for(i=0;i<5;i++)
- DispRAM[8-i] = (num[sx][i]<<4) | (num[gx][i]);
-
- for(i=0;i<5;i++)
- DispRAM[14-i] = (num[qx][i]<<5) | (num[bx][i]<<1);
-
- // MatxDisp(DispRAM,duty);
- }
- void main()
- {
- Port_Init();
- Sound_Init();
- Init_Timer();
- Sound_Tone(1,14,5);//滴
-
- srand(TL0);
- delayms(100);
- Play_Music(sound_game_start);
- Flash_Screen_Clear();
- while(1)
- {
- tms = 0;
- keypad = K_NULL;//清除按键状态
- switch (GUI_Main()) //进入用户游戏选择界面,返回选择的游戏
- {
- case 1: Tetris_Game(); break;
- case 2: Snake_Game(); break;
- case 3: RAC_Game(); break;
- case 4: Shot_Game(); break;
- }
- Play_Music(sound_game_over);
- Flash_Screen_Clear();
- ShowScore(scores); //将分数载入显存
- delayms(300);
-
- keypad = K_NULL;
- while(keypad != K_UP) //在没按下OK键时保持分数显示
- {
- MatxDisp(DispRAM,duty);
- SMG_Display(scores,duty);
- }
- }
- }
- /* Timer0 interrupt routine */
- void T0_Timer_1ms_int() interrupt 1 using 1
- {
- if(tms<0xfffe) tms++; //防止溢出
- if(key_state){ if(!--keycont) key_state=0;}
- if(PIN_TR2)//TR2如果打开,则开始播放音效
- {
- if(!sound_cnt_time--)
- {
- TR2_OFF;
- beep = 1;
- if(music_p[s_p][1])
- {
- Sound_Tone(sound_ON,music_p[s_p][0],music_p[s_p][1]);
- s_p++; //自动装载下一个音符,实现音效与游戏“同时”运行
- }
- }
- }
- if(KEY_DOWN==0 & KEY_UP==0) IAP_CONTR=0x60;//软件复位下载程序
- }
- void T2_Timer_Sound_freq() interrupt 12 //中断入口
- {
- beep = ~beep; //蜂鸣器频率震动
- }
- uint8 Get_Kvuale(uint8 key_delay)//键值消抖处理,参数为灵敏度调节
- {
- uint8 kvuale = K_NULL; //返回的初始值为空值
- if(keypad != K_NULL) //当键值不为NULL时,说明有按键按下
- {
- if(!key_state) //当按键状态位state为0时说明是第一次触发有效,为1时为重复触发
- {
- key_state=1; //置1,防止重复触发
- kvuale = keypad;//获得读取键值
- keycont = key_delay;//载入消抖时间
- }
- keypad = K_NULL; //清楚键值
- }
- return kvuale;
- }
- /*********外部中断按键区**********/
- void exint0() interrupt 0 //INT0
- {
- keypad = 0;
- }
- void exint1() interrupt 2 //INT1
- {
- keypad = 1;
- }
- void exint2() interrupt 10 //INT2
- {
- keypad = 2;
- }
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
GAMEBOX_CODE_Keil5_v1.1.zip
(291.3 KB, 下载次数: 19)
|