按键的单击、双击、连续按、短按和长按实现思路

news2025/1/18 19:07:56

概念区分

看到好多教程说了这些概念,有的说单击就是短按,连续按就是长按等等。

其实,仔细想想,这几个概念是有一些区别的。

假如一个按键,没按下时是高电平,按下时是低电平,以此来理解这些概念。

单击:按键按下后,第一次检测到低电平,则触发动作,之后即使按键还处于低电平状态,也不会触发动作。

双击:必须连续按下两次,才会触发相应的动作。

连续按:只要按键一直被按下,即一直处于低电平状态,则会根据调用间隔不停地触发动作。

短按:按键按下后不会立即触发动作,而是会经过一小段时间,才会触发动作。

长按:按键按下后不会立即触发动作,而是会经过一长段时间,才会触发动作。

注意区分以上五种功能,以下记录实现思路。

补充注意:在配置外部中断时,有个上升沿触发或者下降沿触发,这里指的是,下降沿发生时触发了中断,但是判断按键是否处于按下状态,依然是判断低电平。

连续按

连续按相对简单,所以先讲这个。

按下去之后,就会一直有效,具体有效的间隔时长,可以自行设定,比如快点的话,就1秒钟检测60次,慢点的话,就1秒钟检测十几二十次差不多,再慢点,就一秒钟检测一两次也行,具体根据需要来。但是间隔一定不能超过人能反应过来的时间。

只要固定间隔比如100ms检测一次电平,如果是有效电平,就触发动作即可。

对应的按键扫描思路如下:

这个代码可以写在硬件层,然后业务层调用后判断即可。

比如,业务层每隔100ms调用一次该函数,每次都返回的是1,说明一直处于按下状态,然后就执行相应的动作即可。

想想键盘按键被卡住。

单击

单击则是在连续按的基础上,做一些限制,如果之前已经按下过,那么之后即使还处于按下状态,也不会触发动作。

因此,需要加一个变量,来记录按键是否已经被按下过。

不支持连续按的实现,有一个关键点,就是这一次的判断和上一次的按键状态有关,怎么理解呢?如果上一次是高电平,这一次检测是低电平,那么就会因为是第一次触发,所以会被视为有效。但是如果这次检测到的是低电平,但是其上一次检测的也是低电平,那么,就表示是发生了连续按,此时,需要阻止其触发动作。

所以,扫描按键在判断时,不能只判断这一次是否处于按下状态,还要结合上一次的按键的状态。

对应的按键扫描思路如下:

这段代码的最后应该还有个return 0;

注意,这里的是否已经被按下标志key_up需要定义为static变量,是为了让其只在第一次调用时被初始化。

这里的代码理解就是,只有之前没被按下并且这次被按下才能生效,如果没有被按下,或者之前已经被按下这次还是按下,都不会生效。

上面的方式,轮询和外部中断中都适用。

如果是外部中断,还有另外的实现思路

就是下降沿触发进入中断后,给一个全局的状态标志,只要触发进入了中断,则状态标志置位,触发功能之后,状态标志再复位。

再简单点,直接将操作逻辑放在中断里,这样,按下一次就只会触发一次,后续即使还是按下的状态,也不会重复执行。

有时,为了不在中断里放过多的业务逻辑,保证中断的快进快出,就可以只在中断里判断标志位,然后在其他地方(比如按键的专用c文件中)根据标志位执行相应的动作。

其实,就算在中断里,也还是可以根据低电平来判断是不是处于按下状态,从而实现单击或者连续按。

这里算是提供基于边沿触发的外部中断下的一种思路吧。

双击

短按和长按

短按和长按其实都是同一种思路,区别就是延时触发的延迟时间长短不同。

所以,这里的关键就是,如何合理地检测低电平持续的时间

短按,其实可以理解为单击,就是按下之后要很快松开,因为时间长了会被判定为长按。

一开始,我的想法是,检测是否有低电平发生,如果有,就再延时一段时间比如5s,之后再次判断是否还是低电平,如果是,则表示发生了长按。可是,一细想,又发现这个思路有BUG,如果我先按下按键,然后松开,等到快5秒的时候再按下,这样,也会两次都检测到低电平,但实际并不是长按。

我又想,那么在5秒内,一直判断是不是低电平不就行了,所以,需要造一个5秒的for循环,在里面一直判断是不是低电平,只要有一个高电平发生,就不能判定为长按,而是被判定为短按。

