這是在師傅那里拿到點陣板后為了練習16*16點陣板寫的一個彈球小游戲,算法是自己寫的一、使用的工具
1.點陣板:七星蟲德飛萊的LY-LED16*16BV2.1
2.單片機:STC89C52 LY51-L2c的單片機,晶振是12.000
3.編程軟件:Keil
4.調試工具:stc-isp-15xx-v6.86D
5.STC的89c52 USB轉串口線驅動
二,主要功能有下1.顯示開始界面
1.jpg (2.39 MB, 下載次數: 44)
下載附件
2018-6-1 15:08 上傳
2.消除,并數碼管顯示分數
2.jpg (2.37 MB, 下載次數: 53)
下載附件
2018-6-1 15:12 上傳
3.繼續消除
3.jpg (2.28 MB, 下載次數: 47)
下載附件
2018-6-1 15:13 上傳
4.結束游戲
4.jpg (2.49 MB, 下載次數: 67)
下載附件
2018-6-1 15:13 上傳
5.游戲中可以加速和減速小球
6.消除完全部小球后會顯示笑臉
三、規則
開始、結束、勝利中使用s4作為確認鍵
開始游戲后按鍵功能如下
1.s1 左移
2.s2 右移
3.s3 減速
4.s4 加速
四、缺點
1.要消除完一整行之后才能消除下一行
2.擋板的和球的反彈有點問題
3.別的還有問題希望大家多多指教
五、單片機源程序如下:
- /*-----------------------------------------------
- 名稱:彈彈球游戲
- 編寫:田*
- 日期:2018年
- 內容:屏+5V連接電源5V
- GND接GND
- P3.0-P3.3分別連接A、B、C、D,用于控制16行
- SCK時鐘連接P1.5
- LATCH鎖存連接P1.6
- R1紅色數據信號連接至P1.4
- G1綠色數據信號連接至P3.4,如果單紅色屏此信號無需連接
- OE使能端接P1.1
- ------------------------------------------------*/
- #include<reg52.h>
- #include "scanKey.h"
- #include "scanNum.h"
- sbit T_STR = P1^6; // 鎖存引腳,屏上標識位STR
- sbit R1 = P1^4; // 數據引腳,屏上標識R1
- sbit G1 = P3^4; // 數據引腳,屏上標識G1 ·沒有該燈光,可不用
- sbit T_CLK = P1^5; // 時鐘引腳,屏上標識位CLK
- sbit OE = P1^1; // 使能引腳,屏上標識EN/OE
- unsigned char DIS[]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; //行數據
- unsigned char ledShow[][32]={0x00}; // 顯示擋板
- code dotDis[8] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; // 扭轉順序
- void input2Byte(unsigned char dataR1); // 寫入數據
- void init_Timer1(void); // 初始化定時器
- void position(int pos); // 移動擋板位置
- void gameOver(); // 游戲結束
- void gameWin(); // 游戲勝利
- bit isGameWin(); // 判斷游戲是否勝利
- void gameMenu(); // 游戲菜單
- void playGame(); // 開始游戲
- /*
- 以下是擋板移動位置的十六進制
- 1111 1000 0000 0000 ledShow[28] = 0xF8 ledShow[29] = 0x00
- 0111 1100 0000 0000 ledShow[28] = 0x7C ledShow[29] = 0x00
- 0011 1110 0000 0000 ledShow[28] = 0x3E ledShow[29] = 0x00
- 0001 1111 0000 0000 ledShow[28] = 0x1F ledShow[29] = 0x00
- 0000 1111 1000 0000 ledShow[28] = 0x0F ledShow[29] = 0x80
- 0000 0111 1100 0000 ledShow[28] = 0x07 ledShow[29] = 0xC0
- 0000 0011 1110 0000 ledShow[28] = 0x03 ledShow[29] = 0xE0
- 0000 0001 1111 0000 ledShow[28] = 0x01 ledShow[29] = 0xF0
- 0000 0000 1111 1000 ledShow[28] = 0x00 ledShow[29] = 0xF8
- 0000 0000 0111 1100 ledShow[28] = 0x00 ledShow[29] = 0x7C
- 0000 0000 0011 1110 ledShow[28] = 0x00 ledShow[29] = 0x3E
- 0000 0000 0001 1111 ledShow[28] = 0x00 ledShow[29] = 0x1F
- */
- bit move = 0; // 是否移動
- bit isUp = 1; // 小球往上
- bit isDown = 0; // 小球往下
- char rolIndex = 26; // 初始行位置
- char colIndex = 3; // 初始列位置
- char pos = 5; // 擋板位置
- char sysFun = 0; // 系統功能
- bit gameState = 0; // 游戲狀態
- char speed = 50; // 游戲速度
- unsigned short gameScore = 0; // 游戲分數
- bit f_num = 0; // 數碼管顯示
- // 主程序
- int main()
- {
- static unsigned char count = 0; // 數碼管顯示計時
- init_Timer1(); // 初始化定時器
- fillDisBuf(gameScore,1); // 填充數碼管
- while(1)
- {
- scanKey(); // 實時掃描按鍵
- if (sysFun == 1 && f_num) {
-
- count++;
- if (count == 20) { // 100ms比較好
- display();
- count = 0;
- }
- f_num = 0;
- }
-
- /* 多任務控制核心 */
- switch(sysFun) {
- case 0: // 顯示游戲菜單
- gameMenu();
- break;
- case 1: // 開始游戲
- playGame();
- break;
- case 2: // 游戲勝利
- gameWin();
- break;
- case 3: // 游戲結束
- gameOver();
- break;
- }
- }
- }
- /* 顯示游戲菜單 */
- void gameMenu() {
- char i;
- if (!gameState) {
-
- // 全部先初始化為不亮
- for (i = 0; i < 32; i++){
- ledShow[0][i] = 0x00;
- }
-
- // 初始化游戲LED燈,顯示初始界面
- ledShow[0][0] = 0xEA; ledShow[0][1] = 0x05;
- ledShow[0][2] = 0x2E; ledShow[0][3] = 0xEF;
- ledShow[0][4] = 0xEA; ledShow[0][5] = 0x44;
- ledShow[0][6] = 0x8E; ledShow[0][7] = 0x4E;
- ledShow[0][8] = 0xEA; ledShow[0][9] = 0xF5;
- ledShow[0][10] = 0x2E; ledShow[0][11] = 0x44;
- ledShow[0][12] = 0x24; ledShow[0][13] = 0x4C;
- ledShow[0][14] = 0xEE; ledShow[0][15] = 0xE4;
- ledShow[0][16] = 0x04;
- gameState = 1; // 開啟游戲狀態為
- /* 擋板歸位 */
- pos = 5; // 擋板初始位置
- rolIndex = 26; // 小球索引
- ledShow[0][rolIndex] = 0x01; // 球初始位置
- position(pos); // 顯示擋板
- gameScore = 0; // 游戲歸0
- }
- /* s4作為游戲開始 */
- if (s4d) {
- s4d = 0;
- sysFun = 1;
- gameState = 1;
- }
- }
- /* 玩游戲 */
- void playGame() {
- char i;
- if (gameState) { // 是否經過了初始化
- /* 初始化游戲區域 */
- gameState = 0;
- for (i = 0; i < 32; i++){
- if (i <= 15) {
- ledShow[0][i] = 0xFF;
- }
- else{
- ledShow[0][i] = 0x00;
- }
- }
- /* 擋板歸位 */
- pos = 5; // 擋板位置
- rolIndex = 26; // 小球索引
- ledShow[0][rolIndex] = 0x01; // 球初始位置
- position(pos); // 顯示擋板
- gameScore = 0; // 游戲歸0
- }
- /* 根據按鍵移動擋板 */
- if (s1d){
- s1d = 0;
- pos--;
- if (pos < 0) { // 判斷是否在邊界,是則不能移動
- pos = 0;
- }
- else{
- position(pos);
- }
- /* 判斷是否在另外一個區域的邊界 */
- if (ledShow[0][rolIndex] == 0x80 && rolIndex == 27) {
- ledShow[0][rolIndex] = 0x00; // 關閉當前行
- rolIndex--; // 跳轉下一行
- ledShow[0][rolIndex] = 0x01; // 新位置
- }
- else if (rolIndex >= 25 && rolIndex <= rolIndex + 2) {
- /* 判斷是否在可移動邊界 */
- if (ledShow[0][rolIndex] != 0x80) { // 是否還能移動
- ledShow[0][rolIndex] <<= 1; // 小球左移
- }
- }
- }
- if (s2d){
- s2d = 0;
- pos++;
- if (pos >= 12) { // 12是到右邊界移動的距離
- pos = 11;
- }
- else{
- position(pos); // 往右移動擋板
- }
- /* 判斷是否在另外一個區域的邊界 */
- if (ledShow[0][rolIndex] == 0x01 && rolIndex == 26) {
- ledShow[0][rolIndex] = 0x00;
- rolIndex++;
- ledShow[0][rolIndex] = 0x80;
- }
- else if (rolIndex >= 25 && rolIndex <= rolIndex + 2) {
- /* 判斷是否在可移動邊界 */
- if (ledShow[0][rolIndex] != 0x01) { // 判斷是否已到達邊界
- ledShow[0][rolIndex] >>= 1;
- }
- }
- }
- // 游戲減速
- if(s3d) {
- s3d = 0;
- // 加大延遲
- speed += 10;
- speed = (speed <= 50) ? speed : 50;
- }
-
- // 游戲加速
- if(s4d) {
- s4d = 0;
- // 減小延遲
- speed -= 10;
- speed = (speed >= 20) ? speed : 20;
- }
-
- // 點移動
- if (move) {
- move = 0;
-
- /* 當球往上移動的時候 */
- if (isUp) {
- rolIndex -= 2; // 點陣版是順序加,-2才上球的正上方
- /* 如果是在空白區域則直接往上移動 */
- if (ledShow[0][rolIndex] == 0x00 && rolIndex > 0) {
- ledShow[0][rolIndex] = ledShow[0][rolIndex+2];
- ledShow[0][rolIndex+2] = 0x00; // 移動之后需要將前一行燈關閉
- }
- else if (rolIndex < 0) { // 判斷是否到達邊界
- if(isGameWin()){ // 判斷是否全部打完
- sysFun = 2; // 切換系統狀態
- }
- else{
- isUp = 0;
- isDown = 1;
- rolIndex += 2; // +2回到頂部
- }
- }
- else if (ledShow[0][rolIndex] != 0x00 &&
- (ledShow[0][rolIndex] & ledShow[0][rolIndex+2]) == 0x00){
- // 上一行沒有消除完整但是正上一個為空,直接返回
-
- isUp = 0;
- isDown = 1;
- rolIndex += 2;
- }
- else if (ledShow[0][rolIndex] == 0xFF ||
- (ledShow[0][rolIndex] & ledShow[0][rolIndex+2]) != 0x00) {
-
- // 判斷上面一行是不是整行未消除或者正上方有
- ledShow[0][rolIndex] &= (~ledShow[0][rolIndex+2]);
- isUp = 0;
- isDown = 1;
- rolIndex += 2;
- // 根據小球速度進行加分
- switch(speed) {
- case 50: gameScore += 1; break; // 四等級+1分
- case 40: gameScore += 2; break; // 三等級+2分
- case 30: gameScore += 3; break; // 二等級+3分
- case 20: gameScore += 4; break; // 一等級+4分
- }
- fillDisBuf(gameScore,1); // 分數+完填充數碼管
- }
- }
- if (isDown) {
- rolIndex += 2;
- if (rolIndex > 31) { // 超出邊界
- rolIndex = 30;
- sysFun = 3; // 切換系統狀態到結束
-
- }
- else if (ledShow[0][rolIndex] == 0x00) { // 空白區域直接下移
- ledShow[0][rolIndex] = ledShow[0][rolIndex-2];
- ledShow[0][rolIndex-2] = 0x00;
- }
- else if ((ledShow[0][rolIndex]) != 0x00) { // 碰到板
- isUp = 1;
- isDown = 0;
- rolIndex -= 2;
- }
- }
- }
- }
- /* 判斷游戲勝利 */
- bit isGameWin() {
- bit flag = 1;
- char i;
- for(i = 0; i < 16; i++) { // 上方磚塊區域
- /*判斷是否除了小球外游戲區域的磚塊全部消除*/
- if (ledShow[0][i] != 0x00 && ledShow[0][i] != ledShow[0][rolIndex+2]) { // 判斷點陣是否全滅
- flag = 0;
- break;
- }
- }
- return flag;
- }
- /* 游戲勝利 */
- void gameWin() {
- // 游戲勝利標志
- ledShow[0][0] = 0x00; ledShow[0][1] = 0x00;
- ledShow[0][2] = 0x00; ledShow[0][3] = 0x00;
- ledShow[0][4] = 0x07; ledShow[0][5] = 0xE0;
- ledShow[0][6] = 0x08; ledShow[0][7] = 0x10;
- ledShow[0][8] = 0x10; ledShow[0][9] = 0x08;
- ledShow[0][10] = 0x26; ledShow[0][11] = 0x64;
- ledShow[0][12] = 0x20; ledShow[0][13] = 0x04;
- ledShow[0][14] = 0x20; ledShow[0][15] = 0x04;
-
- ledShow[0][16] = 0x20; ledShow[0][17] = 0x04;
- ledShow[0][18] = 0x22; ledShow[0][19] = 0x44;
- ledShow[0][20] = 0x21; ledShow[0][21] = 0x84;
- ledShow[0][22] = 0x10; ledShow[0][23] = 0x08;
- ledShow[0][24] = 0x08; ledShow[0][25] = 0x10;
- ledShow[0][26] = 0x07; ledShow[0][27] = 0xE0;
- ledShow[0][28] = 0x00; ledShow[0][29] = 0x00;
- ledShow[0][30] = 0x00; ledShow[0][31] = 0x00;
- if (s4d) {
- s4d = 0;
- sysFun = 0;
- }
- }
- /* 游戲結束 */
- void gameOver() {
- // 游戲結束標志
- ledShow[0][0] = 0x00; ledShow[0][1] = 0x00;
- ledShow[0][2] = 0x00; ledShow[0][3] = 0x00;
- ledShow[0][4] = 0x07; ledShow[0][5] = 0xE0;
- ledShow[0][6] = 0x08; ledShow[0][7] = 0x10;
- ledShow[0][8] = 0x10; ledShow[0][9] = 0x08;
- ledShow[0][10] = 0x26; ledShow[0][11] = 0x64;
- ledShow[0][12] = 0x20; ledShow[0][13] = 0x04;
- ledShow[0][14] = 0x20; ledShow[0][15] = 0x04;
-
- ledShow[0][16] = 0x20; ledShow[0][17] = 0x04;
- ledShow[0][18] = 0x21; ledShow[0][19] = 0x84;
- ledShow[0][20] = 0x22; ledShow[0][21] = 0x44;
- ledShow[0][22] = 0x10; ledShow[0][23] = 0x08;
- ledShow[0][24] = 0x08; ledShow[0][25] = 0x10;
- ledShow[0][26] = 0x07; ledShow[0][27] = 0xE0;
- ledShow[0][28] = 0x00; ledShow[0][29] = 0x00;
- ledShow[0][30] = 0x00; ledShow[0][31] = 0x00;
- if (s4d) {
- s4d = 0;
- sysFun = 0;
- }
- }
- /* 初始化定時器,做為動態掃描 */
- void init_Timer1(void)
- {
- TMOD |= 0x11;
- EA=1; //總中斷使能
- ET1=1; //定時中斷使能
- TR1=1; //打開定時器開關
- TR0=1; // start
- TH0=0xEC;
- TL0=0x78;
- ET0=1;
- }
- // 一次寫入兩個字節
- void input2Byte(unsigned char dataR1) //寫兩個字節
- {
- unsigned char i;
- bit temp = 0;
- for(i=0; i<8; i++)
- {
- R1 = !(dataR1 & dotDis[i]); // 調整成較為方便的看的順序
-
- T_CLK = 0;
- T_CLK = 1;
- }
- }
- // 定時器執行動態掃描整個點陣
- void timer1_isr(void) interrupt 3
- {
- static unsigned char count;
- unsigned char i;
-
- TH1=0xFF; //重裝初值
- TL1=0;
- T_STR=0; // 鎖存釋放
- input2Byte(ledShow[0][i]);
- input2Byte(ledShow[0][i+1]);
- OE=1; // 暫時關閉屏幕,防止出現鬼影,如果沒有使用該引腳控制則會出現拖影現象。
- T_STR=1; // 鎖存有效,此時一行的數據顯示到屏上
- P3=DIS[15-count]|0xF0; // 用P0口的前4位控制16行,屏內部通過4-16譯碼器工作,循環掃描其他15行
- OE=0; // 使能
- count++;
- i+=2; // 累加調用下一行數據
- if(count==16) count=0;
- if(i==32) i=0; // 又從第一個位置掃描
- }
- // 中斷0 ,產生移動信號
- void init_timer0()interrupt 1 using 1{
- static unsigned char count = 0;
- TR0=0;
- TH0=0xEC;
- TL0=0x78;
- TR0=1;
- f_num = 1; // 5ms顯示一次數碼管
- count++;
- if (count >= speed) {
- count = 0;
- move = 1;
- }
- }
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
所有代碼51hei提供下載:
彈球小游戲-源代碼.zip
(53.77 KB, 下載次數: 60)
2018-6-1 15:18 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|