蓝桥杯之按键

本文详细介绍了在蓝桥杯开发板上独立按键与矩阵按键的检测方法,包括使用延时函数消除按键抖动和利用定时中断进行扫描的高级技巧。通过具体的代码示例,展示了如何读取IO口电平状态判断按键状态,并提供了矩阵按键的检测思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

声明:代码确实写的不好,用的都是最笨的方法实现功能,不喜勿喷
其实按键的检测主要是检测IO口的电平。下面看一下蓝桥杯板子上的按键的电路图:

这块开发板上是通过跳线帽来控制独立按键和矩阵按键的,用跳线帽将2和3连在一起就是独立按键,将2和1连在一起就是矩阵按键。

独立按键:

对于独立按键的控制相对来说比较简单,我们只需要读取 P30、P31、P32、P33四个IO口的电平状态就可以判断按键是否按下了。

对于这个板子来说只要判断这四个IO是不是低电平就可以判断按键是否按下了。

直接看一下代码:

void keyscan()
{
    	if(P30==0)
		{
				Delay6ms();
				if(P30==0)
				{
					P00 = 0;
				}
				while(!P30);	
		}
		else if(P31==0)
		{
				Delay6ms();
				if(P31==0)
				{
					P01 = 0;
				}
				while(!P31);	
		}
		else if(P32==0)
		{
				Delay6ms();
				if(P32==0)
				{
					P02 = 0;
				}
				while(!P32);	
		}
		else if(P33==0)
		{
				Delay6ms();
				if(P33==0)
				{
					P03 = 0;
				}
				while(!P33);	
		}
}
void Delay6ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	_nop_();
	i = 65;
	j = 136;
	do
	{
		while (--j);
	} while (--i);
}

一般来说对于按键的判断我们都是在按键按下之后把一些标志位置位或者直接去操控一下东西,比如点亮LED灯、数码管显示等。

对于按键的检测大部分情况下是要消除抖动的,在程序中Delay6ms()延时之后在次判断是否按下就是为了消除抖动。当然最后我们也是要进行松手检测的,这样可以防止程序发生一些不必要的错乱。

还有一种独立按键的检测方式,这种方式可以不用延时函数,而是用定时中断来定时扫描,下面看一下程序:

uchar KeySta[4] = {1,1,1,1};//独立按键的当前状态
void main()
{
	uchar backup[4] = {1,1,1,1};//按键值备份,保存前一次的值
	uchar cnt;
	P2 = 0XA0;P0 = 0X00;//关闭蜂鸣器和继电器
	P2 = 0X80;P0= 0XFF;//开启流水灯
	P2=0XC0;P0=0XFF;//开启数码管片选端,选中所有数码管
	P2=0XEF;P0=0XFF;//开启数码管段选端,关闭所有段
	Timer0Init();	
	while(1)
	{
		if(KeySta[0] != backup[0])		//当前值与前一次值不相等说明此时按键有动作
		{
			if(backup[0] == 1)					//如果前一次值为1说明当前是按下动作
			{
				cnt++;
				Display1_2(cnt,cnt+1);				
			}		
			if(backup[0] == 0)					//如果前一次值为0说明当前是弹起动作
			{

			}
			backup[0] = KeySta[0];
		}
		if(KeySta[1] != backup[1])
		{
			if(backup[1] == 0)
			{
				Display4_5(4,5);
			}
			backup[1] = KeySta[1];
		}
		if(KeySta[2] != backup[2])
		{
			if(backup[2] == 0)
			{
				Display3_6(10,10);
			}
			backup[2] = KeySta[2];
		}
		if(KeySta[3] != backup[3])
		{
			if(backup[3] == 0)
			{
				Display7_8(7,8);
			}
			backup[3] = KeySta[3];
		}
	}	
}

void Timer0Init(void)		//2毫秒@11.0592MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x9A;		//设置定时初值
	TH0 = 0xA9;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	EA = 1;
	ET0 = 1;
}

