按键功能拓展--单击、双击、长按、组合按等

本文介绍了如何通过轮询方式和定时器检测来拓展无自锁功能的按键,实现单击、双击、长按等操作。通过设置不同的计数器和延时判断,可以区分按键的不同状态,并通过结构体和函数调用来处理按键事件,支持单个按键和组合按键的多种功能。此外,还提供了按键自锁的实现,防止按键多次触发。

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

按键功能拓展--单击、双击、长按等

将无自锁功能的按键通过对其单击,双击,长按等状态,进行分配相应的功能,扩展按键功能,调用相关函数即可。

1.轮询方式

key.c

#include "firmware.h"
#include "key.h"

u8 Key1_Lock_Flag = 0;
u16 Key1_Cnt = 0;//u8 0-255;u16 0-65535
u8 KeyNum = 0;
u8 Key_Short_Flag = 0;
u8 Key1_Cnt2 = 0;
u8 Key1_Times = 0;
u8 Key1_Cnt3 = 0;
u8 Key_Couple_Flag = 0;
u8 Key12_Lock_Flag = 0;
u16 Key12_Cnt = 0;
u8 Key2_Lock_Flag = 0;
u16 Key2_Cnt = 0;

按键单击消抖

void Key_Scan1(void)
{
	if(KEY1 == 1)//按键没有按下
	{
		Key1_Lock_Flag = 0;//清零自锁标志
		Key1_Cnt = 0;//清零计数标志
	}
	else if(Key1_Lock_Flag == 0)
	{
		Key1_Cnt ++;//累计按键消抖延时次数
		if(Key1_Cnt > Key_Delay_Time)
		{
			Key1_Cnt = 0;//清零计数变量
			Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
			KeyNum = 1;//赋键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
		}
	}
}

按键短按与长按

void Key_Scan2(void)
{
	if(KEY1 == 1)//按键没有按下
	{
		Key1_Lock_Flag = 0;//清零自锁标志
		Key1_Cnt = 0;//清零计数标志
		if(Key_Short_Flag == 1)
		{
			Key_Short_Flag = 0;
			KeyNum = 1;//赋短按键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
		}
	}
	else if(Key1_Lock_Flag == 0)
	{
		Key1_Cnt ++;//累计按键消抖延时次数
		if(Key1_Cnt > Key_Delay_Time)
		{
			Key_Short_Flag = 1;//大于消抖时间,有可能是长按也有可能是短按
		}
		if(Key1_Cnt > Key_Long_Time)
		{
			Key_Short_Flag = 0;//进入长按,取消短按标志位
			Key1_Cnt = 0;
			KeyNum = 2;//赋长按键值编码。
			Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
		}
	}
}

按键短按与连按

void Key_Scan3(void)
{
	if(KEY1 == 1)//按键没有按下
	{
		Key1_Lock_Flag = 0;//清零自锁标志
		Key1_Cnt = 0;//清零计数标志
	}
	else if(Key1_Lock_Flag == 0)
	{
		Key1_Cnt ++;//累计按键消抖延时次数
		if(Key1_Cnt > Key_Delay_Time)
		{
			Key1_Cnt = 0;//清零计数变量
			Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
			KeyNum = 1;//赋键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
		}
	}
	else if(Key1_Cnt < Key_Long_Time)//按键持续按下自锁标志为1,不可进入上述步骤
		{
			Key1_Cnt ++;//连按超过一定时限,进入连按
		}
		else
		{
			Key1_Cnt2 ++;//连击时间间隔计数
			if(Key1_Cnt2 > Key_Long_Time2)//每超过连击时间间隔
			{
				Key1_Cnt2 = 0;//连击时间间隔计数器清零
				KeyNum = 1;//与单击相同实现连续单击效果
			}
		}
}

按键单击、双击与连击

void Key_Scan4(void)
{
	if(KEY1 == 1)//按键没有按下
	{
		Key1_Lock_Flag = 0;//清零自锁标志
		Key1_Cnt = 0;//清零计数标志
		if(Key1_Times > 0)
		{
			Key1_Cnt3 ++;//当前距离前一次按下间隔时间
			if(Key1_Cnt3 > Key_Double_Time)//超过双击有效间隔时间
			{
				Key1_Cnt3 = 0;
				Key1_Times = 0;
			}
		}
	}
	else if(Key1_Lock_Flag == 0)
	{
		Key1_Cnt ++;//累计按键消抖延时次数
		if(Key1_Cnt > Key_Delay_Time)
		{
			Key1_Cnt = 0;//清零计数变量
			Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
			Key1_Times ++;//统计按键按下次数
			Key1_Cnt3 = 0;
			if(Key1_Times == 1)
			{
				KeyNum = 1;//按键单击
			}
			else if(Key1_Times == 2)
			{
				KeyNum = 2;//按键双击
			}
			else if(Key1_Times == 3)
			{
				KeyNum = 3;//按键三击
			}
		}
	}
	else if(Key1_Cnt < Key_Long_Time)//按键持续按下自锁标志为1,不可进入上述步骤
		{
			Key1_Cnt ++;//连按超过一定时限,进入连按
		}
		else
		{
			Key1_Cnt2 ++;//连击时间间隔计数
			if(Key1_Cnt2 > Key_Long_Time2)//每超过连击时间间隔
			{
				Key1_Cnt2 = 0;//连击时间间隔计数器清零
				KeyNum = 1;//与单击相同实现连续单击效果
			}
		}
}

