【蓝桥杯】—{模块}—{独立按键}

   九层妖塔 起于垒土
在这里插入图片描述

独立键盘(BTN)

1、原理图

在这里插入图片描述
J523相连,即为独立键盘模式(BTN)
按键S7,S6,S5,S4用作独立按键,分别对应P30,P31,P32,P33

2、实物图

在这里插入图片描述
右 BTN 独立键盘
左 KBD 矩阵键盘

3、波形图

波形图:
在这里插入图片描述

4、Method

1、普通软件延时消抖:

 ●代码:

//独立按键--普通软件延时消抖

#include<STC15F2K60S2.H>
#include<intrins.h>

#define uchar unsigned char
#define uint unsigned int
sbit S4 = P3^3;

uchar SEG_Array[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//数码管段码
uchar yi,er,san,si,wu,liu,qi,ba;
uchar LED_num;  //LED流水计数标志

void All_Init(void);   //开发板初始化
void SEG_Init(void);   //数码管初始化,熄灭所有数码管
void Delay1ms();	  	//@11.0592MHz
void Delay10ms();		  //@11.0592MHz
void SEG_1_2(uchar yi,uchar er);//数码管1,2驱动
void LED_Water(void);  //按键LED流水灯驱动

void main(void)
{
	All_Init();  //开发板初始化
	
	while(1)
	{
		if(S4==0)
		{
			Delay10ms();
			if(S4==0)
			{
				LED_num++;
				if(LED_num==10) LED_num=0;
				while(!S4);
			}
		}
		LED_Water();
		SEG_1_2(LED_num,2);
		SEG_Init();
	}
}


//-------------------------------延时-------------------------------//

void Delay1ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	_nop_();
	i = 11;
	j = 190;
	do
	{
		while (--j);
	} while (--i);
}
void Delay10ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 108;
	j = 145;
	do
	{
		while (--j);
	} while (--i);
}

//----------------------------------初始化---------------------------------//
//----------------------------------开发板初始化--------------------------//
void All_Init(void) 
{
	P2&=0X1F;  //关573
	P0=0XFF;   //预送数据
	P2|=0X80;  
	P2&=0X9F;  //开LED的573
	P0=0XFF;   //关LED
	P2&=0X1F;  //关573
	
	P2&=0X1F;  //关573
	P0=0X00;   //预送数据
	P2|=0XA0;  
	P2&=0XBF;  //开蜂鸣器继电器的573
	P0=0X00;   //关蜂鸣器,继电器	
	P2&=0X1F;  //关573
	
	P2&=0X1F;  //关573
	P0=0X00;   //预送数据
	P2|=0XC0;  
	P2&=0XDF;  //开数码管位选573
	P0=0X00;   //位选,全部不选
	P2&=0X1F;  //关573
	
	P2&=0X1F;  //关573
	P0=0XFF;   //预送数据
	P2|=0XE0;  
	P2&=0XFF;  //开数码管段选573 
	P0=0XFF;   
	P2&=0X1F;  //关573
}

//----------------------------------数码管初始化--------------------------//
void SEG_Init(void)    //关闭熄灭所有数码管
{
	P2&=0X1F;  //关573
	P0=0X00;   //预送数据
	P2|=0XC0;  
	P2&=0XDF;  //开数码管位选573
	P0=0X00;   //位选,全部不选
	P2&=0X1F;  //关573
	
	P2&=0X1F;  //关573
	P0=0XFF;   //预送数据
	P2|=0XE0;  
	P2&=0XFF;  //开数码管段选573 
	P0=0XFF;   
	P2&=0X1F;  //关573
}

//------------------------------------动态数码管驱动-----------------------//
//------------------------------------动态数码管驱动------第一二个---------//
void SEG_1_2(uchar yi,uchar er)
{
	//-------第一个数码管---------//
	P2&=0X1F;         //关573
	P0=SEG_Array[yi]; //预送段选数据
	P2|=0XE0;  
	P2&=0XFF;         //开数码管段选573 
	P0=SEG_Array[yi]; //送段选数据

	P2&=0X1F;  //关573
	P0=0X00;   //消影
	P2|=0XC0;  
	P2&=0XDF;  //开数码管位选573
	P0=0X01;   //送位选数据
	P2&=0X1F;  //关573 
	
	Delay1ms();
	
	//-------第二个数码管---------//
	P2&=0X1F;         //关573
	P0=SEG_Array[er]; //预送段选数据
	P2|=0XE0;  
	P2&=0XFF;         //开数码管段选573 
	P0=SEG_Array[er]; //送段选数据

	P2&=0X1F;  //关573
	P0=0X00;   //消影
	P2|=0XC0;  
	P2&=0XDF;  //开数码管位选573
	P0=0X02;   //送位选数据
	P2&=0X1F;  //关573 
	
	Delay1ms();
}

