找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 9303|回复: 17
收起左侧

DIY复古掌上像素游戏机(2个8*8点阵屏)童年记忆 附单片机源码

  [复制链接]
ID:287429 发表于 2018-3-4 15:02 来自手机 | 显示全部楼层 |阅读模式
82a67009c93d70cf2e9a0b52fbdcd100bba12ba1.jpg

电路原理图:
0.jpg
这个刚开始的原型只是一条蛇。。
所谓一百个程序员有一百条蛇,刚开始我只是想把我之前用C语言写的贪吃蛇程序拿到单片机,在8*8的点阵跑一下,但觉得有点简单,在STC12C5A60S2单片机下只用了不到程序10%觉得还是加点什么的,后来就加了俄罗斯方块,赛车,打飞机。。索性做了个简易的GUI界面。
硬件结构非常简单,用了一个逆天IAP15F2K61S2单片机,直接用单片机管脚推挽模式驱动点阵,限流电阻什么的都不管了,不用任何外围IC,两个8*8点阵和三位数码管,共用一组数据口,几乎用了单片机所以引脚;采用逐点扫描方式,并且用软PWM调节亮度,妈妈再也不用担心我单片机电流过载了而烧坏了~
可怕的背部飞线:
9a91de3d70cf3bc789606cb3d200baa1cc112aa1.jpg
较早版本是并口数据模式,走线比较痛苦,但程序比较好写,
后面版本修改了驱动,引脚可以自由映射,走线起来就很舒服了。
实现同一屏,不同对比度:
34a567cf3bc79f3def81456fb9a1cd11738b29a1.jpg


8d572cc79f3df8dcc95d2ecece11728b461028a1.jpg

大概4~5天之后来了,这个快递包裹体积很小,但重量异常的沉。。。
c65f883df8dcd100a3fc597e718b4710b8122fa1.jpg

焊上元件,烧上程序,还好能正常运行,总算松了口气。。。。
62a5efdcd100baa1d74ce6e44410b912c9fc2ea1.jpg

看着心好累,焊得我蛋疼。。。
0544c600baa1cd1169d6d37fba12c8fcc2ce2da1.jpg
2c98ada1cd11728b5b4d2d7dcbfcc3cec2fd2ca1.jpg

/******************************************************************************************************/
目前有四款游戏程序空间大概用了40%左右,后续有时间精力更新更多的游戏进来。。
以下是工程文件,如果你有单片机基础,那就自己也DIY一个吧,回味下童年。
/****************************************工程文件下载区*******************************************/

视频:


单片机源程序如下:
  1. /*
  2. //作者:郑梓滨        Jaupin@126.com
  3. //功能:复古掌上俄罗斯方块游戏机源代码,包括游戏GUI,俄罗斯方块、贪吃蛇、经典赛车游戏、射击障碍物游戏
  4. v1.0:
  5.         2014-7-26 00:00:00        :完成有俄罗斯方块游戏基本模型;
  6.         2014-7-28 02:12:03        :将原先临时使用的延时键盘扫描改为外部中断状态位检测键;
  7.         2014-7-28 20:40:37        :完成俄罗斯方块分数计数及分数显示功能;
  8.         2014-8-1 01:01:54        :将较早之前完成贪吃蛇游戏代码合并植入;
  9.         2014-8-2 17:04:25        :整理之前的临时源码,使工程文件规范化;
  10.         2014-8-3 23:50:49        :构建游戏选择画面基本模型,完成画面平移效果;
  11.         2014-8-5 00:50:04        :改进LED点阵底层驱动,用软件PWM调节画面亮度;
  12.         2014-8-7 00:53:35        :完成赛车游戏,用PWM分层扫描画面,形成游戏画面对比度;
  13.         2014-8-8 02:16:44        :完成赛车游戏选择预览画面,并将三个游戏合并在一起;
  14.         2014-8-12 01:47:07        :将逐行扫描改为逐点扫描,使显示亮度均匀;增加亮度调节功能;
  15.         2014-9-9 00:32:40        :修改及优化若干细节;
  16. v1.1:
  17.         2014-9-18 0:57:23        :重新布局电路,修改原先不合理的地方,为制作PCB板作准备;
  18.         2014-9-19 22:02:36        :加入游戏音效,并且可以通过软件方式开关声音;
  19.         2014-9-21 14:59:39        :增加三位mini数码管,实时显示游戏分数,数码管共用点阵并行数据口;
  20.         ~~~~~~~~~~~忘记备注
  21.         2014-10-20 21:30:15        :加入射击游戏,将GUI模块化,简化流程
  22. */

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

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

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

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

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

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

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

  100.         Array_CLR(DispRAM);

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

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

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

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

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

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

  203. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