组合按键(不区分先后顺序)

void Key_Scan5(void)
{
	if((KEY1 || KEY2) == 1)//按键没有按下
	{
		Key_Couple_Flag = 0;
		Key12_Lock_Flag = 0;//清零自锁标志
		Key12_Cnt = 0;//清零计数标志
	}
	else if(Key12_Lock_Flag == 0)
	{
		Key12_Cnt ++;//累计按键消抖延时次数
		Key_Couple_Flag = 1;//组合按键按下
		if(Key12_Cnt > Key_Delay_Time)
		{
			Key12_Cnt = 0;//清零计数变量
			Key12_Lock_Flag = 1;//自锁标志,防止按键多次触发
			KeyNum = 12;//赋键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
		}
	}
	
	if(KEY1 == 1)//按键没有按下
	{
		Key1_Lock_Flag = 0;//清零自锁标志
		Key1_Cnt = 0;//清零计数标志
	}
	else if((Key1_Lock_Flag == 0) && (Key_Couple_Flag == 0))
	{
		Key1_Cnt ++;//累计按键消抖延时次数
		if(Key1_Cnt > Key_Delay_Time)
		{
			Key1_Cnt = 0;//清零计数变量
			Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
			KeyNum = 1;//赋键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
		}
	}
	
	if(KEY2 == 1)//按键没有按下
	{
		Key2_Lock_Flag = 0;//清零自锁标志
		Key2_Cnt = 0;//清零计数标志
	}
	else if((Key2_Lock_Flag == 0) && (Key_Couple_Flag == 0))
	{
		Key2_Cnt ++;//累计按键消抖延时次数
		if(Key2_Cnt > Key_Delay_Time)
		{
			Key2_Cnt = 0;//清零计数变量
			Key2_Lock_Flag = 1;//自锁标志,防止按键多次触发
			KeyNum = 2;//赋键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
		}
	}
}

组合按键(区分先后顺序)

void Key_Scan6(void)
{	
	if(KEY1 == 1)//按键没有按下
	{
		Key1_Lock_Flag = 0;//清零自锁标志
		Key1_Cnt = 0;//清零计数标志
	}
	else if(Key1_Lock_Flag == 0)
	{
		Key1_Cnt ++;//累计按键消抖延时次数
		if(Key1_Cnt > Key_Delay_Time)
		{
			Key1_Cnt = 0;//清零计数变量
			if(KEY2 == 0)
			{
				Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
				KeyNum = 3;//赋键值编码。
			}
			else
			{
				Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
				KeyNum = 1;//赋键值编码。
			}
		}
	}
	
	if(KEY2 == 1)//按键没有按下
	{
		Key2_Lock_Flag = 0;//清零自锁标志
		Key2_Cnt = 0;//清零计数标志
	}
	else if(Key2_Lock_Flag == 0)
	{
		Key2_Cnt ++;//累计按键消抖延时次数
		if(Key2_Cnt > Key_Delay_Time)
		{
			Key2_Cnt = 0;//清零计数变量
			Key2_Lock_Flag = 1;//自锁标志,防止按键多次触发
			KeyNum = 2;//赋键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
		}
	}
}

key.h

#ifndef __KEY_H
#define __KEY_H

#include "firmware.h"  //IO define
#define Key_Delay_Time  100 //按实际调整
#define Key_Long_Time   500 //长按持续时间
#define Key_Long_Time2  500 //长按每次变化间隔时间
#define Key_Double_Time 200 //双击有效间隔时间

void Key_Scan1(void)
void Key_Scan2(void)
void Key_Scan3(void)
void Key_Scan4(void);
void Key_Scan5(void);
void Key_Scan6(void);

#define KEY1 IN1 //单片机IO
#define KEY2 IN2 //单片机IO
#endif

2.定时器检测

开启定时器中断,将计时时间设置为50ms,即50ms扫描一次按键,实现检测按键是否按下和连按。

struct Key
{
  char KeyStaute;//是否按下
  char Continuous;//是否连按
  int KeyNumberContinuous;//连按统计
};
struct Key key1,key2,key3,key4;//定义结构体变量,代表四个按键

void Key_Scan(struct Key * key,GPIO_TypeDef* GPIO_Port,uint16_t GPIO_Pin)
{
  if(!HAL_GPIO_ReadPin(GPIO_Port,GPIO_Pin))//按键按下被拉低
  {
    if(key->KeyStaute)
    {
      key->KeyContinueNumber++;
      if(key->KeyContinueNumber>20)//长按超过1s
      {
        key->Continuous = 1;
      }
    }
    else
    {
      key->KeyStaute = 1;
    }
  }
  else
  {
    key->KeyStaute = 0;
    key->KeyContinueNumber = 0;
    key->Continuous = 0;
  }
}

按键自锁

