C51模拟CSGO的C4炸弹小程序

本文章使用的道具有LCD1602显示屏、矩阵键盘、这两个,可以买普中的C51练习板这些东西都会带有。

规则:

开始用矩阵键盘输入密码7355608按S16启动炸弹

炸弹倒计时15秒后爆炸

按住独立按键拆弹,拆弹时间为3.5秒

S14为重置游戏(炸弹启动后无法重置),S15为清空密码重新输入,S16为确定,S1-S9为1-9,S10为0

如图所示

  

一、 LCD1602的代码编程

这个现实屏幕的代码编程参考了B站up主江协科技的部分代码,编写思路也差不多,详情见链接

http://【51单片机入门教程-2020版 程序全程纯手打 从零开始入门】 https://www.bilibili.com/video/BV1Mb411e7re/?p=32&share_source=copy_web&vd_source=a87f3237d624c356d11c0b6df1a6ff91

代码部分

#include <REGX52.H>
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_E=P2^7;
#define LCD_DataPort P0	//将LCD1602的D0口直接换成P0

void LCD_Delay()		//@12.000MHz,延时一毫秒,1602执行LCD—E用
{
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
}
//写入指令
void LCD_WriteCommand(unsigned char Command){	        
	LCD_RS=0;	       //根据LCD1602写操作时序图,给低电平,之后同理
	LCD_RW=0;	
	LCD_DataPort=Command;
	LCD_E=1;
	LCD_Delay();         //延时由于指令执行时间问题,速度太快可能读不过来
	LCD_E=0;
	LCD_Delay();
}
//写入数据
void LCD_WriteData(unsigned char Data){
	LCD_RS=1;	       
	LCD_RW=0;	
	LCD_DataPort=Data;
	LCD_E=1;
	LCD_Delay();         
	LCD_E=0;
	LCD_Delay();
}
//1602初始化
void LCD_Init(void){
	LCD_WriteCommand(0x38);   //八位数据接口,两行显示,5*7点阵    
	LCD_WriteCommand(0x0c);		//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);		//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);		//清屏
}
//设置光标位置
void LCD_setCursor(unsigned char Line,unsigned char Column){
	if(Line==1){
		LCD_WriteCommand(0x80|(Column-1));		//由计算得
	}
	else{
		LCD_WriteCommand(0x80|(Column-1)+0x40);
	}
}
//1602显示字符
void LCD_showChar(unsigned char Line, unsigned char Column, unsigned char Char) //显示字符(指定行,列,字符)
{
    LCD_setCursor(Line, Column);
    LCD_WriteData(Char);
}
//在LCD1602指定位置开始显示所给字符串
void LCD_ShowString(unsigned char Line,unsigned char Column,unsigned char *String){
	unsigned char i;
	LCD_setCursor(Line,Column);
	for(i=0;String[i]!='\0';i++){
		LCD_WriteData(String[i]);
	}
}
//返回值=X的Y次方
int LCD_Pow(int X,int Y){
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++){
		Result*=X;
	}
	return Result;
}
//在LCD1602指定位置开始显示所给数字
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length){
	unsigned char i;
	LCD_setCursor(Line,Column);
	for(i=Length;i>0;i--){
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}
//在LCD1602显示字符串,随着循环length次显示第i个字符
void LCD_ShowCharlist(unsigned char Line,unsigned char Column,char *String,unsigned char length)
{
	unsigned char i;
	LCD_setCursor(Line,Column);
	for(i=0;i<length;i++)
	{
		LCD_WriteData(String[i]);
	}
}

允许用户调用函数

.h文件配置,使用方法基本上大同小异我只给出两段演示

#ifndef __LCD1602_H__
#define __LCD1602_H__
//用户调用函数
void LCD_Init(void);
void LCD_showChar(unsigned char Line,unsigned char Column,unsigned char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,unsigned char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowCharlist(unsigned char Line,unsigned char Column,char *String,unsigned char length);
#endif

 二、 矩阵键盘代码编程

同样参考了江科自协的51入门教程,链接如下

http://【51单片机入门教程-2020版 程序全程纯手打 从零开始入门】 https://www.bilibili.com/video/BV1Mb411e7re/?p=15&share_source=copy_web&vd_source=a87f3237d624c356d11c0b6df1a6ff91

代码

#include <REGX52.H>
#include "Delay.h"
/**
  * @brief  矩阵键盘读取按键键码
  * @param  无 
  * @retval KeyNumber 按下按键的键码值
	          如果按键按下不放,程序会停留在此函数,松手瞬间,返回按键键码
						没有按键返回零
  */
unsigned char MatrixKey()
{
  unsigned char KeyNumber=0;
	
  P1=0xFF;
  P1_3=0;
  if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;}
  if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=5;}
  if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=9;}
  if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=13;}
	
	P1=0xFF;
  P1_2=0;
  if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=2;}
  if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=6;}
  if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=10;}
  if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=14;}
	
	P1=0xFF;
  P1_1=0;
  if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=3;}
  if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=7;}
  if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=11;}
  if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=15;}
		
	P1=0xFF;
  P1_0=0;
  if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=4;}
  if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=8;}
  if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=12;}
  if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=16;}
  return KeyNumber;

}

