51微控制器系列(三)51 微控制器遊戲設計 —— 雙人對戰小遊戲(石頭剪刀布)

BeLoved91發表於2020-12-14

本部落格51微控制器實訓系列,旨在記錄本人在大學上微控制器技術這門課時所做的課程實訓內容,並與大家分享基於51單片的課程作業,如果作業中的某些細節和程式碼能給大家一點啟發那就更好了,希望大家能用51微控制器做出多姿多彩的東西。最後不要忘記,我們的目標是星辰大海!

51微控制器系列(三)51 微控制器遊戲設計 —— 雙人對戰小遊戲(石頭剪刀布)


在這裡插入圖片描述

實驗遊戲規則介紹

本遊戲(石頭剪刀布)玩法如下:
1、本遊戲分為甲乙雙方,採用 8*8 點整顯示出拳結果
①(“石頭”-用圓角矩形表示)
②(“剪刀”-用大寫字母 X 表示)
③(“布” -用矩形表示)
④通過 Led1-4 顯示甲方的積分,Led5-8 顯示乙方的積分
2、本遊戲採用 5 局 3 勝制。
①甲方通過控制獨立按鍵的 key1(石頭)、key3(剪刀)、key4(布)。
②乙方通過控制矩陣鍵盤 S1(石頭)、S2(剪刀)、S3(布)。
③當甲方勝利,甲方積分加 1,甲方的 Led 燈區域點亮一盞燈(表示獲得 1 積分),乙方同理。
④當其中一方率先到達 3 分時,這一方的四棧 led 全亮,蜂鳴器發出遊戲結 束的聲音(提示其中一方獲勝)。
3、開啟微控制器電源,顯示遊戲未開始的介面。該介面由石頭剪刀布以及一個向 右的箭頭組成,玩家可以按下 S15 鍵開始遊戲,然後遊戲進入到等待輸入介面。
4、當一局遊戲結束時,玩家可以按下 S16 鍵來重置遊戲(重新開一局)

實驗遊戲詳細介紹

首先開啟 51 板子電源後,我們能看到 88 點陣顯示的遊戲等待介面。介面 上有四個圖形分別是:圓角矩形(代表石頭)、大寫字母 X(代表剪刀)、矩形 (代表布)、向右的箭頭(意味著遊戲馬上開始)。當我們按下矩陣鍵盤區的 S15 時,遊戲開始 88 點陣變黑等待玩家的輸入。遊戲的甲玩家操控獨立按鍵區 的 Key1(代表石頭)、Key3(代表剪刀)、Key4(代表布),乙玩家操控矩陣 按鍵區的 S1(代表石頭)、S2(代表剪刀)、S3(代表布)。雙方的出拳結果會顯示 到 8*8 點陣,並且本遊戲設計 Led1-4 顯示玩家甲的積分,led5-8 顯示玩家乙的 積分。當其中一方勝利一局時,對應的 led 區域點亮一盞燈。當其中一個玩家的 積分到達三分時,4 棧 led 燈全亮,蜂鳴器響起,代表玩家獲勝。此時玩家可以 通過矩陣鍵盤的 S16 重新開始一局遊戲。

實驗遊戲計算推導過程

在這裡插入圖片描述

實驗專案所用到的模組

LED 模組,74HC138 譯碼器,8*8 點陣模組,獨立按鍵模組,矩陣按鍵模組,蜂 鳴器模組。

表格展示

在這裡插入圖片描述

演算法流程圖

在這裡插入圖片描述

程式清單

//
// Created by BeLoved91 on 2020-12-14.
//
#include "reg51.h"
#include "intrins.h"

typedef	unsigned char u8;
typedef	unsigned int u16;

#define led P2	   //將P2口定義為led 後面就可以使用led代替P2口
#define GPIO_KEY P1		   //矩陣按鍵
u8 KeyValue;	//用來存放讀取到的鍵值			  
//--定義使用的IO口--//
sbit SRCLK=P3^6;
sbit RCLK=P3^5;
sbit SER=P3^4;