void Timer0() interrupt 1
{
	static unsigned char keybuf[4] = {0XFF,0XFF,0XFF,0XFF};//扫描缓冲区,保存一段时间内的扫描值
	uchar i;
	TL0 = 0x9A;		//设置定时初值
	TH0 = 0xA9;		//设置定时初值
	//将四个独立按键值移入缓冲区
	keybuf[0] = (keybuf[0]<<1)| P30;
	keybuf[1] = (keybuf[1]<<1)| P31;	
	keybuf[2] = (keybuf[2]<<1)| P32;
	keybuf[3] = (keybuf[3]<<1)| P33;	
	for(i=0;i<4;i++)
	{
		if(keybuf[i] == 0x00)//连续八次扫描全为0,说明按键已经按下
		{
			KeySta[i] = 0;
		}
		else if(keybuf[i] == 0XFF)//连续八次扫描全为1,说明按键已经按下
		{
			KeySta[i] = 1;
		}		
	}
}

矩阵按键:

矩阵按键相对来说比较麻烦一点,一般我们用的检测思路是对高四位的其中一位赋值零检测低四位,或者低低四位的其中一位赋值零检测高四位。

判断的依据和处理的方法和独立按键是一样的,下面来看一下代码:

void keysca16()
{
		uchar temp;
		//第一列按键
		P3 = 0X7F;P42 = 1;P44=0;
		temp = P3;
		temp = temp&0X0F;
		if(temp!=0X0F)
		{
			Delay6ms();
			if(temp!=0X0F)
			{
				temp = P3;
				switch(temp)
				{
					case 0X7E: P0=0XFE;break;
					case 0X7D: P0=0XFD;break;
					case 0X7B: P0=0XFB;break;
					case 0X77: P0=0XF7;break;
				}
				while(temp!=0X0F)
				{
					temp = P3;
					temp = temp&0X0F;
				}
			}
		}
		//第二列按键
		P3 = 0XBF;P42 = 0;P44 = 1;
		temp = P3;
		temp = temp&0X0F;
		if(temp!=0X0F)
		{
			Delay6ms();
			if(temp!=0X0F)
			{
				temp = P3;
				switch(temp)
				{
					case 0XBE: P0=0XEF;break;
					case 0XBD: P0=0XDF;break;
					case 0XBB: P0=0XBF;break;
					case 0XB7: P0=0X7F;break;
				}
				while(temp!=0X0F)
				{
					temp = P3;
					temp = temp&0X0F;
				}
			}
		}
		//第三列按键
		P3 = 0XDF;P42 = 1;
		temp = P3;
		temp = temp&0X0F;
		if(temp!=0X0F)
		{
			Delay6ms();
			if(temp!=0X0F)
			{
				temp = P3;
				switch(temp)
				{
					case 0XDE: P0=0XFF;break;
					case 0XDD: P0=0X00;break;
					case 0XDB: P0=0XAA;break;
					case 0XD7: P0=0X55;break;
				}
				while(temp!=0X0F)
				{
					temp = P3;
					temp = temp&0X0F;
				}
			}
		}
	//第四列按键
		P3 = 0XEF;
		temp = P3;
		temp = temp&0X0F;
		if(temp!=0X0F)
		{
			Delay6ms();
			if(temp!=0X0F)
			{
				temp = P3;
				switch(temp)
				{
					case 0XEE: P0=0X00;break;
					case 0XED: P0=0XFF;break;
					case 0XEB: P0=0X55;break;
					case 0XE7: P0=0XAA;break;
				}
				while(temp!=0X0F)
				{
					temp = P3;
					temp = temp&0X0F;
				}
			}
		}		
}
void Delay6ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	_nop_();
	i = 65;
	j = 136;
	do
	{
		while (--j);
	} while (--i);
}

 