允许用户调用函数

.h文件配置,使用方法基本上大同小异我只给出两段演示

#ifndef __MATRIXKEY_H__
#define __MATRIXKEY_H__

unsigned char MatrixKey();
	
#endif

  、 延时代码编程

多次用到,你也可以用在主函数里,利用stc-isp生成。需要.h文件调用。

#include <INTRINS.H>
void	Delay(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms--)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
  }
}

void Delayus()		//@12.000MHz
{
	unsigned char i;

	_nop_();
	i = 47;
	while (--i);
}

四、 定时器代码编程

需要.h文件调用。

#include <REGX52.H>

/**
  * @brief  定时器0初始化,1毫秒@12.000MHZ
  * @param  无
  * @retval 无
  */
void Timer0Init(void)
{
	 TMOD&=0xF0; //把TMOD的低四位清零,高四位保持不变
	 TMOD|=0x01; //把TMOD的最低位置1,高四位保持不变
	 TL0=0x18;   //设置定时器初值
	 TH0=0xFC;	 //设置定时器初值
	 TF0=0;      //清除TF0标志
	 TR0=1;      // 定时器0开始计时
	 ET0=1;			//打开定时器
	 EA=1;			//打开总中断
	 PT0=0;
   
}

//定时器中断函数模板
//void Timer0_Routine() interrupt 1
//{
//	 static unsigned int T0Count;
//	 TL0=0x18;
//	 TH0=0xFC;	 
//	 T0Count++;
//	 if(T0Count>=1000)
//	 {
//	   T0Count=0;
        
//	 }

//}

五、 独立按键编程

需要.h文件调用。

#include "Key.h"


unsigned char key_scan()
{
	if(KEY1==0)
	{
		//while(KEY1==0);
		return KEY1_PRESS;
	}
	else if(KEY2==0)
	{
		//while(KEY2==0);
		return KEY2_PRESS;
	}
	else if(KEY3==0)
	{
		//while(KEY3==0);
		return KEY3_PRESS;
	}
	else if(KEY4==0)
	{
		//while(KEY4==0);
		return KEY4_PRESS;
	}
	else
	{
		return KEY_UNPRESS;		
	}
}

主函数代码

思路就是利用指针LCD显示多位密码,简易密码锁加上判断条件。这个代码的缺点是无法加速报警,加速报警之后会和拆弹抢时间。

#include <REGX52.H>
#include "LCD1602.h"  //LCD1602
#include "MatrixKey.h"	//矩阵键盘
#include "Delay.h"	//延时
#include "Timer0.h"	//定时器
#include "Key.h"	//独立按键
#define len_pd 7	//密码长度