原理图及源代码: GAMEBOX_CODE_Keil5_v1.1.zip (291.3 KB, 下载次数: 124)
回复

使用道具 举报

ID:287429 发表于 2018-3-4 15:04 来自手机 | 显示全部楼层
图不见了
34a567cf3bc79f3def81456fb9a1cd11738b29a1.jpg
9a91de3d70cf3bc789606cb3d200baa1cc112aa1.jpg
82a67009c93d70cf2e9a0b52fbdcd100bba12ba1.jpg
回复

使用道具 举报

ID:287429 发表于 2018-3-4 15:21 来自手机 | 显示全部楼层
怎么上传
回复

使用道具 举报

ID:313960 发表于 2018-5-10 22:46 | 显示全部楼层
好想学一学,做一做,觉得好复杂好难的样子。。。
回复

使用道具 举报

ID:161343 发表于 2018-5-11 16:23 | 显示全部楼层
点阵是什么型号的啊楼主
回复

使用道具 举报

ID:378221 发表于 2018-7-24 01:28 | 显示全部楼层
路过帮顶
回复

使用道具 举报

ID:294331 发表于 2018-7-27 17:44 | 显示全部楼层
感谢楼主分享,楼主很厉害哦
回复

使用道具 举报

ID:179958 发表于 2018-7-28 13:52 来自手机 | 显示全部楼层
666,有空也做个
回复

使用道具 举报

ID:479299 发表于 2019-2-22 16:01 | 显示全部楼层
mark,回头学习
回复

使用道具 举报

ID:401370 发表于 2019-3-4 14:14 | 显示全部楼层
两个点阵是怎么连接的呀?
回复

使用道具 举报

ID:1091354 发表于 2023-8-15 11:08 | 显示全部楼层
学习学习也是不错的。
回复

使用道具 举报

ID:59884 发表于 2023-8-18 13:16 | 显示全部楼层
谢谢楼主分享!有空也做个来玩。
回复

使用道具 举报

ID:71233 发表于 2023-8-18 18:40 | 显示全部楼层
请问不同亮度是怎样实现的?
回复

使用道具 举报

ID:77589 发表于 2023-11-1 14:38 | 显示全部楼层
lmn2005 发表于 2023-8-18 18:40
请问不同亮度是怎样实现的?

行或列停留时间长度
回复

使用道具 举报

ID:899981 发表于 2023-11-2 10:58 | 显示全部楼层
移动咋搞的?另外咋知道插入了?
回复

使用道具 举报

ID:998401 发表于 2023-11-2 11:21 | 显示全部楼层
学习准备做一个
感谢楼主
回复

使用道具 举报

ID:157007 发表于 2023-12-28 22:02 | 显示全部楼层
ZHAOBAO511 发表于 2023-11-2 10:58
移动咋搞的?另外咋知道插入了?

二维数组,图像移动就是里面的数字的行和列在改变。
不断查询同一行是否全是一,如果是,则消去,上方的自动下落。

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:965040 发表于 2024-1-9 08:44 | 显示全部楼层
学习了, 文件很详细,赞
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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