<think>嗯,用户问的是蓝桥杯竞赛中的双按键问题,需要解题思路和代码实现。首先,我需要回忆一下双按键问题的具体内容。可能是指某种需要同时处理两个按键输入的问题,比如按键状态变化或者组合按键的检测。 用户提到的蓝桥杯竞赛,通常涉及算法和编程,所以双按键问题可能涉及到状态机或者事件处理。比如,当两个按键被按下时,触发某种操作,或者需要记录按键的时间差等等。 接下来,我需要查找相关的资料或者之前的解题经验。根据引用[1],蓝桥杯有Python组,所以可能需要用Python来实现。引用[3]提到了STL和Lambda表达式,但那是C++的内容,不过可能对思路有帮助。 双按键问题可能的场景是:两个按键A和B,按下后会有不同的效果,或者需要同时按下才能触发某个事件。例如,按键A和B在不同时间被按下,需要计算它们的时间差,或者判断是否在特定时间窗口内同时按下。 解题步骤可能包括:记录按键事件的时间戳,然后分析事件序列,找出符合条件的组合。比如,使用字典或列表来存储按键状态和时间,然后遍历这些记录进行判断。 在代码实现方面,可能需要读取输入事件,存储每个按键的按下时间,然后比较两个按键的时间差是否在允许的范围内。例如,按键A和B的按下时间差不超过某个阈值,则视为同时按下,触发相应动作。 测试用例方面,需要考虑多种情况,比如A先按B后按,B先按A后按,或者两者时间差超过阈值的情况。确保代码能正确处理这些边界条件。 优化点可能包括使用更高效的数据结构来存储事件,比如优先队列或者直接维护两个变量记录最近的按键时间,减少空间复杂度。 最后,需要按照用户的要求,用Python编写代码,并确保符合蓝桥杯的编程规范,比如处理输入输出,避免超时等。</think>### 蓝桥杯按键问题解法分析 蓝桥杯竞赛中的双按键问题通常涉及**状态机设计**和**事件时序分析**。这类问题要求处理两个独立按键的输入逻辑,常见场景如“组合按键触发”“时序约束操作”等。以下是分步解析与实现: --- #### 解题思路 1. **问题建模** - 定义按键事件(按下/释放)的时间戳 - 建立状态变量记录按键A/B的当前状态 - 设定触发条件(如同时按下时间差≤阈值) 2. **核心逻辑** ```python events = [] # 存储按键事件(时间戳,按键类型,动作) a_pressed_time = None b_pressed_time = None threshold = 0.5 # 时间差阈值(单位:秒) ``` 3. **算法流程** - 遍历按键事件序列 - 当检测到按键A按下时,记录时间戳 - 当检测到按键B按下时,记录时间戳 - 检查两次按下的时间差是否满足条件 --- #### 代码实现(Python) ```python def dual_key_solution(events): a_press = None b_press = None result = [] for time, key, action in events: if action == 'press': if key == 'A': a_press = time elif key == 'B': b_press = time # 检测是否满足双按键条件 if a_press is not None and b_press is not None: if abs(a_press - b_press) <= 0.5: result.append((max(a_press, b_press), 'trigger')) # 重置状态避免重复触发 a_press = None b_press = None elif action == 'release': # 释放任意键则重置对应状态 if key == 'A': a_press = None elif key == 'B': b_press = None return result ``` --- #### 测试用例示例 ```python # 输入事件格式:(时间戳, 按键类型, 动作) test_events = [ (1.0, 'A', 'press'), (1.2, 'B', 'press'), # 时间差0.2s,应触发 (2.0, 'A', 'release'), (3.0, 'A', 'press'), (3.6, 'B', 'press') # 时间差0.6s,不触发 ] print(dual_key_solution(test_events)) # 输出: [(1.2, 'trigger')] ``` --- #### 优化方向 1. **空间优化**:仅记录最近一次按键的时间戳,而非存储全部事件[^3] 2. **时间复杂度**:使用单次遍历算法($O(n)$) 3. **容错处理**:添加按键抖动过滤(如50ms内状态变化视为噪声) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值