sbit Buzzer=P2^5;		//定义蜂鸣器为P2.5
unsigned char KeyNum,Sec=15,flag,cai=0;		//定义字节,keyNum为矩阵按键、Sce为爆炸倒计时秒数、flag为判断字符、cai为拆弹密码计数
unsigned int j,i;	//定义整数j、i
int Count = 0;	//定义输入密码计数
unsigned char Password[len_pd]={'7','3','5','5','6','0','8'};	//密码
unsigned char Temp_Password[len_pd];	//中间变量
void Buzzer_Time(unsigned int ms){	//蜂鸣器配置
	unsigned int i;
	for (i=0;i<ms;i++){	
		Buzzer = !Buzzer;
		Delay(1);
	}
}
void main()
{
	for(i=0;i<len_pd;i++){
		Temp_Password[i]='*';	//密码清零
	}
	LCD_Init();	//1602初始化
	Timer0Init();	//定时器初始化
	TR0=0;	//关定时器
	LCD_ShowString(1,1,"C4 Password:");
	LCD_ShowCharlist(2,17-len_pd,Temp_Password,len_pd);	//更新显示
	
	while(1){
		KeyNum=MatrixKey();	//矩阵键盘使用
		if(KeyNum){
			if(KeyNum==10)//S10代表0
			{
				KeyNum=0;
			}
			if(KeyNum<=10)				//如果按键S1~S10按键按下,输入密码
			{
				for(i=0;i<100;i++){	//按键提示音
				Buzzer=~Buzzer;
				Delay(1);
				}
				if(Count<len_pd){	//如果输入次数小于7
				Temp_Password[Count]=KeyNum+48;				//获取一位密码
				Count++;	//计次加一
			}
			LCD_ShowCharlist(2,17-len_pd,Temp_Password,len_pd);	//更新显示
		}
		if(KeyNum==16&&Count==7){			//如果S16按下且输入位数等于7位,确认
			flag=1;	//密码判断正确标志
			for(i=0;i<len_pd;i++){
			if(Temp_Password[i]!=Password[i]){	//如果不等于正确密码
				LCD_ShowString(1,14,"ERR");				//显示ERR
				flag=0;	
			}
		}
		if(flag==1){
				LCD_ShowString(1,14,"OK ");	//显示OK
				Delay(300);	
			for(i=0;i<len_pd;i++){
				Temp_Password[i] = '*';				//密码清零
			}
				Count=0;	//计数清零
				LCD_ShowCharlist(2,17-len_pd,Temp_Password,len_pd); //更新显示
				flag=0;	//密码判段标志清零
				Timer0Init();	//定时器初始化
				TR0=1;	//开定时器
				while(1){
					LCD_ShowString(1,1,"Protect Bomb    ");
					LCD_ShowNum(2,1,Sec,2);	//更新显示,进入引爆倒计时
					if(KEY1==0||KEY2==0||KEY3==0||KEY4==0){						
						cai++;
						Delay(500);	//若独立按键按下,拆弹密码计数加一,每0.5秒输入一个密码
						LCD_ShowCharlist(2,17-len_pd,Temp_Password,len_pd);	
						LCD_ShowCharlist(2,17-len_pd,Password,cai);	//更新显示
						if(cai==len_pd){	//若拆弹计数等于密码,拆弹成功
							LCD_ShowCharlist(2,17-len_pd,Password,len_pd);	//更新显示
							LCD_Init();	//用1602初始化清屏
							TR0=0;	//关定时器
							P2 = 0x00;		
							Buzzer_Time(300);
							P2 = 0xFF;
							Delay(100);
							P2 = 0x00;
							Buzzer_Time(300);
							P2 = 0xFF;
							LCD_ShowString(1 ,5,"You Win");
							LCD_ShowString(2,1,"Press S14 restart");	//显示胜利,按下S14重新开始
							break;
					}
				}
					else{
						cai=0;	//拆弹计数清零
					}
					if(Sec==0){		//引爆!!!!!!
					for(i=0;i<100;i++){
						P2 = 0x00;
						Buzzer_Time(100);
						P2 = 0xFF;
					}
					TR0=0;	
					LCD_Init();		//1602初始化清屏
					LCD_ShowString(1,5,"You Lost");
					LCD_ShowString(2,1,"Press S14 restart");	显示失败,按下S14重新开始
					break;
			} 
		}
			}
		else{
			LCD_ShowString(1,14,"ERR");	//显示ERR
			for(i=0;i<len_pd;i++){
				Temp_Password[i] = '*';		//密码清零
			}
			Count=0;	//计次清零
			LCD_ShowCharlist(2,17-len_pd,Temp_Password,len_pd);	//更新显示
		}
		}
		if(KeyNum==15)	//如果S15被按下,清零
		{
			for(i=0;i<len_pd;i++)
				{
					Temp_Password[i] = '*';	//密码清零
				}
			Count=0;				//计次清零
			LCD_ShowString(1,14,"   ");	//清楚显示
			LCD_ShowCharlist(2,17-len_pd,Temp_Password,len_pd);	//更新显示
			}
		if(KeyNum==14){	//重置游戏,炸弹启动时无法重置(没有回头路)
			return;
			}
		}
	}
}
//定时器中断
void Timer0_Routine() interrupt 1
{
	 static unsigned int T0Count;
	 TL0=0x18;
	 TH0=0xFC;	 
	 T0Count++;
	 if(T0Count>=1000)	//若定时器小于等于1000毫秒,计数清零,Sec自减
	 {
		 T0Count=0;
		 Sec--;
		 if(Sec){	//报警,让蜂鸣器随秒数响
				for(i=0;i<100;i++){
					Buzzer=~Buzzer;
					Delay(1);
			 }
		 }
	 }
}

整个编程图

猜你喜欢

转载自blog.csdn.net/qq2606393744/article/details/131637647
C4
C51