sbit k1 = P3^1;
sbit k2 = P3^0;
sbit k3 = P3^2;
sbit k4 = P3^3;
//蜂鳴器
sbit beep =  P1^5; 
u8 ledwei[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
u8 ledduan[10][8]=
{0x60,0x90,0x90,0x60,0x06,0x09,0x09,0x06, //石頭-石頭
 0x60,0x90,0x90,0x60,0x09,0x06,0x06,0x09, //石頭-剪刀
 0x60,0x90,0x90,0x60,0x0f,0x09,0x09,0x0f, //石頭-布
 0x90,0x60,0x60,0x90,0x06,0x09,0x09,0x06, //剪刀-石頭
 0x90,0x60,0x60,0x90,0x09,0x06,0x06,0x09, //剪刀-剪刀
 0x90,0x60,0x60,0x90,0x0f,0x09,0x09,0x0f, //剪刀-布
 0xf0,0x90,0x90,0xf0,0x06,0x09,0x09,0x06, //布-石頭
 0xf0,0x90,0x90,0xf0,0x09,0x06,0x06,0x09, //布-剪刀
 0xf0,0x90,0x90,0xf0,0x0f,0x09,0x09,0x0f, //布-布
 0x6f,0x99,0x99,0x6f,0x94,0x64,0x6e,0x94  //開局畫面									
};

//甲的分數,乙的分數。
u8 jiaScore =0,yiScore=0;
//重置遊戲標誌位
u8 flag = 0;
//獲勝者標識   0代表甲贏,1代表乙贏。
u8 vy = -1;

u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//顯示0~F的值
 
void delayfordig(u16 time){		//延時函式
 	
	u16 i,j;
	for(i=0;i<time;i++){
		 for(j=0;j<121;j++){
		 }
	}
	
}
void delay(u16 i){
 	while(i--);
}
void Hc595SendByte(u8 dat)	  //傳送段選訊號
{
	u8 a;
	SRCLK=0;
	RCLK=0;
	for(a=0;a<8;a++)
	{
		SER=dat>>7;
		dat<<=1;
		SRCLK=1;
		_nop_();
		_nop_();
		SRCLK=0;	
	}

	RCLK=1;
	_nop_();
	_nop_();
	RCLK=0;
}

void showresult(u8 j){
	u8 tab,count=16;
	u16 i;
	while(count--){
	for(i=0;i<6;i++)
	{
		for(tab=0;tab<8;tab++)
		{
			    Hc595SendByte(0x00); //消隱
			    P0=ledwei[tab];
				Hc595SendByte(ledduan[j][tab]);
				delayfordig(2);
		}
	}
   }
    Hc595SendByte(0x00); //消隱
}

//矩陣鍵盤
void KeyDown(void)
{
	char a=0;
	GPIO_KEY=0x0f;
	if(GPIO_KEY!=0x0f)//讀取按鍵是否按下
	{
		delay(1000);//延時10ms進行消抖
		if(GPIO_KEY!=0x0f)//再次檢測鍵盤是否按下
		{	
			//測試列
			GPIO_KEY=0X0F;
			switch(GPIO_KEY)
			{
				case(0X07):	KeyValue=1;break;
				case(0X0b):	KeyValue=2;break;
				case(0X0d): KeyValue=3;break;
				case(0X0e):	KeyValue=4;break;
			}
			//測試行
			GPIO_KEY=0XF0;
			switch(GPIO_KEY)
			{
				case(0X70):	KeyValue=KeyValue;break;
				case(0Xb0):	KeyValue=KeyValue+4;break;
				case(0Xd0): KeyValue=KeyValue+8;break;
				case(0Xe0):	KeyValue=KeyValue+12;break;
			}
			
		}
		}
	while((a<50)&&(GPIO_KEY!=0xf0))	 //檢測按鍵鬆手檢測
	{
		delay(100);
		a++;
	}
}
void bmp()    //遊戲結束時,蜂鳴器發出聲音函式
{
	u8 t=500;
	while(t--)
	{
		beep=~beep;
		delay(500);	
	}
}
//遊戲邏輯處理
void handler();
//結果處理
void resultJudge(); 
void main()
{
u8 count = 20;
  //熄滅所有燈
  led=0xff;
  while(count--)
  {	
  		//熄滅所有燈
  		led=0xff;
  		//初始化得分
  		jiaScore =0,yiScore=0;
  		//開場畫面
		showresult(9);
  		while(flag){
  		KeyValue=0;//復位
 		KeyDown();		   //按鍵判斷函式
		handler();		   //遊戲邏輯處理
		resultJudge();     //結果處理
		}
		if(vy == 0){
		  led = 0xf0;      //led0-led3,一直亮表示甲贏
		  bmp();		   //提示遊戲結束
		    delay(5000);
		  delay(5000);
		  vy = -1;
		}
		if(vy == 1){
		  led = 0x0f;	   //led4-led7,一直亮表示乙贏
		  bmp();           //提示遊戲結束
		  delay(5000);
		  delay(5000);
		  vy = -1;
		}
		KeyDown();		   //按鍵判斷函式
		if(KeyValue == 15){//當按下s15時,開始遊戲
		  flag = 1;
		  KeyValue = 0;
		}
		if(KeyValue == 16){//當按下s16時,重置比賽
		  flag = 1;
		  KeyValue = 0;
		  //熄滅所有燈
  	      led=0xff;
		}
  }
}
//結果處理
void resultJudge(){
	if(jiaScore == 0 && yiScore == 1){
		   led = 0xef;
		   delay(50000);
	}
	if(jiaScore == 0 && yiScore == 2){
		   led = 0xcf;
		   delay(50000);
	}
	if(jiaScore == 0 && yiScore == 3){	//0-3乙勝利
		   led = 0x8f;
		   delay(20000);  
		   flag = 0;
		   vy = 1;
		   return ;
	}


	if(jiaScore == 1 && yiScore == 0){
		   led = 0xfe;
		   delay(50000);
	}
	if(jiaScore == 1 && yiScore == 1){
		   led = 0xee;
		   delay(50000);
	}
	if(jiaScore == 1 && yiScore == 2){
		   led = 0xce;
		   delay(50000);
	}
	if(jiaScore == 1 && yiScore == 3){   //1-3乙勝利
	       led = 0x8e;
		   delay(20000);  
		   flag = 0;
		   vy = 1;
		   return ;
	}


	if(jiaScore == 2 && yiScore == 0){
		   led = 0xfc;
		   delay(50000);
	}
	if(jiaScore == 2 && yiScore == 1){
		   led = 0xec;
		   delay(50000);
	}
	if(jiaScore == 2 && yiScore == 2){
		   led = 0xcc;
		   delay(50000);
	}
	if(jiaScore == 2 && yiScore == 3){   //2-3乙勝利
	       led = 0x8c;
		   delay(20000);  
		   flag = 0;
		   vy = 1;
		   return ;
	}


	if(jiaScore == 3 && yiScore == 0){	 //3-0甲勝利
		   led = 0xf8;
	       delay(20000);
		   flag = 0;
		   vy = 0;
	}
	if(jiaScore == 3 && yiScore == 1){	 //3-1甲勝利
		   led = 0xe8;
	       delay(20000);
		   flag = 0;
		   vy = 0;
	}
	if(jiaScore == 3 && yiScore == 2){	 //3-2甲勝利
		   led = 0xd8;
		   delay(20000);  
		   flag = 0;
		   vy = 0;
		   return ;
	}
}
//遊戲邏輯處理
void handler(){
		//情況二	 //石頭-石頭  //石頭-剪刀   //石頭-布
	 	if(k1 == 0 &&  KeyValue==1)
  		{
			delay(1000);
			if(k1 == 0){
			   showresult(0);   //石頭-石頭
			   KeyValue=0;//復位
			}
			while(!k1);
		}
		if(k1 == 0 &&  KeyValue==2)
  		{
			delay(1000);
			if(k1 == 0){
			   showresult(1);   //石頭-剪刀
			   jiaScore++;		//甲贏了,加一分
			   KeyValue=0;//復位
			}
			while(!k1);
		}			
		if(k1 == 0 &&  KeyValue==3)
  		{
			delay(1000);
			if(k1 == 0){
			   showresult(2);   //石頭-布
			   yiScore++;		//乙贏了,加一分
			   KeyValue=0;//復位
			}
			while(!k1);
		}


		//情況二	 //剪刀-石頭  //剪刀-剪刀   //剪刀-布
		if(k3 == 0 &&  KeyValue==1)
  		{
			delay(1000);
			if(k3 == 0){
			   showresult(3);   //剪刀-石頭
			   yiScore++;		//乙贏了,加一分
			   KeyValue=0;//復位
			}
			while(!k1);
		}
		if(k3 == 0 &&  KeyValue==2)
  		{
			delay(1000);
			if(k3 == 0){
			   showresult(4);    //剪刀-剪刀
			   KeyValue=0;//復位
			}
			while(!k1);
		}			
		if(k3 == 0 &&  KeyValue==3)
  		{
			delay(1000);
			if(k3 == 0){
			   showresult(5);    //剪刀-布	 
			   jiaScore++;       //甲贏了,加一分
			   KeyValue=0;//復位
			}
			while(!k1);
		}

			//情況三	 //布-石頭  //布-剪刀   //布-布
		if(k4 == 0 &&  KeyValue==1)
  		{
			delay(1000);
			if(k4 == 0){
			   showresult(6);    //布-石頭
			   jiaScore++;       //甲贏了,加一分 
			   KeyValue=0;//復位
			}
			while(!k1);
		}
		if(k4 == 0 &&  KeyValue==2)
  		{
			delay(1000);
			if(k4 == 0){
			   showresult(7);     //布-剪刀 
			   yiScore++;		  //乙贏了,加一分
			   KeyValue=0;//復位
			}
			while(!k1);
		}			
		if(k4 == 0 &&  KeyValue==3)
  		{
			delay(1000);
			if(k4 == 0){
			   showresult(8);     //布-布
			   KeyValue=0;//復位
			}
			while(!k1);
		}
}

程式碼有點長,這是一次課後作業,大概花了一個星期完成。

相關文章