static void KEY_Detect() 
{
	uint8_t i = 0;
	
	if(KEY1.KEY_Flag == TRUE)//先判断有按键按下
	{
		KEY1.Click = FALSE;
		KEY1.Press = TRUE;
		//触摸按键长按检测
		for(i=0;i<500;i++)
		{
			HAL_Delay(10);
			//如果5s内,按键状态出现高电平,此时按键为短按,跳出循环
			if(检测到高电平)
			{
				KEY1.Click = TRUE;
				KEY1.Press = FALSE;
				break; //跳出for循环
			}
		}
		
		if(是短按)
		{
			//短按对应的动作
		}
		
		if(是长按)
		{
			//长按对应的动作
		}
		
		//清除按键状态
		KEY1.KEY_Flag = FALSE;
		KEY1.Click = FALSE;
		KEY1.Press = FALSE;
	}
}

这种思路是可行的,但是根据for循环来实现按键时长,并不精准。

如果想要更精准的时间判断,怎么办呢?

最好是结合定时器。

定时器的思路其实和上述for循环是一样的。

也是每隔10ms判断一次按键状态,只是定时器方式是将这个判断放到定时器中了。

可以让其在10ms定时器里进入判断500次,只要没有高电平出现,就置位长按标志,否则置位短按标志。

之后再根据这个标志去执行相应动作即可。

又或者在定时器里面判断低电平来计数,只要计数大于等于500,就可以执行相应动作。

比如:

static int cnt=0;
if(GPIOB_ReadPortPin(GPIO_Pin_22)==0)
{
    cnt++;
    if(cnt>500)
    {
        PRINT("long press\n");
        ……
        cnt =0;
    }
……
}

注意,编程时,不一定非要根据某种动作来执行另一种动作,可以先根据一种动作来设置一些相应的标志位,然后在其他地方根据标志位再进行一些动作,这样更加灵活。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/576153.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JVM—Class类文件结构详解

Class类文件的结构 要了解Class文件的结构首先得了解Class文件所采用的数据类型&#xff1a; Class文件格式采用一种类似C语言结构体的伪结构来存储数据&#xff0c;这种伪结构只有两种数据结构&#xff0c;即无符号数和表&#xff0c;解析Class文件全是以这两个数据结构为基础…

【数据结构】什么是堆,如何使用无序数组生成一个堆?

文章目录 一、堆的概念及其介绍二、如何使用无序序列构建一个堆&#xff1f;三、C语言实现堆的基本操作结构体创建与销毁获取堆顶数据与个数及堆的判空堆的插入与删除 源代码分享 一、堆的概念及其介绍 堆(Heap)是计算机科学中一类特殊的数据结构的统称&#xff0c;堆通常是一…

LEETCODE 每日一题 1093.大样本统计

题目描述 前往leetcode1093题 我们对 0 到 255 之间的整数进行采样&#xff0c;并将结果存储在数组 count 中&#xff1a;count[k] 就是整数 k 在样本中出现的次数。 计算以下统计数据: minimum &#xff1a;样本中的最小元素。 maximum &#xff1a;样品中的最大元素。 mean &…

【Log】About these two years

文章目录 第一篇博客&#xff1f;成长收获的季节Future 第一篇博客&#xff1f; 第一次在CSDN发布博客&#xff0c;是当初我学习嵌入式的时候&#xff0c;那个时候我们做了一个大创&#xff0c;其中使用到了激光雷达&#xff0c;然后我就负责激光雷达部分代码的编写和设计&…

AI-新手玩转RKNN

关于RKNN RKNN 是Rockchip npu 平台使用的模型类型&#xff0c;以.rknn后缀结尾的模型文件。Rockchip 提供了完整了模型转换 Python 工具&#xff0c;方便用户将自主研发的算法模型转换成 RKNN 模型&#xff0c;同时 Rockchip 也提供了C/C和Python API 接口。 #mermaid-svg-M7l…

电子器件系列37:SD卡座(Push-Push和Push-Pull)

SD卡座是目前最通用的数据存储卡座、记忆卡座。在各种通讯数码产品、安防产品、带储存类产品等设备上都有所应用。有着性价比高、存储容量大、使用便捷、通用性以及安全性强等特点。自弹式SD卡座的卡槽底部会设有一个小直径、小线径的弹簧或一种切口式弹片。当装入SD卡时&#…

Kafka如何保证数据高可靠

这节课给大家分享一下Kafka的数据高可靠。为什么要讲这个&#xff1f;因为Kafka它本身不是一个金融级别数据可靠的分布式消息系统。 虽然说它存储到某个topic里的数据会先拆分多个partition&#xff0c;这体现了分治的一个思想。每一个partition在最终存储的时候会保存多个副本…

117.【微信小程序】

微信小程序 (一)、微信小程序概括1.微信小程序简介(1).小程序与普通网页开发的区别 2.注册微信小程序账号(1).注册小程序账号(2).获取小程序的AppID 3.安装微信开发者工具(1).微信开发者工具的简介:(2).微信开发者工具的下载 4.创建第一个小程序(1).创建小程序步骤(2).开发者工…

域横向移动-传递攻击atschtasks

