找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2438|回复: 1
收起左侧

单片机制作的GAMEBOX_Keil5_v1.1源码与原理图(射击,赛车,贪食蛇)

[复制链接]
ID:407334 发表于 2018-10-10 08:00 | 显示全部楼层 |阅读模式
单片机制作的gamebox,包含射击游戏,赛车游戏,贪食蛇等,有led显示,2个8*8点阵 电路原理图如下:
0.png

元件清单:
0.png

可以到./src/config.h文件自由配置引脚
0.png

0.png

单片机源程序如下(有详细的代码注释):
  1. #include "config.h"

  2. #define ASPEED 28         //按加速键后的速度
  3. uint8 ucar=1;                //你的车,1靠右,2靠左

  4. static void keyscan()
  5. {
  6.         static bit r = 0;
  7.         int8 k = Get_Kvuale(30);
  8.         if(KEY_OK==0) {
  9.                 speeds = ASPEED;
  10.                 if(!sound_cnt_time | r) Sound_Tone(sound_ON,6,255);
  11.                 r=0;
  12.         }
  13.         else{        //随着分数的增加, 游戏速度逐渐加快
  14.                 speeds = 200 - scores/10;
  15.                 if(!sound_cnt_time | !r) Sound_Tone(sound_ON,1,255);
  16.                 r=1;
  17.         }
  18.         if(k==K_LEFT)        ucar=1;
  19.         if(k==K_RIGHT)        ucar=2;
  20. }
  21. void RAC_Game()
  22. {        
  23.         int8 xcar[4][2]={0};        //[2] 0:左/右/无;        1:车的Y轴位置
  24.         uint8 code carport[3][4]={{0,0,0,0},{0x50,0x20,0x70,0x20},{0x0a,0x04,0x0e,0x04}};
  25.         uint8 code track[5]={0x81,0x81,0x81,0x00,0x00};
  26.         uint8 carid=0,lastid=0,stp=0;
  27.         uint8 p,i;
  28.         Glife=1;
  29.         speeds = 200;
  30.         scores = 0;
  31.         for(i=0;i<4;i++){
  32.                 xcar[i][1]=i*5;//其它赛车之间间隔控制,重要部分!
  33.                 xcar[i][0]=0;
  34.         }        
  35.         /******************初始化完成,开始游戏***********************/
  36.         while(Glife){        
  37. //                分层扫描,将画面两边的赛道和赛车分为两次扫描,使跑道跟赛车产生画面对比度
  38. //                uint8 xtmp[16];
  39. //                for(p=0;p<16;p++)//刷新跑道
  40. //                        DispRAM[p]=track[(p+stp)%5];//动态跑道算法
  41. //                for(p=0;p<16;p++){
  42. //                        xtmp[p]=0x00;
  43. //                        for(i=0;i<4;i++)        //刷新其他赛车
  44. //                                if((0<=(p-xcar[i][1])) && (p-xcar[i][1])<4)        
  45. //                                        xtmp[p] = carport[xcar[i][0]][p-(xcar[i][1])];
  46. //                        if(p<4)
  47. //                                if(xtmp[p] & carport[ucar][p])//判断你的赛车是否与其它赛车碰撞
  48. //                                        Glife=0;
  49. //                                else
  50. //                                        xtmp[p] |= carport[ucar][p];
  51. //                }
  52.                
  53.                 //同步扫描
  54.                 for(p=0;p<16;p++)//刷新跑道
  55.                 {
  56.                         DispRAM[p]=0x00;
  57.                         DispRAM[p]=track[(p+stp)%5];//动态跑道算法
  58.                         
  59.                         for(i=0;i<4;i++)//刷新其他赛车
  60.                                 if((0<=(p-xcar[i][1])) && (p-xcar[i][1])<4)        
  61.                                         DispRAM[p] |= carport[xcar[i][0]][p-(xcar[i][1])];
  62.                         if(p<4)
  63.                         {
  64.                                 if(DispRAM[p] & carport[ucar][p])//判断你的赛车是否与其它赛车碰撞
  65.                                         Glife=0;
  66.                                 else        DispRAM[p] |= carport[ucar][p];
  67.                         }
  68.                 }
  69.                 if(tms > speeds)//游戏速度节拍
  70.                 {        
  71.                         stp++;
  72.                         if(stp==5) stp=0;//跑道动态算法标记位
  73.                         for(i=0;i<4;i++)
  74.                         {
  75.                                 xcar[i][1]--;        //其他车跟随跑道下移
  76.                                 if(xcar[i][1]== -4){
  77.                                         xcar[i][1]=15;
  78.                                         if(lastid>0)        //游戏规则,如果上次产生的不是空车位,则这一次产生一个空车位
  79.                                                 carid=0;
  80.                                         else
  81.                                                 carid=rand()%3;//随机产生一辆车
  82.                                         lastid = carid;
  83.                                         xcar[i][0]=carid;
  84.                                         scores ++;
  85.                                 }
  86.                         }        
  87.                         tms=0;
  88.                 }
  89.                 keyscan();
  90.                 MatxDisp(DispRAM,duty);
  91.                 SMG_Display(scores,duty);
  92.         }
  93.         TR2_OFF;
  94. }
