單片機制作的gamebox,包含射擊游戲,賽車游戲,貪食蛇等,有l(wèi)ed顯示,2個8*8點陣 電路原理圖如下:
0.png (92.36 KB, 下載次數(shù): 14)
下載附件
2018-10-10 13:36 上傳
元件清單:
0.png (17.14 KB, 下載次數(shù): 15)
下載附件
2018-10-10 13:38 上傳
可以到./src/config.h文件自由配置引腳
0.png (38.91 KB, 下載次數(shù): 20)
下載附件
2018-10-10 13:36 上傳
0.png (12.26 KB, 下載次數(shù): 13)
下載附件
2018-10-10 13:39 上傳
單片機源程序如下(有詳細的代碼注釋):
- #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{ //隨著分數(shù)的增加, 游戲速度逐漸加快
- 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){
- // 分層掃描,將畫面兩邊的賽道和賽車分為兩次掃描,使跑道跟賽車產(chǎn)生畫面對比度
- // uint8 xtmp[16];
- // for(p=0;p<16;p++)//刷新跑道
- // DispRAM[p]=track[(p+stp)%5];//動態(tài)跑道算法
- // 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];//動態(tài)跑道算法
-
- 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)//游戲速度節(jié)拍
- {
- stp++;
- if(stp==5) stp=0;//跑道動態(tài)算法標記位
- for(i=0;i<4;i++)
- {
- xcar[i][1]--; //其他車跟隨跑道下移
- if(xcar[i][1]== -4){
- xcar[i][1]=15;
- if(lastid>0) //游戲規(guī)則,如果上次產(chǎn)生的不是空車位,則這一次產(chǎn)生一個空車位
- carid=0;
- else
- carid=rand()%3;//隨機產(chǎn)生一輛車
- 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,將進行優(yōu)化。
- */
- #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; //獲得隨機數(shù)種子;//用計數(shù)器作為隨機數(shù)發(fā)生器
- for(i=1;i<(snake.node);i++)//檢測產(chǎn)生的食物是否與蛇本身重疊
- {
- 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++)//清除內(nèi)存數(shù)據(jù)
- {
- snake.x[c]=-1;
- snake.y[c]=-1;
- }
- snake.life = 1; //賦予蛇生命
- snake.node = 3; //默認長度3節(jié)
- 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) //根據(jù)蛇的方向標前進
- {
- 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;//直接在此增加蛇長度會在下一個顯示掃描產(chǎn)生一個原有數(shù)據(jù)留影,故通過加長
- snake.node++;
- // game_speed-=10; //每吃一個食物增加10點速度
- Create_Food(); //產(chǎn)生新食物
- }
- 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++)//從蛇的第四節(jié)開始判斷是否撞到自己了,因為蛇頭不可能撞到二三四節(jié)
- {
- 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,俄羅斯方塊、貪吃蛇、經(jīng)典賽車游戲、射擊障礙物游戲
- v1.0:
- 2014-7-26 00:00:00 :完成有俄羅斯方塊游戲基本模型;
- 2014-7-28 02:12:03 :將原先臨時使用的延時鍵盤掃描改為外部中斷狀態(tài)位檢測鍵;
- 2014-7-28 20:40:37 :完成俄羅斯方塊分數(shù)計數(shù)及分數(shù)顯示功能;
- 2014-8-1 01:01:54 :將較早之前完成貪吃蛇游戲代碼合并植入;
- 2014-8-2 17:04:25 :整理之前的臨時源碼,使工程文件規(guī)范化;
- 2014-8-3 23:50:49 :構建游戲選擇畫面基本模型,完成畫面平移效果;
- 2014-8-5 00:50:04 :改進LED點陣底層驅(qū)動,用軟件PWM調(diào)節(jié)畫面亮度;
- 2014-8-7 00:53:35 :完成賽車游戲,用PWM分層掃描畫面,形成游戲畫面對比度;
- 2014-8-8 02:16:44 :完成賽車游戲選擇預覽畫面,并將三個游戲合并在一起;
- 2014-8-12 01:47:07 :將逐行掃描改為逐點掃描,使顯示亮度均勻;增加亮度調(diào)節(jié)功能;
- 2014-9-9 00:32:40 :修改及優(yōu)化若干細節(jié);
- v1.1:
- 2014-9-18 0:57:23 :重新布局電路,修改原先不合理的地方,為制作PCB板作準備;
- 2014-9-19 22:02:36 :加入游戲音效,并且可以通過軟件方式開關聲音;
- 2014-9-21 14:59:39 :增加三位mini數(shù)碼管,實時顯示游戲分數(shù),數(shù)碼管共用點陣并行數(shù)據(jù)口;
- ~~~~~~~~~~~忘記備注
- 2014-10-20 21:30:15 :加入射擊游戲,將GUI模塊化,簡化流程
- */
- #include "config.h"
- volatile uint8 data keypad = K_NULL; //鍵盤狀態(tài)
- volatile uint8 data keycont = 0; //鍵盤檢測消抖定時器
- volatile uint16 data tms = 0; //1ms T0定時器
- bit key_state = 0; //按鍵狀態(tài)
- 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};//用于數(shù)字序號定位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下降沿觸發(fā)
- EX0 = 1; //使能外部中斷INT0
- IT1 = 1; //設置INT1下降沿觸發(fā)
- 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;//清除按鍵狀態(tài)
- 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); //將分數(shù)載入顯存
- delayms(300);
-
- keypad = K_NULL;
- while(keypad != K_UP) //在沒按下OK鍵時保持分數(shù)顯示
- {
- 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++; //自動裝載下一個音符,實現(xiàn)音效與游戲“同時”運行
- }
- }
- }
- 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)//鍵值消抖處理,參數(shù)為靈敏度調(diào)節(jié)
- {
- uint8 kvuale = K_NULL; //返回的初始值為空值
- if(keypad != K_NULL) //當鍵值不為NULL時,說明有按鍵按下
- {
- if(!key_state) //當按鍵狀態(tài)位state為0時說明是第一次觸發(fā)有效,為1時為重復觸發(fā)
- {
- key_state=1; //置1,防止重復觸發(fā)
- kvuale = keypad;//獲得讀取鍵值
- keycont = key_delay;//載入消抖時間
- }
- keypad = K_NULL; //清楚鍵值
- }
- return kvuale;
- }
- /*********外部中斷按鍵區(qū)**********/
- 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, 下載次數(shù): 19)
2018-10-10 08:00 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|