基于STM32F103的貪吃蛇
單片機源程序如下:
- ///***************************************************
- //程序名:貪吃蛇
- //平臺:STM32F103ZET6精英版
- //
- //程序功能:貪吃蛇游戲,吃到食物后,速度增加,長度變長,咬到自己游戲結(jié)束,復(fù)位重新開始
- //
- //程序調(diào)用:自制手柄按鍵,AD產(chǎn)生隨機數(shù),正點原子4.3寸屏幕,FreeRTOS操作系統(tǒng)
- //
- //設(shè)計思路:創(chuàng)建若干任務(wù),按鍵任務(wù)控制蛇方向,顯示任務(wù)控制屏幕的顯示與坐標更新,事件任務(wù)為數(shù)據(jù)處理任務(wù),并控制著其他任務(wù)能否運行
- //
- //知識準備:AD采樣,GPIO設(shè)置,FreeRTOS創(chuàng)建任務(wù)與掛起
- //
- //注意:屏幕被裁剪成4.3寸版本,其它屏幕請修改為原程序
- //
- ///****************************************************
- //系統(tǒng)文件
- #include "sys.h"
- #include "delay.h"
- #include "usart.h"
- #include "stdio.h"
- #include "stdlib.h"
- #include "math.h"
- //內(nèi)部驅(qū)動
- #include "rand.h"
- //外圍電路
- #include "led.h"
- #include "key.h"
- #include "lcd_4_3.h"
- //用戶算法
- #include "my_task.h"
- #define GAME_WIDTH 480 //設(shè)置屏幕分辨率為800*480,為了維持正方形,分成80*48等分
- #define GAME_HEIGHT 800
- #define GAME_XPART 48
- #define GAME_YPART 80
- enum sta //枚舉狀態(tài)
- {
- OFF,//0
- ON //1
- } station;
- enum dir //枚舉貪吃蛇方向
- {
- UP, //上
- DOWN, //下
- LEFT, //左
- RIGHT //右
- }direction;
- typedef struct //貪吃蛇重要參數(shù)集
- {
- u16 speed; //速度
- u16 length; //長度
- u16 energybuf; //能量緩存
- u16 width; //蛇寬 //未使用
- u16 life; //生命數(shù) //未使用
- u16 firstx; //蛇頭坐標x
- u16 firsty; //蛇頭坐標y
- u16 lastx; //蛇尾坐標x
- u16 lasty; //蛇尾坐標y
- u16 color; //蛇顏色 //未使用
- }snakes;
- snakes snake;
- void Snake_Init(snakes * snake)//貪吃蛇參數(shù)初始化
- {
- snake->speed=5;
- snake->length=10;
- snake->energybuf=0;
- snake->width=1;
- snake->life=3;
- snake->firstx=4;
- snake->firsty=5;
- snake->lastx=0;
- snake->lasty=0;
- snake->color=RED;
- }
- typedef struct //食物重要參數(shù)集
- {
- u16 energy ;//食物能量
- u16 x ; //食物坐標x
- u16 y ; //食物坐標y
- }apples;
- apples apple;
- void Apple_Init(apples * apple)//食物參數(shù)初始化
- {
- apple->energy=1;
- // apple->x=24; //坐標由隨機數(shù)計算出來
- // apple->y=40;
- }
- typedef struct //事件重要參數(shù)集
- {
- u16 Process ;//是否游戲暫停
- u16 GameSta ;//是否游戲結(jié)束
- u16 AppleSta;//食物狀態(tài)
- u16 Direction;//蛇前進方向
- }events;
- events event;
- void Event_Init(events * event)//事件參數(shù)初始化
- {
- event->Process=ON;
- event->GameSta=ON;
- event->AppleSta=ON;
- event->Direction=DOWN;//初始方向向下
- }
- typedef struct //貪吃蛇坐標參數(shù)
- {
- u16 x;
- u16 y;
- }axiss;
- axiss snake_axis[100]; //設(shè)蛇身最大長度可以達到100
- void Display(u16 x,u16 y,u16 color)//按照80*48的坐標映射到800*480的屏幕上
- {
- LCD_Fill(GAME_WIDTH/GAME_XPART*x,GAME_HEIGHT/GAME_YPART*y,GAME_WIDTH/GAME_XPART*(x+1),GAME_HEIGHT/GAME_YPART*(y+1),color);
- }
- void DisplayInit(void) //蛇身初始化,默認在該位置,并蛇頭向下
- {
- u16 i;
- for(i=0;i<5;i++)//將初始坐標存入蛇身坐標內(nèi)
- {
- snake_axis[i].x=i;
- snake_axis[i].y=0;
- }
- for(i=5;i<10;i++)
- {
- snake_axis[i].x=4;
- snake_axis[i].y=i-4;
- }
- LCD_Clear(WHITE);
- for(i=0;i<10;i++)
- {
- Display(snake_axis[i].x,snake_axis[i].y,RED);//按照初始坐標打印出蛇身
- }
- }
- void GameOver(void)//游戲結(jié)束函數(shù),打印"GAME OVER",掛起核心數(shù)據(jù)處理函數(shù)
- {
- LCD_ShowString(180,388,200,24,24,"GAME OVER !");
- vTaskSuspend(EVENTTask_Handler);
- }
- //全局變量//////////////////////////////////////
- int main(void)
- {
- delay_init(); //延時函數(shù)初始化
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設(shè)置NVIC中斷分組2:2位搶占優(yōu)先級,2位響應(yīng)優(yōu)先級
- Rand_Adc_Init(); //隨機數(shù)初始化
- LED_Init(); //LED端口初始化
- KEY_PLAY_Init(); //按鍵初始化,自制按鍵上/下/左/右/暫停,分別連接PF0/1/2/3/4,低電平接通
- LCD_Init(0);//默認為豎屏模式
- DisplayInit();//打印初始蛇身
- Snake_Init(&snake);//貪吃蛇參數(shù)初始化
- Apple_Init(&apple);//食物參數(shù)初始化
- Event_Init(&event);//事件參數(shù)初始化
- xTaskCreate((TaskFunction_t )start_task, //任務(wù)函數(shù)
- (const char* )"start_task", //任務(wù)名稱
- (uint16_t )START_STK_SIZE, //任務(wù)堆棧大小
- (void* )NULL, //傳遞給任務(wù)函數(shù)的參數(shù)
- (UBaseType_t )START_TASK_PRIO, //任務(wù)優(yōu)先級
- (TaskHandle_t* )&StartTask_Handler); //任務(wù)句柄
- vTaskStartScheduler(); //開啟任務(wù)調(diào)度
- }
-
- //開始任務(wù)任務(wù)函數(shù)
- void start_task(void *pvParameters)
- {
- taskENTER_CRITICAL(); //進入臨界區(qū)
- //創(chuàng)建貪吃蛇任務(wù)
- xTaskCreate((TaskFunction_t )snake_task,
- (const char* )"snake_task",
- (uint16_t )SNAKE_STK_SIZE,
- (void* )NULL,
- (UBaseType_t )SNAKE_TASK_PRIO,
- (TaskHandle_t* )&SNAKETask_Handler);
- //創(chuàng)建食物任務(wù)
- xTaskCreate((TaskFunction_t )apple_task,
- (const char* )"apple_task",
- (uint16_t )APPLE_STK_SIZE,
- (void* )NULL,
- (UBaseType_t )APPLE_TASK_PRIO,
- (TaskHandle_t* )&APPLETask_Handler);
- //創(chuàng)建事件任務(wù)
- xTaskCreate((TaskFunction_t )event_task,
- (const char* )"event_task",
- (uint16_t )EVENT_STK_SIZE,
- (void* )NULL,
- (UBaseType_t )EVENT_TASK_PRIO,
- (TaskHandle_t* )&EVENTTask_Handler);
- //創(chuàng)建顯示任務(wù)
- xTaskCreate((TaskFunction_t )display_task,
- (const char* )"display_task",
- (uint16_t )DISPLAY_STK_SIZE,
- (void* )NULL,
- (UBaseType_t )DISPLAY_TASK_PRIO,
- (TaskHandle_t* )&DISPLAYTask_Handler);
- //創(chuàng)建閃爍任務(wù)
- xTaskCreate((TaskFunction_t )led_task,
- (const char* )"led_task",
- (uint16_t )LED_STK_SIZE,
- (void* )NULL,
- (UBaseType_t )LED_TASK_PRIO,
- (TaskHandle_t* )&LEDTask_Handler);
- //創(chuàng)建輸入任務(wù)
- xTaskCreate((TaskFunction_t )key_task,
- (const char* )"key_task",
- (uint16_t )KEY_STK_SIZE,
- (void* )NULL,
- (UBaseType_t )KEY_TASK_PRIO,
- (TaskHandle_t* )&KEYTask_Handler);
- vTaskDelete(StartTask_Handler); //刪除開始任務(wù)
- taskEXIT_CRITICAL(); //退出臨界區(qū)
- }
- //事件任務(wù)函數(shù),核心數(shù)據(jù)處理函數(shù)
- void event_task(void *pvParameters)
- {
- while(1)
- {
- if(event.GameSta==ON)//如果游戲正常則繼續(xù)
- {
- if(event.Process==ON)//如果沒有暫停則繼續(xù)
- {
- switch(event.Direction)//檢測按鍵情況,根據(jù)方向調(diào)整蛇頭坐標
- {
- case UP:
- {
- snake.firsty-=1;
- if(snake.firsty>GAME_YPART-1)
- {
- snake.firsty=GAME_YPART-1;
- }
- }break;
- case DOWN:
- {
- snake.firsty+=1;
- if(snake.firsty>GAME_YPART-1)
- {
- snake.firsty=0;
- }
- }break;
- case LEFT:
- {
- snake.firstx-=1;
- if(snake.firstx>GAME_XPART-1)
- {
- snake.firstx=GAME_XPART-1;
- }
- }break;
- case RIGHT:
- {
- snake.firstx+=1;
- if(snake.firstx>GAME_XPART-1)
- {
- snake.firstx=0;
- }
- }break;
- }
- snake.lastx=snake_axis[0].x;//保存下蛇尾坐標
- snake.lasty=snake_axis[0].y;
- if(snake.firstx==apple.x&&snake.firsty==apple.y)//如果此時的坐標與食物坐標相同
- {
- event.AppleSta=OFF; //食物被吃掉
- snake.energybuf+=apple.energy;//蛇的能量加一
- vTaskResume(APPLETask_Handler); //使能生成食物函數(shù)
- }
- vTaskResume(DISPLAYTask_Handler); //使能顯示函數(shù)
- }
- }else GameOver();//如果游戲為結(jié)束狀態(tài)則游戲結(jié)束
- delay_ms(1000/snake.speed); //按照蛇的速度調(diào)整此核心數(shù)據(jù)處理函數(shù)的時間間隔
- }
- }
- //輸入任務(wù)函數(shù),根據(jù)按鍵調(diào)整蛇的方向,數(shù)據(jù)處理函數(shù)之前最后一次按鍵視為有效
- void key_task(void *pvParameters)
- {
- u8 key;
- while(1)
- {
- key=KEY_PLAY_Scan(0);//按鍵掃描函數(shù),此處是自制的手柄,上/下/左/右/暫停,分別連接PF0/1/2/3/4,低電平接通
- switch(key)
- {
- case KEY_UP_PRES:
- {
- if(event.Direction!=DOWN)//如果當前方向與按鍵方向相反,則不響應(yīng)
- event.Direction=UP;
- }break;
- case KEY_DOWN_PRES:
- {
- if(event.Direction!=UP)
- event.Direction=DOWN;
- }break;
- case KEY_LEFT_PRES:
- {
- if(event.Direction!=RIGHT)
- event.Direction=LEFT;
- }break;
- case KEY_RIGHT_PRES:
- {
- if(event.Direction!=LEFT)
- event.Direction=RIGHT;
- }break;
- case KEY_PASS_PRES://按下切換暫停/繼續(xù)狀態(tài)
- {
- event.Process=!event.Process;
- }break;
- }
- delay_ms(20);//每20ms響應(yīng)一次
- }
- }
- //食物任務(wù)函數(shù),食物被吃掉時觸發(fā)此函數(shù)
- void apple_task(void *pvParameters)
- {
- u16 flag,i;
- while(1)
- {
- flag=1;
- while(flag)//生成新的食物坐標
- {
- flag=0;
- apple.x=Get_Rand()%(u16)(GAME_XPART);
- apple.y=Get_Rand()%(u16)(GAME_YPART);
- for(i=0;i<snake.length;i++) //食物坐標不能在蛇身上
- {
- if(snake_axis[i].x==apple.x&&snake_axis[i].y==apple.y)
- {
- flag++;
- }
- }
- }
- Display(apple.x,apple.y,RED);//按照坐標將食物顯示出來
- vTaskSuspend(APPLETask_Handler);//掛起任務(wù)
- }
- }
- //貪吃蛇任務(wù)函數(shù) ,此任務(wù)作廢
- void snake_task(void *pvParameters)
- {
- while(1)
- {
- //LED0=!LED0;
- delay_ms(500);
- }
- }
- //顯示任務(wù)函數(shù),顯示蛇頭,消去蛇尾,并更新蛇的坐標
- void display_task(void *pvParameters)
- {
- u16 i;
- while(1)
- {
- Display(snake.firstx,snake.firsty,RED);//顯示蛇頭
- if(snake.energybuf==0) //如果沒有吃到食物
- {
- Display(snake.lastx,snake.lasty,WHITE);//消去蛇尾
- for(i=0;i<snake.length-1;i++)
- {
- snake_axis[i].x=snake_axis[i+1].x;//挨個更新坐標
- snake_axis[i].y=snake_axis[i+1].y;
- }
- }else //如果吃到了食物
- {
- snake.energybuf--;//能量緩沖區(qū)減一
- snake.length++; //蛇身加一
- // if(snake.length%2==0)snake.speed++;
- snake.speed++; //由于地圖很大,故設(shè)置蛇身加一則速度加一
- }
- snake_axis[snake.length-1].x=snake.firstx;//最新的坐標更新為蛇頭的坐標
- snake_axis[snake.length-1].y=snake.firsty;
- for(i=0;i<snake.length-1;i++)//檢查有沒有咬到自己
- {
- if(snake_axis[i].x==snake.firstx&&snake_axis[i].y==snake.firsty)
- {
- event.GameSta=OFF; //遍歷蛇身坐標是否與蛇頭坐標相同
- }
- }
- vTaskSuspend(DISPLAYTask_Handler);
- }
- }
- //閃爍任務(wù)函數(shù),證明程序沒有死機
- void led_task(void *pvParameters)
- {
- while(1)
- {
- LED0=!LED0;
- delay_ms(500);
- }
- }
復(fù)制代碼
所有資料51hei提供下載:
貪吃蛇游戲F1.7z
(356.21 KB, 下載次數(shù): 147)
2019-1-6 04:18 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|