复制代码

  1. /*
  2.         2014-1-26 00:00:00        :完成贪吃蛇游戏模型
  3.         2014-3-8 23:27:05        :增加游戏会随着吃的食物的增加而加快游戏速度
  4.         2014-3-15 20:06:15        :进行实体硬件测剩,运行良好,但贪吃蛇结构设置太耗RAM,将进行优化。
  5. */
  6. #include "config.h"

  7. #define NORSPEED 360
  8. #define ASPEED 100
  9. #define WIDTH  8        //游戏屏幕宽度
  10. #define LENGTH 16        //游戏屏幕长度

  11. static struct Food
  12. {
  13.     uint8 x;//食物的横坐标
  14.     uint8 y;//食物的纵坐标
  15. }food;

  16. struct Snake snake;

  17. enum direc{up, down, left, right};//蛇的运动方向

  18. static void Snake_Init();                //初始化游戏
  19. static void Snake_Disp();        //游戏显示
  20. static void Snake_Run();                //蛇向前走一步
  21. static void Create_Food();                //随机生成食物

  22. static void Create_Food()
  23. {
  24.         uint8 i;
  25.         food.x = rand() % WIDTH;        //范围1-16;
  26.         food.y = rand() % LENGTH;        //获得随机数种子;//用计数器作为随机数发生器
  27.         for(i=1;i<(snake.node);i++)//检测产生的食物是否与蛇本身重叠
  28.         {
  29.                 if((food.x==snake.x[i])&&(food.y==snake.y[i]))
  30.                         Create_Food();        //重叠则重新成生
  31.         }
  32. }

  33. static void Snake_Init()
  34. {        
  35.         uint8 c;        
  36.         for(c=0;c < MAX_SNAKE;c++)//清除内存数据
  37.         {
  38.                 snake.x[c]=-1;
  39.                 snake.y[c]=-1;
  40.         }
  41.         snake.life = 1;                                //赋予蛇生命
  42.         snake.node = 3;                        //默认长度3节
  43.         snake.direc = up;//初始方向
  44.         snake.x[0]=4;
  45.         snake.y[0]=5;
  46.         snake.x[1]=4;
  47.         snake.y[1]=4;
  48.         snake.x[2]=4;
  49.         snake.y[2]=3;
  50.         speeds = NORSPEED;         //游戏速度
  51.         tms = 0;
  52.         scores = 0;
  53.         Create_Food();                //生成第一个食物
  54. }

  55. static void Snake_Run()        //蛇爬行算法
  56. {        
  57.         uint8 i;
  58.         for(i=(snake.node-1);i>0;i--)                //蛇头作为前进引导,长江后浪推前浪
  59.         {
  60.                 snake.y[i]=snake.y[i-1];
  61.                 snake.x[i]=snake.x[i-1];
  62.         }
  63.         switch (snake.direc)        //根据蛇的方向标前进
  64.         {
  65.                 case up:         snake.y[0]+=1;        break;
  66.                 case down:        snake.y[0]-=1;        break;
  67.                 case left:        snake.x[0]-=1;        break;
  68.                 case right:        snake.x[0]+=1;        break;
  69.         }
  70. }

  71. static void Snake_Disp()        //游戏画面显示
  72. {
  73.         uint8 p = 16;
  74. //        for(p=0;p<snake.node;p++)//绘制蛇图像
  75. //        {               
  76. //                delayus(500-duty);
  77. //                DisPoint(snake.x[p],snake.y[p]);
  78. //                delayus(duty/5);
  79. //                cdata = 0xff;
  80. //        }
  81. //        DisPoint(food.x,food.y);//绘制食物图像
  82. //        delayus(duty);
  83. //        cdata = 0xff;
  84. //        
  85. //        for(i=0;i<16;i++)
  86. //        {
  87. //                DispRAM[i] = 0;
  88. //        }
  89.         while(p--) DispRAM[p]=0;        //清除缓存        
  90.         for(p=0;p<snake.node;p++)        //写入新缓存
  91.         {        
  92.                 DispRAM[snake.y[p]] |= 0x80 >> (snake.x[p]);
  93.         }
  94. //        DispRAM[food.y] |= 0x80 >> (food.x);
  95.         
  96.         MatxDisp(DispRAM,duty);
  97.         DisPoint(7-food.x,food.y);
  98.         delayus(duty);
  99. }

  100. void Snake_Game()        //游戏过程
  101. {
  102.         Snake_Init();                //初始化游戏
  103.         Play_Music(sound_canon);
  104.         while(snake.life)        //有生命,便可玩
  105.         {
  106.                 uint8 i;
  107.                 switch(keypad)//直接读取键值,贪吃蛇不需要消抖
  108.                 {
  109.                         case K_UP:        if((snake.direc==left)||(snake.direc==right))        snake.direc=up;
  110.                                 //按下UP键时,只有蛇在水平方向时才能改变
  111.                                 break;
  112.                         case K_DOWN:if((snake.direc==left)||(snake.direc==right))        snake.direc=down;
  113.                                 //按下DOWN键时,只有蛇在水平方向时才能改变
  114.                                 break;
  115.                         case K_LEFT:if((snake.direc==up)||(snake.direc==down))                snake.direc=left;
  116.                                 //按下left键时,只有蛇在垂直方向时才能改变
  117.                                 break;
  118.                         case K_RIGHT:if((snake.direc==up)||(snake.direc==down))                snake.direc=right;
  119.                                 //按下right键时,只有蛇在垂直方向时才能改变
  120.                                 break;
  121.                         default :
  122.                                 break;
  123.                 }
  124.                
  125.                 if(KEY_OK==0) speeds = ASPEED;//加速键
  126.                 else speeds = NORSPEED;
  127.                 keypad = K_NULL;
  128.                
  129.                 if(tms > speeds)        //半秒前进一格
  130.                 {
  131.                         tms=0;
  132.                         Snake_Run();        //无聊散步
  133.                 }
  134.                 if((snake.x[0]==food.x) && (snake.y[0]==food.y))//是否吃到食物
  135.                 {
  136.                         Sound_Tone(sound_ON,4,5);
  137. //                        getfood=1;//直接在此增加蛇长度会在下一个显示扫描产生一个原有数据留影,故通过加长
  138.                         snake.node++;
  139. //                        game_speed-=10;        //每吃一个食物增加10点速度
  140.                         Create_Food();        //产生新食物
  141.                 }
  142.                 if((snake.x[0]>WIDTH-1)||(snake.x[0]<0)||(snake.y[0]>LENGTH-1)||(snake.y[0]<0))//是否碰壁
  143.                 {
  144.                         snake.life=0;        //蛇碰到墙壁死亡
  145.                 }
  146.                 for(i=3;i<snake.node;i++)//从蛇的第四节开始判断是否撞到自己了,因为蛇头不可能撞到二三四节
  147.                 {
  148.                         if((snake.x[i]==snake.x[0])&&(snake.y[i]==snake.y[0]))//是否自残
  149.                                 snake.life=0;        //蛇头碰到自身死亡
  150.                 }
  151.                 Snake_Disp();        //显示游戏图像
  152.                 scores = snake.node-3;
  153.                 SMG_Display(scores,duty);
  154.         }
  155.         scores = snake.node-3;
  156.         TR2_OFF;
  157. }