横向移动就是拿下对方一台主机后&#xff0c;以拿下的那台主机作为跳板&#xff0c;对内网的其他主机再进行后渗透&#xff0c;拿到其他内网主机的权限的过程。叫做横向移动。横向移动的主要目的就是扩大战果。 传递攻击主要建立在明文和hash值获取基础上进行攻击。 at和scht…

Typora改变字体颜色

方法一&#xff1a;下载AutoHotkey并创建快捷键的方法&#xff08;推荐&#xff09; 第一步&#xff1a;在官网&#xff08;https://www.autohotkey.com/&#xff09;下载 AutoHotkey并傻瓜式安装&#xff0c;安装在任意盘符下均可&#xff1b; 第二步&#xff1a;在安装目录…

STM32F4_I2C(从机EEPROM/MPU-6050)协议详解

目录 1. I2C是什么 2. I2C物理层介绍 3. I2C协议层介绍 3.1 I2C基本读写过程 3.1.1 通讯复合格式 3.2 通讯的起始和停止信号 3.3 数据有效性 3.4 地址及数据方向 3.5 响应 4. STM32的I2C特性及架构 4.1 I2C架构剖析 5. I2C通讯过程 5.1 主发送器 5.2 主接收器 6…

Windows文件自动备份——“使用文件历史记录进行备份”

一、背景 因为有一些重要的文件需要经常改动&#xff0c;同时也有“找到某文件某历史版本”的需求&#xff0c;但考虑到时常手动备份比较麻烦&#xff0c;就想到了使用Windows自带的文件备份功能——“使用文件历史记录进行备份”来帮助进行文件的备份和版本管理。 二、环境 1…

一个测试开发人员在字节的7年,太真实了...

测试这条路是坎坷的&#xff0c;我自己深有体会。 我们的起点低&#xff0c;基础差。 测试这个职位也很尴尬&#xff0c;很少有公司会有针对性的对测试人员做成长规划&#xff0c;也很少有公司会那么重视测试人员&#xff0c; 也许进了像 BATJ 这样的大厂会好一点。 但是大多数…

nacos2.2.1搭建

springboot 3.0集成nacos2.2.1内容可评论区Q我 搭建环境&#xff1a; Java版本&#xff1a;11.0.18 系统&#xff1a;window7 数据库&#xff1a;mysql8.0.29 第一步&#xff0c;下载nacos&#xff0c;下载地址&#xff1a; https://github.com/alibaba/nacos/releases/d…

HACKABLE: III实战演练

文章目录 HACKABLE: III实战演练一、前期准备1、相关信息 二、信息收集1、端口扫描2、访问网站3、查看网站源码4、扫描目录5、访问网址6、查看并下载7、访问网站8、查看文件9、解密10、访问网站11、访问网站12、查看文件13、解密14、访问网站15、访问网站16、下载图片17、隐写1…

CrossOver软件好用吗?最新版22.1.1有哪些优势功能

CrossOver2023是一款系统兼容软件 让您可以在Mac和Linux系统上运行Win应用&#xff0c;不必重启系统&#xff0c;不必使用虚拟机。通过CrossOver&#xff0c; 您可以从dock直接启动Wind应用&#xff0c;与您的Mac和Linux系统功能无缝集成。crossover兼容软件是可以在苹果电脑中…

oracle的基本使用(建表,操作表等)

一、表空间&#xff0c;用户 1、创建表空间 使用system登录 创建表空间 waterboss 为表空间名称datafile 用于设置物理文件名称size 用于设置表空间的初始大小autoextend on 用于设置自动增长&#xff0c;如果存储量超过初始大小&#xff0c;则开始自动扩容next 用于设置每次…

tiechui_lesson14_网络连接请求的拦截

这一节主要学习网络请求的过滤&#xff0c;铁锤大佬讲了些关于IRP的知识。 笔记 先祭出一张灵魂作画&#xff0c;这是用来描述IRP的流转形式的。 通过这幅图着重解释了一下IoSkipCurrentIrpStackLocation(pirp);的过程&#xff0c;就是在流转到当前的IRP请求之后&#xff0c…

Jarvis OJ pwn——level1

checksec&& 运行 ida main函数里的vulnerable_function函数存在溢出 给输入分配的栈空间为0x88 利用思路 ret2shellcode 代码 Author : 白银 Date : 2023-05-27 14:43:28 LastEditors : 白银 LastEditTime : 2023-05-27 16:52:19 FilePath : /pw…

五十行代码教你写一个简单的内存池(二级指针的应用)

固定大小内存的内存池实现 该内存池是一个很简单的内存池&#xff0c;只能申请固定大小的内存&#xff0c;仅供学习 要点&#xff1a; 构造隐式链表二级指针 存储结构 typedef struct mempool_s{int block_size; // 每一块的大虚哎int free_count; // 剩余有多少块是可以…