好久不寫51單片機了,最近做了一個貪食蛇游戲機。
貪食蛇封面.jpg (256.52 KB, 下載次數: 51)
下載附件
2021-4-20 11:51 上傳
用到的模塊包括:8x8點陣,LCD1602,矩陣鍵盤、紅外遙控器、光敏電阻、EEPROM、電機驅動等
實現的功能包括:投幣檢測,紅外、鍵盤、上位機三種操作模式、最高分記錄、震動反饋等
在B站傳了一個驗收時候的視頻,所有的功能的介紹都在視頻里強烈建議直接戳視頻看
強烈建議直接戳視頻看
強烈建議直接戳視頻看:
https://www.bilibili.com/video/BV1Ba4y1Y7oz?share_source=copy_web
上位機界面:
上位機截圖.png (13.55 KB, 下載次數: 56)
下載附件
2021-4-20 11:51 上傳
51是用keil建的工程,上位機是QT寫的。附件包含了全部的代碼,51和上位機都有嗷~
代碼.png (289.61 KB, 下載次數: 45)
下載附件
2021-4-20 11:58 上傳
單片機源程序如下:
- #include <reg52.h>
- #include "typedef.h"
- #include "LCD1602.h"
- #include "LED88.h"
- #include "key.h"
- #include "IR.h"
- #include "24c02.h"
- #include "UART.h"
- #include "XPT2046.h"
- sfr T2MOD = 0xc9; //補充寄存器T2MOD定義
- sbit motor = P2^2; //電機接口
- u8 time = 0; //每50ms加一
- u8 game_state = 0; //指示游戲進行狀態
- u8 game_level = 1; //游戲難度等級。每吃到八個點增加一級
- u16 ADC_value = 0; //光敏電阻采值
- u8 control_mode = 0;//控制模式,1為板載按鍵,2為紅外遙控
- u8 score_record = 0;//最高分記錄,保存在24c02中
- extern u8 length; //蛇身長度
- extern u8 direction;//前進方向
- extern u8 food_x; //食物點坐標
- extern u8 food_y;
- extern u8 xdata snake_x[64]; //蛇身坐標
- extern u8 xdata snake_y[64];
- extern u8 key_value; //按鍵操作
- extern u8 IR_value; //紅外遙控按鍵操作
- extern u8 irtime; //紅外遙控計時標志位
- extern u8 UART_data; //串口接收內容
- sbit test = P1^1;
- void main()
- {
- motor = 0; //關閉電機
- LCD1602_Init();//1602初始化
- I2C_init(); //I2C初始化
- LED88_clean(); //8x8點陣清屏
- //從24C02中讀取游戲最高分記錄
- score_record = I2C_ReceiveData(0);//從AT24C02第0個單元中讀取數據
- //使能定時器2 50ms 用于貪食蛇、LCD閃爍等計時
- T2MOD = 0; //向上計數
- T2CON = 0; //16位自動重裝模式
- TL2 = 0x00; //設置定時初值
- TH2 = 0x4C;
- RCAP2L = 0x00; //設置定時重載值
- RCAP2H = 0x4C;
- ET2=1;
- TR2=1;
- //使能總中斷開關
- EA = 1;
-
- //剛上電時ADC讀值不穩定,延遲2s啟動
- LCD1602_Dis_Str(0, 0, "Welcome!");
-
- while(1)
- {
- u8 i,last_state,flag;
-
- test = ~test;
-
- //模式更新第一次進入while時,flag會被置0
- if(game_state!=last_state)
- flag = 0;
- else
- flag = 1;
- last_state = game_state;
- switch(game_state)
- {
- //未開始游戲,需要投幣
- case 0:
- //AD采值要放在LCD刷新之前,否則受引腳共用的影響會出錯
- ADC_value = (ADC_read(AD_CH0));
- //INSERT COIN每1s閃爍
- if(time/20%2==0)
- LCD1602_Dis_Str(0, 1, "INSERT COIN");
- else
- LCD1602_Dis_Str(0, 1, " ");
-
- //如果光敏被遮住,認為投入硬幣,開始游戲
- if(ADC_value>1500)
- {
- ADC_value = 0;
- LCD1602_clean(); //LCD清屏
- snake_food(); //隨機初始化一個食物的位置
- game_state = 1; //進入操作方式選擇
- }
- else
- delay_ms(10); //ADC采值不能過于頻繁,否則會出錯
- break;
-
- //選擇操作方式
- case 1:
- //通過flag變量確保以下內容只執行一次
- if(flag==0)
- {
- LCD1602_Dis_Str(0, 0, "Select Ctrl Mode");
- LCD1602_Dis_Str(0, 1, "1:Key 2:IR 3:PC");
- }
-
- key_scan(); //掃描矩陣鍵盤
- if(key_value==16) //按S2選擇板載鍵盤操作
- {
- control_mode = 1;
- key_value = 0; //按鍵標志位清零
- }
- else if(key_value==17) //按S3選擇紅外遙控器操作
- {
- control_mode = 2;
- key_value = 0; //按鍵標志位清零
-
- //使能定時器1 用于紅外遙控
- TMOD|= 0x20;
- TH1 = 0x00;
- TL1 = 0x00;
- ET1 = 1;
- TR1 = 1;
- //使能外部中斷 用于紅外遙控
- IT0 = 1;
- EX0 = 1;
- }
- else if(key_value==18)
- {
- control_mode = 3;
- key_value = 0; //按鍵標志位清零
-
- UART_init();
- }
- if(control_mode!=0)
- {
- //倒計時三秒開始
- LCD1602_clean();
- LCD1602_Dis_Str(8, 0, "3");
- delay_ms(1000);
- LCD1602_Dis_Str(8, 0, "2");
- delay_ms(1000);
- LCD1602_Dis_Str(8, 0, "1");
- delay_ms(1000);
-
- //LCD清屏,顯示游戲界面信息
- LCD1602_clean();
- LCD1602_Dis_Str(0, 0, "level:");
- LCD1602_Dis_Str(0, 1, "score:");
-
- game_state = 2; //進入游戲模式
- time = 0; //T0累加位清零
- }
- break;
-
- //游戲進行中
- case 2:
- //刷新游戲界面
- for(i=0; i<length; i++)
- LED88_point(snake_x[i], snake_y[i]); //顯示蛇
- LED88_point(food_x, food_y); //顯示食物
-
- //獲取用戶操作
- if(control_mode==1)
- key_scan(); //掃描矩陣鍵盤
- else if(control_mode==2)
- IR_process(); //處理紅外遙控
- // else if(control_mode==3)
- // UART_receive();
-
- //手動調節難度等級
- if(key_value==18 || IR_value==18 || UART_data==18)
- {
- key_value = 20;
- IR_value = 20;
- UART_data = 20;
- if(game_level<9)
- game_level++;
- time = 0;
- }
- else if(key_value==17 || IR_value==17 || UART_data==17)
- {
- key_value = 20;
- IR_value = 20;
- UART_data = 20;
- if(game_level>1)
- game_level--;
- time = 0;
- }
- //顯示難度等級和得分
- LCD1602_Dis_Str(7, 0, u8_to_str(game_level));
- LCD1602_Dis_Str(7, 1, u8_to_str((length-3)/10));
- LCD1602_Dis_Str(8, 1, u8_to_str((length-3)%10));
- //如果打破紀錄,顯示new record字樣
- if((length-3)>score_record)
- {
- LCD1602_Dis_Str(11, 0, "new");
- LCD1602_Dis_Str(10, 1, "record");
- }
- //如果長度達到64,直接結束游戲
- if(length==64)
- {
- LCD1602_clean();
- LED88_clean();
- game_state = 4;
- time = 0;
- }
- //判斷是否暫停
- if(key_value==16 || IR_value==16 || UART_data==16) //按下暫停鍵
- {
- LCD1602_clean();
- LCD1602_Dis_Str(0, 0, "-----Pause-----");
- game_state = 3;
- key_value = 20; //清空按鍵值,否則會直接觸發繼續
- IR_value = 20;
- UART_data = 20;
- }
- break;
-
- //游戲暫停
- case 3:
- ET0 = 0; //關閉T0,蛇保持靜止
-
- //刷新游戲界面
- for(i=0; i<length; i++)
- LED88_point(snake_x[i], snake_y[i]); //顯示蛇
- LED88_point(food_x, food_y); //顯示食物
-
- //獲取用戶操作
- if(control_mode==1)
- key_scan(); //掃描矩陣鍵盤
- else if(control_mode==2)
- IR_process(); //處理紅外遙控
- // else if(control_mode==3)
- // UART_receive();
-
- //判斷是否繼續
- if(key_value==16 || IR_value==16 || UART_data==16) //按下繼續鍵
- {
- LCD1602_clean(); //LCD清屏,顯示游戲信息
- LCD1602_Dis_Str(0, 0, "level:");
- LCD1602_Dis_Str(0, 1, "score:");
- key_value = 20; //清空按鍵值,否則會直接觸發繼續
- IR_value = 20;
- UART_data = 20;
- game_state = 2; //回到游戲狀態(2)
- TH0 = 0x4C;
- TL0 = 0x00;
- ET0 = 1;
- time = 0;
- }
- break;
- //死亡
- case 4:
- //如果沒有打破紀錄
- if((length-3)<=score_record)
- {
- //GAME OVER閃爍
- if(time/20%2==0)
- LCD1602_Dis_Str(0, 0, "GAME OVER");
- else
- LCD1602_Dis_Str(0, 0, " ");
-
- //通過變量flag使得以下內容只執行一次
- if(flag==0)
- {
- LCD1602_clean();
- LED88_clean();
- //顯示得分
- LCD1602_Dis_Str(0, 1, "Your score:");
- LCD1602_Dis_Str(11, 1, u8_to_str((length-3)/10));
- LCD1602_Dis_Str(12, 1, u8_to_str((length-3)%10));
- }
- }
- //如果打破紀錄
- else
- {
- //通過變量flag使得以下內容只執行一次
- if(flag==0)
- {
- LCD1602_clean();
- LED88_clean();
- //將新紀錄保存至24c02
- I2C_TransmitData(0, length-3);
- //顯示得分
- LCD1602_Dis_Str(0, 1, "New record:");
- LCD1602_Dis_Str(11, 1, u8_to_str((length-3)/10));
- LCD1602_Dis_Str(12, 1, u8_to_str((length-3)%10));
- }
- //CONGRATULATIONS!閃爍
- if(time/20%2==0)
- LCD1602_Dis_Str(0, 0, "CONGRATULATIONS!");
- else
- LCD1602_Dis_Str(0, 0, " ");
- }
- //按S5可以清除最高分記錄
- key_scan();
- if(key_value==19)
- {
- I2C_TransmitData(0, 0);
- score_record = 0;
- LCD1602_clean();
- LCD1602_Dis_Str(0, 0, "Reset complete");
-
- key_value = 20;
- delay_ms(1000);
- time = 200; //清除完之后延遲一秒直接退回到投幣界面
- }
- if(time==200)
- {
- LCD1602_clean();
- LCD1602_Dis_Str(0, 0, "Welcome!");
- score_record = length-3;
- control_mode = 0;
- game_state = 0;
- game_level = 1;
- length = 3;
- direction = 4;
- snake_x[0] = 2;
- snake_x[1] = 1;
- snake_x[2] = 0;
- snake_y[0] = 0;
- snake_y[1] = 0;
- snake_y[2] = 0;
- delay_ms(100);
- }
- break;
- }
- }
- }
- //定時器0中斷服務函數
- //void timer0_ISR(void) interrupt 1
- //{
- //}
- //定時器1中斷服務函數
- void timer1_ISR(void) interrupt 3
- {
- irtime++; //用于計數2個下降沿之間的時間
- }
- //定時器2中斷服務函數
- void timer2_ISR(void) interrupt 5
- {
- TF2 = 0; //T2需要手動清除標志位
-
- time++;
- if(time==255)
- time = 0;
- if(time==(18-game_level) && game_state==2)
- {
- time = 0;
- //計算移動
- snake_move();
- //判斷是否吃到食物
- snake_grow();
- //吃一個食物點一盞LED
- P1 = 0xff>>((length-3)%8);
- //判斷是否死亡
- snake_death();
- }
- }
- //外部中斷0服務函數
- void EX0_ISR(void) interrupt 0
- {
- IR_interrupt_process();
- }
復制代碼
文件截圖.png (7.13 KB, 下載次數: 44)
下載附件
2021-4-20 11:54 上傳
所有資料51hei提供下載:
51單片機貪食蛇.rar
(18.36 MB, 下載次數: 32)
2021-4-20 12:06 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|