//-------------------------------按键流水灯驱动--------------//
void LED_Water(void)
{
	P2&=0X1F;  //关573
	P0=0XFF;   //预送数据
	P2|=0X80;  
	P2&=0X9F;  //开LED的573
	P0=~(0X01<<LED_num);
	P2&=0X1F;  //关573
}

 ●流程图:
在这里插入图片描述
 ●松手检查:while(!KEY)等待按键释放。等按键确认释放后再去执行相应代码。防止重入。
 ●CPU在按键按下抖动时进行10ms的软件延时消抖,在数百ms的稳定期以及松手抖动时停滞在松手检测while(!KEY)中,占用CPU资源过多;也就是在整个按键检测期间内,没有再执行其他指令。
 ●按键检测时是借助while(1)死循环进行反复检测。
 ●若是采用普通软件延时消抖10ms的软件延时和松手检测都会占用CPU资源,对其它同样借助while(1)死循环进行反复运行的模块代码产生了挤占影响,比如动态数码管。
 ●稳定期取决于是否松手,若不松手,则数码管将一直保持进入按键检测前最后一次对数码管的操作。

2、标志位软件延时消抖:

 ●代码:

//独立按键--标志位软件延时消抖

#include<STC15F2K60S2.H>
#include<intrins.h>

#define uchar unsigned char
#define uint unsigned int
sbit S4 = P3^3;

uchar SEG_Array[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//数码管段码
uchar yi,er,san,si,wu,liu,qi,ba;
uchar LED_num;  //LED流水计数标志
uchar S4_down;  //S4按键按下标志位

void All_Init(void);   //开发板初始化
void SEG_Init(void);   //数码管初始化,熄灭所有数码管
void Delay1ms();	  	//@11.0592MHz
void Delay10ms();		  //@11.0592MHz
void SEG_1_2(uchar yi,uchar er);//数码管1,2驱动
void LED_Water(void);  //按键LED流水灯驱动

void main(void)
{
	All_Init();  //开发板初始化
	
	while(1)
	{
		if(S4==0 && S4_down==0)
	  {
		 Delay10ms(); 
		 if(S4==0)
		 {
			 S4_down=1;
		 }
	 }
	 if(S4==1 && S4_down==1)
	 {
		 Delay10ms();
		 if(S4==1)
		 {
			 S4_down=0;
			 LED_num++;
			 if(LED_num==10) LED_num=0;
		 }
	 }
	 
		LED_Water();
		SEG_1_2(LED_num,2);
		SEG_Init();
	}
}


//-------------------------------延时-------------------------------//

void Delay1ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	_nop_();
	i = 11;
	j = 190;
	do
	{
		while (--j);
	} while (--i);
}

void Delay10ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 108;
	j = 145;
	do
	{
		while (--j);
	} while (--i);
}

//----------------------------------初始化---------------------------------//
//----------------------------------开发板初始化--------------------------//
void All_Init(void) 
{
	P2&=0X1F;  //关573
	P0=0XFF;   //预送数据
	P2|=0X80;  
	P2&=0X9F;  //开LED的573
	P0=0XFF;   //关LED
	P2&=0X1F;  //关573
	
	P2&=0X1F;  //关573
	P0=0X00;   //预送数据
	P2|=0XA0;  
	P2&=0XBF;  //开蜂鸣器继电器的573
	P0=0X00;   //关蜂鸣器,继电器	
	P2&=0X1F;  //关573
	
	P2&=0X1F;  //关573
	P0=0X00;   //预送数据
	P2|=0XC0;  
	P2&=0XDF;  //开数码管位选573
	P0=0X00;   //位选,全部不选
	P2&=0X1F;  //关573
	
	P2&=0X1F;  //关573
	P0=0XFF;   //预送数据
	P2|=0XE0;  
	P2&=0XFF;  //开数码管段选573 
	P0=0XFF;   
	P2&=0X1F;  //关573
}