复制代码
  1. /*
  2. //作者:郑梓滨        Jaupin@126.com
  3. //日期:2014年10月27日14:04:35   
  4. //功能:复古掌上俄罗斯方块游戏机源代码,包括游戏GUI,俄罗斯方块、贪吃蛇、经典赛车游戏、射击障碍物游戏
  5. v1.0:
  6.         2014-7-26 00:00:00        :完成有俄罗斯方块游戏基本模型;
  7.         2014-7-28 02:12:03        :将原先临时使用的延时键盘扫描改为外部中断状态位检测键;
  8.         2014-7-28 20:40:37        :完成俄罗斯方块分数计数及分数显示功能;
  9.         2014-8-1 01:01:54        :将较早之前完成贪吃蛇游戏代码合并植入;
  10.         2014-8-2 17:04:25        :整理之前的临时源码,使工程文件规范化;
  11.         2014-8-3 23:50:49        :构建游戏选择画面基本模型,完成画面平移效果;
  12.         2014-8-5 00:50:04        :改进LED点阵底层驱动,用软件PWM调节画面亮度;
  13.         2014-8-7 00:53:35        :完成赛车游戏,用PWM分层扫描画面,形成游戏画面对比度;
  14.         2014-8-8 02:16:44        :完成赛车游戏选择预览画面,并将三个游戏合并在一起;
  15.         2014-8-12 01:47:07        :将逐行扫描改为逐点扫描,使显示亮度均匀;增加亮度调节功能;
  16.         2014-9-9 00:32:40        :修改及优化若干细节;
  17. v1.1:
  18.         2014-9-18 0:57:23        :重新布局电路,修改原先不合理的地方,为制作PCB板作准备;
  19.         2014-9-19 22:02:36        :加入游戏音效,并且可以通过软件方式开关声音;
  20.         2014-9-21 14:59:39        :增加三位mini数码管,实时显示游戏分数,数码管共用点阵并行数据口;
  21.         ~~~~~~~~~~~忘记备注
  22.         2014-10-20 21:30:15        :加入射击游戏,将GUI模块化,简化流程
  23. */

  24. #include "config.h"
  25. volatile uint8 data keypad = K_NULL;        //键盘状态
  26. volatile uint8 data keycont = 0;                //键盘检测消抖定时器
  27. volatile uint16 data tms = 0;                        //1ms T0定时器
  28. bit key_state = 0;                                                //按键状态

  29. uint16 data speeds = 0;                //游戏速度
  30. uint16 data scores = 0;                //游戏计分
  31. bit Glife = 1;                                //游戏生命
  32. bit sound_ON = 1;                        //音效开关
  33. uint8 data duty = 80;                //PWM,默认亮度
  34. uint8 data DispRAM[16]={0};
  35. uint8 code bitman[8]={1,2,4,8,16,32,64,128};//用于数字序号定位0~7bit位

  36. uint8 code num[10][5]=                //阳码
  37. {
  38.         {0x7,0x5,0x5,0x5,0x7},
  39.         {0x2,0x6,0x2,0x2,0x7},
  40.         {0x7,0x1,0x7,0x4,0x7},
  41.         {0x7,0x1,0x7,0x1,0x7},
  42.         {0x5,0x5,0x7,0x1,0x1},
  43.         {0x7,0x4,0x7,0x1,0x7},
  44.         {0x7,0x4,0x7,0x5,0x7},
  45.         {0x7,0x1,0x1,0x1,0x1},
  46.         {0x7,0x5,0x7,0x5,0x7},
  47.         {0x7,0x5,0x7,0x1,0x7}
  48. };

  49. /*********************PORT_INIT********************/
  50. void Port_Init()
  51. {
  52.         P0M0 = 0Xff;
  53.         P0M1 = 0X00;
  54.         P1M0 = 0Xff;
  55.         P1M1 = 0X00;
  56.         P2M0 = 0Xff;
  57.         P2M1 = 0X00;
  58.         P3M0 = 0X00;
  59.         P3M1 = 0X00;
  60.         P4M0 = 0Xff;
  61.         P4M1 = 0X00;
  62.         P5M0 = 0Xff;
  63.         P5M1 = 0X00;
  64. }

  65. void Init_Timer()
  66. {
  67. /******************定时器0中断设置**********************/
  68.         AUXR |= 0x80;                   //定时器0为1T模式
  69.     TMOD = 0x00;                    //设置定时器为模式0(16位自动重装载)
  70.     TL0 = T1MS;                     //初始化计时值
  71.     TH0 = T1MS >> 8;
  72.     TR0 = 1;                        //定时器0开始计时
  73.     ET0 = 1;                        //使能定时器0中断
  74.         
  75. /*****************外部中断设置*************************/        
  76.         IT0 = 1;                    //设置INT0下降沿触发
  77.     EX0 = 1;                    //使能外部中断INT0
  78.         IT1 = 1;                    //设置INT1下降沿触发
  79.     EX1 = 1;                    //使能外部中断INT1
  80.         INT_CLKO |= 0x70;           //使能INT2,INT3,INT4(EX4 = 1,EX3 = 1,EX2 = 1
  81.         
  82.         EA = 1;        
  83. }

  84. void Array_CLR(uint8 *p)
  85. {
  86.         uint8 i=0;
  87.         while(i!=16)
  88.         {
  89.                 p[i] = 0x00;
  90.                 i++;
  91.         }
  92. }

  93. void ShowScore(uint score)
  94. {
  95.         uint8 i;
  96.         uint8 qx,bx,sx,gx;
  97.         qx = score /1000;
  98.         bx = score %1000 /100;
  99.         sx = score %100/10;
  100.         gx = score %10;

  101.         Array_CLR(DispRAM);

  102.         for(i=0;i<5;i++)
  103.                 DispRAM[8-i] = (num[sx][i]<<4) | (num[gx][i]);
  104.         
  105.         for(i=0;i<5;i++)
  106.                 DispRAM[14-i] = (num[qx][i]<<5) | (num[bx][i]<<1);
  107.                                 
  108. //        MatxDisp(DispRAM,duty);
  109. }

  110. void main()
  111. {
  112.         Port_Init();
  113.         Sound_Init();
  114.         Init_Timer();
  115.         Sound_Tone(1,14,5);//滴
  116.         
  117.         srand(TL0);               
  118.         delayms(100);
  119.         Play_Music(sound_game_start);
  120.         Flash_Screen_Clear();
  121.         while(1)
  122.         {
  123.                 tms = 0;
  124.                 keypad = K_NULL;//清除按键状态
  125.                 switch (GUI_Main())        //进入用户游戏选择界面,返回选择的游戏
  126.                 {
  127.                         case 1:        Tetris_Game();        break;
  128.                         case 2:        Snake_Game();        break;
  129.                         case 3:        RAC_Game();                break;
  130.                         case 4:        Shot_Game();        break;
  131.                 }
  132.                 Play_Music(sound_game_over);
  133.                 Flash_Screen_Clear();
  134.                 ShowScore(scores);        //将分数载入显存
  135.                 delayms(300);
  136.                
  137.                 keypad = K_NULL;
  138.                 while(keypad != K_UP)        //在没按下OK键时保持分数显示
  139.                 {
  140.                         MatxDisp(DispRAM,duty);
  141.                         SMG_Display(scores,duty);
  142.                 }
  143.         }        
  144. }

  145. /* Timer0 interrupt routine */
  146. void T0_Timer_1ms_int() interrupt 1 using 1
  147. {
  148.         if(tms<0xfffe)        tms++;        //防止溢出
  149.         if(key_state){ if(!--keycont) key_state=0;}

  150.         if(PIN_TR2)//TR2如果打开,则开始播放音效
  151.         {
  152.                 if(!sound_cnt_time--)
  153.                 {
  154.                         TR2_OFF;
  155.                         beep = 1;
  156.                         if(music_p[s_p][1])
  157.                         {
  158.                                 Sound_Tone(sound_ON,music_p[s_p][0],music_p[s_p][1]);
  159.                                 s_p++; //自动装载下一个音符,实现音效与游戏“同时”运行
  160.                         }
  161.                 }
  162.         }
  163.         if(KEY_DOWN==0 & KEY_UP==0)        IAP_CONTR=0x60;//软件复位下载程序
  164. }

  165. void T2_Timer_Sound_freq() interrupt 12           //中断入口
  166. {
  167.      beep = ~beep; //蜂鸣器频率震动
  168. }

  169. uint8 Get_Kvuale(uint8 key_delay)//键值消抖处理,参数为灵敏度调节
  170. {
  171.         uint8 kvuale = K_NULL;        //返回的初始值为空值
  172.         if(keypad != K_NULL)        //当键值不为NULL时,说明有按键按下
  173.         {        
  174.                 if(!key_state)                //当按键状态位state为0时说明是第一次触发有效,为1时为重复触发
  175.                 {
  176.                         key_state=1;        //置1,防止重复触发
  177.                         kvuale = keypad;//获得读取键值
  178.                         keycont = key_delay;//载入消抖时间
  179.                 }
  180.                 keypad = K_NULL;        //清楚键值
  181.         }
  182.         return kvuale;
  183. }
  184. /*********外部中断按键区**********/
  185. void exint0() interrupt 0       //INT0
  186. {
  187.         keypad = 0;
  188. }
  189. void exint1() interrupt 2       //INT1
  190. {
  191.         keypad = 1;        
  192. }
  193. void exint2() interrupt 10      //INT2
  194. {
  195.         keypad = 2;
  196. }
  197. ……………………

  198. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码


所有资料51hei提供下载:
GAMEBOX_CODE_Keil5_v1.1.zip (291.3 KB, 下载次数: 19)
回复

使用道具 举报

ID:577675 发表于 2019-7-4 10:46 | 显示全部楼层
啊啊啊啊啊,好纠结啊,学校要求做一个这个
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表