u16 z_count = 0;
u8 z_en = 0;
u8 z_flag = 0;
void z_key(void)
{
	if(IN3 == 0)
	{
		z_count ++;
		if(z_count >= 300)//调试更改
		{
			z_count = 300;
		}
	}
	if((IN3 == 1) && (z_count >= 300))
	{
		z_en^=1;//异或,相同为0,不同为1
		z_count = 0;
	}
	if(z_en == 1)
	{
		  OUT11 = 1;//按单次
		  z_flag = 1;
	}
	else if(z_en == 0)
	{   
		  OUT11 = 0;//按双次
		  z_flag = 0;
	}	
}
### 回答1: 基于STM32的TFT触摸屏虚拟按键是一种通过触摸屏实现人机交互的技术。它的实现原理是通过在TFT显示屏上绘制虚拟按键,并使用STM32控制器来处理触摸事件。通过触摸屏上的虚拟按键,用户可以模拟真实按键的操作,实现与系统的交互。 在实现这一技术时,首先需要选取合适的TFT显示屏,并连接到STM32控制器。其次,使用STM32的外设库函数,通过代码绘制虚拟按键的外观,包括按键的形状、颜色和文字等。此外,还需将每个按键与相应的功能逻辑进行关联,以达到按下虚拟按键时执行相应操作的目的。 在用户与触摸屏进行交互时,STM32会实时检测触摸事件,并使用触摸屏的驱动库函数获取触摸点的位置。然后,STM32会根据触摸点的位置和虚拟按键的位置信息判断用户是否触摸到虚拟按键,并执行相应的操作。例如,可以根据按下的按键控制系统的音量、切换页面等。 通过使用基于STM32的TFT触摸屏虚拟按键,可以大大提高产品的人机交互体验。与传统机械按键相比,虚拟按键可以更灵活地设置和定制,且无需额外的硬件,减少了产品成本和体积。此外,虚拟按键还可以根据不同的场景或需求进行修改和更新,提供更丰富的功能和交互方式。 总的来说,基于STM32的TFT触摸屏虚拟按键技术是一种高效、灵活且便捷的人机交互方式,可以广泛应用于各种电子设备和嵌入式系统中。 ### 回答2: 基于STM32的TFT触摸屏虚拟按键是一种通过触摸屏来模拟物理按键功能的技术。该技术利用STM32控制器与TFT触摸屏的硬件接口,实现对触摸屏的触摸输入进行处理和识别,从而模拟按键操作。 在实现该功能时,我们首先需要连接STM32与TFT触摸屏的硬件接口,确保它们之间正常通信。然后,通过编程控制,将触摸屏的输入信号转化为相应的按键操作。具体的实现步骤如下: 1. 初始化触摸屏和STM32的硬件接口,包括引脚配置、中断设置等。 2. 在程序中创建虚拟按键的图形界面,可以使用图形库或者自定义绘图函数进行创建。 3. 在主循环中,不断读取触摸屏的输入信号。如果检测到触摸屏被按下,即触摸坐标有效,我们可以根据触摸坐标判断用户点击到了哪个虚拟按键。 4. 对于每个虚拟按键,我们可以定义相应的按键事件处理函数。例如,当用户点击到某个按键时,可以触发相应的代码逻辑或者执行特定的功能。 5. 同时,为了避免误触或按等问题,我们可以通过设置按压时间、滑动距离等参数,来判断用户的操作是单击双击按还是滑动等不同的手势。 通过上述步骤,我们可以实现基于STM32的TFT触摸屏虚拟按键功能。这种技术可以广泛应用于各种电子产品中,如智能家居、工业控制、医疗设备等领域,为用户提供更加便捷的操作体验。 ### 回答3: 基于STM32的TFT触摸屏虚拟按键是一种通过触摸屏来模拟物理按键的技术。它利用STM32控制器的强大功能和TFT触摸屏的精准触控能力,实现了在屏幕上显示虚拟按键,并通过触摸屏来模拟按下按键的操作。 在实现这一技术时,首先需要借助STM32进行屏幕显示的控制STM32可以通过TFT接口来控制TFT显示屏,将屏幕上的各种元素(包括虚拟按键)显示出来。 其次,需要利用STM32的触摸功能来实现按键的触摸检测。通过对触摸屏的坐标进行采样和分析,可以判断用户是否触摸到了虚拟按键的位置。一旦触摸检测到按键的触摸信号,就可以执行相应的按键操作,比如发送一个脉冲信号、改变某个状态等等。 为了提高用户体验,可以在虚拟按键的设计中考虑一些小技巧。比如,可以对按键进行设计,使其在被按下时有一定的反馈效果,比如改变颜色、显示按下动画等等。这样可以增强用户对按键操作的感知,提高整体的交互体验。 基于STM32的TFT触摸屏虚拟按键可以广泛应用于各种嵌入式系统中,特别是那些无需物理按键操作的场景。比如,可以用于家电控制面板、智能家居系统、工业控制设备等等。它可以减少物理按键的使用,提高系统的可靠性和稳定性,并且可以根据具体需求随时更换按键的布局和功能。这样的技术大大拓展了嵌入式系统的交互方式,提升了用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值