//----------------------------------数码管初始化--------------------------//
void SEG_Init(void)    //关闭熄灭所有数码管
{
	P2&=0X1F;  //关573
	P0=0X00;   //预送数据
	P2|=0XC0;  
	P2&=0XDF;  //开数码管位选573
	P0=0X00;   //位选,全部不选
	P2&=0X1F;  //关573
	
	P2&=0X1F;  //关573
	P0=0XFF;   //预送数据
	P2|=0XE0;  
	P2&=0XFF;  //开数码管段选573 
	P0=0XFF;   
	P2&=0X1F;  //关573
}

//------------------------------------动态数码管驱动-----------------------//
//------------------------------------动态数码管驱动------第一二个---------//
void SEG_1_2(uchar yi,uchar er)
{
	//-------第一个数码管---------//
	P2&=0X1F;         //关573
	P0=SEG_Array[yi]; //预送段选数据
	P2|=0XE0;  
	P2&=0XFF;         //开数码管段选573 
	P0=SEG_Array[yi]; //送段选数据

	P2&=0X1F;  //关573
	P0=0X00;   //消影
	P2|=0XC0;  
	P2&=0XDF;  //开数码管位选573
	P0=0X01;   //送位选数据
	P2&=0X1F;  //关573 
	
	Delay1ms();
	
	//-------第二个数码管---------//
	P2&=0X1F;         //关573
	P0=SEG_Array[er]; //预送段选数据
	P2|=0XE0;  
	P2&=0XFF;         //开数码管段选573 
	P0=SEG_Array[er]; //送段选数据

	P2&=0X1F;  //关573
	P0=0X00;   //消影
	P2|=0XC0;  
	P2&=0XDF;  //开数码管位选573
	P0=0X02;   //送位选数据
	P2&=0X1F;  //关573 
	
	Delay1ms();
}

//-------------------------------按键流水灯驱动--------------//
void LED_Water(void)
{
	P2&=0X1F;  //关573
	P0=0XFF;   //预送数据
	P2|=0X80;  
	P2&=0X9F;  //开LED的573
	P0=~(0X01<<LED_num);
	P2&=0X1F;  //关573
}

 ●波形图:
在这里插入图片描述
 ●通过引入按下标志位,省去了while(!KEY)的松手检测,将按下时稳定期的数百ms释放出来,只占用了按下和松手时的共20ms的消抖时间。
 ●若采用10ms消抖,按下和松手时刻,数码管仍然会有轻微闪动。

3、状态机:

4、定时器:

5、三行代码:

5、Template

Template1、标志位软件延时消抖:

//独立按键--标志位软件延时消抖
sbit S4 = P3^3;
sbit S5 = P3^2;
sbit S6 = P3^1;
sbit S7 = P3^0; 

void keyscan_4(void); //独立按键扫描


//-------------------------------------独立按键扫描---------------------//
void keyscan_4(void)
{
	static uchar S4_down,S5_down,S6_down,S7_down;  //S4-S7独立按键按下标志位
	
		if(S4==0 && S4_down==0)  //S4
	  {
		 Delay10ms(); 
		 if(S4==0)
		 {
			 S4_down=1;
		 }
	 }
	 if(S4==1 && S4_down==1)
	 {
		 Delay10ms();
		 if(S4==1)
		 {
			 S4_down=0;
			 SEG_num1++;
			 if(SEG_num1==10) SEG_num1=0;
		 }
	 }
	 
	 if(S5==0 && S5_down==0)   //S5
	 {
		Delay10ms();
		if(S5==0)
		{
			S5_down=1;
		}
	 }
	 if(S5==1 && S5_down==1)
	 {
		Delay10ms();
		if(S5==1)
		{
			S5_down=0;
			SEG_num2++;
			if(SEG_num2==10) SEG_num2=0;
		}
	 }
	 
	  if(S6==0 && S6_down==0)   //S6
	 {
		Delay10ms();
		if(S6==0)
		{
			S6_down=1;
		}
	 }
	 if(S6==1 && S6_down==1)
	 {
		Delay10ms();
		if(S6==1)
		{
			S6_down=0;
			SEG_num3++;
			if(SEG_num3==10) SEG_num3=0;
		}
	 }
	 
	  if(S7==0 && S7_down==0)   //S7
	 {
		Delay10ms();
		if(S7==0)
		{
			S7_down=1;
		}
	 }
	 if(S7==1 && S7_down==1)
	 {
		Delay10ms();
		if(S7==1)
		{
			S7_down=0;
			SEG_num4++;
			if(SEG_num4==10) SEG_num4=0;
		}
	 }
}


参考1
参考2
参考3
参考4
参考5

猜你喜欢

转载自blog.csdn.net/qq_43935020/article/details/107676505