免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

按键状态机设计指南:从消抖原理到单击、双击、长按的事件识别

按键状态机设计指南:从消抖原理到单击、双击、长按的事件识别 1. 为什么简单的延时消抖方案搞不定按键检测做嵌入式开发或者上位机工具的时候按键处理看起来是最不起眼的环节但真正把单击、双击、长按放在一起做的时候很多人会翻车。我在实际项目里见过不少同事一开始图省事按下延时20ms消抖松开再延时20ms消抖然后根据按下持续时间判断是单击还是长按结果调试的时候发现双击永远触发不了或者单击偶尔会被识别成长按。先说一个最基本的认知机械按键按下和释放的瞬间簧片会因为物理接触产生连续的通断抖动持续时间通常在5ms到20ms左右。这个抖动如果不处理一次物理按下在MCU看来可能是几十次电平跳变。最原始的做法是检测到电平变化后延时20ms再读一次确认电平稳定后认为按键生效。这种延时消抖方案在只有单击需求的场景下确实够用但是一旦涉及双击和长按的组合判断问题就暴露了延时期间程序是阻塞的无法同时采集后续的按键动作。比如用户在200ms内快速按了两下第一次按下还在消抖延时里第二次按下已经发生了等延时结束之后读到的状态可能刚好是第二次按下的中间状态整个判定就乱套了。这里有一个容易被忽略的工程细节抖动不仅仅发生在按下瞬间释放瞬间同样有抖动而且释放抖动往往被很多人漏掉。只处理按下消抖不处理释放消抖会导致按键释放边沿的判定不稳定进而影响长按计时结束的准确性。我自己在调试中踩过这个坑用示波器看过按键波形之后才发现释放抖动甚至比按下抖动更严重尤其是用了一段时间的按键簧片氧化之后释放波形能拖到30ms以上。所以核心结论是先想清楚再做按键检测的本质不是“消除抖动”而是“识别稳定状态”。你要的不是一个电平值而是一个有意义的输入事件。从这个角度出发状态机架构是处理多事件按键检测的自然选择它天然解决了抖动过滤、事件识别、非阻塞这三个互相纠缠的问题。2. 按键状态机的核心思想与基础框架2.1 状态机为什么适合按键检测按键检测的本质是处理“输入信号的时序变化”。机械按键的信号在时间轴上是这样演变的未按下时的稳定高电平按下过程中的抖动区间按下后的稳定低电平释放过程中的抖动区间释放后的稳定高电平。这个过程天然是一个有限状态序列每个状态之间的迁移条件是明确的因此非常适合用有限状态机建模。状态机的核心收益在于它把按键检测从“基于时间延时的阻塞逻辑”改成了“基于状态迁移的事件逻辑”。你不需要在检测到电平变化之后傻等20ms而是每次扫描周期读一次电平根据当前状态和新的电平值决定迁移到哪个状态。扫描周期可以做到5ms到10ms一次整个过程非阻塞MCU可以在扫描间隙处理其他任务。我用生活化的类比解释一下延时消抖就像你听到有人敲门先等20秒再开门确认门外真的有人才应答——这20秒里如果有人连续敲了三次你都会当成一次。状态机消抖就像你收到信号后在极短时间内持续观察只有当信号稳定下来才决定是否响应这期间所有新的敲门声都会被纳入同一个事件的判断周期。对于双击检测来说状态机方案能精确地感知“两次敲门的间隔”而延时方案可能在第一次延时还没结束时就错过了第二次敲门。2.2 基础状态定义一个完整的按键状态机至少需要定义以下状态IDLE空闲态没有检测到任何按下动作输出高电平假设低有效。PRESS_DETECTED按下检测态检测到第一次电平跳变但尚未确认是真实按下还是抖动。PRESS_CONFIRMED按下确认态消抖确认后的稳定按下状态长按计时从此状态开始。RELEASE_DETECTED释放检测态检测到释放动作的边沿但尚未确认释放是否稳定。RELEASE_CONFIRMED释放确认态确认释放后的空闲状态回到IDLE。在确认按下和确认释放的状态中还可以根据具体需求加入计时器字段用于长按判定和双击间隔判定。这里要特别说明一个设计思路状态的迁移条件设计得越保守消抖效果越好但事件响应越迟钝设计得越激进响应越快但误触率越高。工程上要在这两者之间找平衡点而不是一味追求某一个极端。2.3 消抖机制的实现在状态机的框架下消抖不再是一个“延时等待”的动作而是“连续N次扫描电平一致才确认状态迁移”的计数逻辑。以10ms扫描周期为例按下消抖可以设计为连续3次30ms读到低电平才认为进入稳定按下状态释放消抖同样连续3次读到高电平才确认释放。这样做的效果是抖动期间的电平翻转会被状态机的“连续采样不满足条件”自然过滤掉不会导致状态来回跳变。这种计数消抖方式和传统延时消抖的另一个区别在于延时消抖是一次性读取如果抖动恰好发生在延时结束的那个点就会误判计数消抖是持续采样抖动的任何异常翻转都可能导致计数清零重新累积因此抗干扰能力更强。我实测过一组对比数据使用20ms固定延时方案在按键老化抖动达到30ms的场景下误判率明显上升使用连续3次10ms扫描的计数方案同样的按键始终能稳定识别。这里需要提醒一下计数消抖的累计策略很关键。有些实现是连续N次都相同才迁移只要有一次不同就清零重新计数有些实现允许中间偶尔跳变但整体趋势一致就迁移。前者更严格但可能把正常的慢速按下当成抖动过滤掉后者更宽容但抗干扰能力弱。我的建议是按键扫描场景用严格模式因为机械按键一旦真正按下稳定电平是确定的不需要宽容累计。3. 单击、双击、长按三种事件的检测逻辑拆解3.1 单击检测与判定时间窗口单击的定义是检测到一次完整的按下→释放过程并且这次按下持续时间不超过长按阈值且在这段时间内没有第二次按下发生。这个定义拆开来看有两个关键参数长按阈值和单击判定窗口。长按阈值一般设定为500ms到1000ms之间具体取决于应用场景。比如数字键盘的数字输入长按阈值可以设置得短一些方便快速触发长按的快捷功能如果是用于翻页或者音量调节长按阈值适当延长避免误触。单击判定窗口则是指从释放开始计时等待下一次按下的时间上限一般取200ms到400ms。这个窗口的作用是区分“单击”和“双击”的第一下释放后如果在窗口期内没有新的按下就判定为单击立即触发单击事件如果在窗口期内检测到新的按下则取消单击事件进入双击判定流程。这里涉及到一个重要的设计抉择单击事件是在释放后立刻触发还是等判定窗口结束后触发有些实现为了响应速度在释放确认后立即触发单击事件如果后续检测到双击再发一个“取消单击”的补偿事件。这种方式响应快但逻辑复杂上位机应用里很容易出现UI闪动——单击已经触发了操作双击事件又来了界面状态来回切换。另一种实现是延迟到判定窗口结束才触发单击事件牺牲约200ms的响应延迟换来的是事件逻辑的清晰可靠。我个人建议在大多数场景采用后者除非你的应用对响应延迟极其敏感否则200ms的延迟用户基本感知不到而且能避免一大堆边界问题。单击检测的完整状态流转是这样的IDLE状态检测到按下边沿→进入按下检测态→连续采样确认稳定按下一进入按下确认态→持续检测释放边沿→检测到释放边沿进入释放检测态→连续采样确认释放→进入释放确认态→启动单击判定窗口计时→窗口期内没有新的按下→触发单击事件→回到IDLE。3.2 双击检测时间窗口的嵌套与边界双击检测的逻辑本质上是在单击判定窗口内再嵌套一个按下检测流程。用户在第一次释放后的200ms到400ms内再次按下并释放就判定为双击。实现上需要重点处理的是第一下释放后不能立刻回到IDLE而是进入一个DOUBLE_CLICK_WAIT双击等待态在这个状态下继续扫描按键输入如果在窗口期超时前检测到第二次按下边沿就进入第二次按下的消抖确认流程确认按下后再确认释放整个流程完成则触发双击事件。我实际操作中遇到的典型问题是双击第二下按下消抖完成的时候第一下的判定窗口可能刚好到期。也就是说第一下释放后处于等待状态第二下按下消抖花了30ms按下确认后如果直接判定双击恰好卡在窗口期的尾巴上时序非常紧张。解决方案有两种一是在第二次按下消抖确认完成的瞬间不需要等第二次释放就可以预判为双击只要后续确认释放即可触发双击事件二是把双击等待窗口设置得比“两次按键之间的间隔”稍宽比如用户正常双击的间隔是150ms那窗口就设250ms到300ms留出足够的余量。前一种方案逻辑上更严谨后一种实现上更简单。我在实际项目中用的是前一种方案虽然状态多了一个“双击确认态”但时序判断的准确性明显更好。还有一个容易踩的坑双击事件和单击事件是互斥的。如果第一下释放后等待窗口内检测到第二下按下那么第一下释放时如果已经触发了单击事件必须在第二次按下确认时取消之前发出的单击事件。这个逻辑如果不用状态机而用简单的定时器加标志位实现很容易出现事件重复触发的bug。状态机方案的优势就在这里——单击事件只在DOUBLE_CLICK_WAIT超时后触发一旦进入第二次按下流程单击事件自然就不会触发从结构上消除了互斥逻辑漏洞。3.3 长按检测与连发机制长按检测的核心是在PRESS_CONFIRMED状态下启动一个计时器当计时时长超过长按阈值后进入LONG_PRESS_ACTIVE状态并触发一次长按事件。长按事件触发之后根据应用需求可以有两种处理方式一种是只触发一次释放时结束另一种是支持连发repeat即长按期间每隔一定时间连续触发事件比如键盘的持续删除功能。长按检测里容易被忽略的关键点在于如何区分一个“长按”和“单击的慢速释放”。有些按键在按下后保持稳定状态2秒才释放如果长按阈值是500ms那这个操作确实应该被判定为长按。但如果用户只是按住不放超过阈值但本意不想触发长按比如在思考过程中无意识地按住了一个键这就涉及到底层交互设计的取舍。在大多数场景下长按一旦触发就无法撤销所以长按阈值要设置得保守一些宁可慢一点也不能频繁误触。长按触发后后续的状态流转有两种分支第一种是用户在长按触发后立即释放则触发长按结束事件回到IDLE第二种是用户在长按触发后继续保持按下则根据连发周期重复触发连发事件直到检测到释放边沿。这里还有一个细节长按状态下的释放消抖同样要做因为长按过程中的释放抖动会导致状态机提前退出长按状态造成长按时间被截短。我在一些项目中还会加入“长按穿透”处理长按事件触发后如果用户在保持按下的同时系统产生了其他事件比如触摸滑动需要定义清楚按键事件是否继续占用资源。对于纯按键扫描的应用这个需求不常见但如果做的是按键矩阵加触摸屏的混合输入设备就需要在状态设计中预留这类处理的接口。4. 从理论到代码一套可直接落地的状态机实现4.1 数据结构与状态定义具体实现时我习惯用枚举定义状态用结构体保存按键实例的参数方便一个状态机同时管理多个按键。下面这套代码在C语言环境下可以直接编译运行移植到不同平台时只需要替换底层电平读取函数。typedef enum { KEY_STATE_IDLE 0, KEY_STATE_PRESS_DETECTED, KEY_STATE_PRESS_CONFIRMED, KEY_STATE_RELEASE_DETECTED, KEY_STATE_RELEASE_CONFIRMED, KEY_STATE_DOUBLE_CLICK_WAIT, KEY_STATE_LONG_PRESS_ACTIVE } key_state_t; typedef struct { uint8_t pin_id; uint8_t active_level; key_state_t state; uint8_t debounce_cnt; uint8_t debounce_threshold; uint16_t press_timer; uint16_t long_press_threshold; uint16_t double_click_timer; uint16_t double_click_window; uint8_t event_flags; } key_t;结构体里每个字段都有明确用途debounce_cnt用于消抖计数press_timer记录按下持续时长double_click_timer记录双击等待窗口剩余时间event_flags用于标记当前需要上报的事件。这些参数在初始化时赋值不同按键实例可以拥有不同的消抖阈值和长按阈值灵活性很高。4.2 核心状态迁移函数状态机的主扫描函数通常放在定时器中断或者主循环的周期任务中调用扫描周期一般取5ms到10ms。每次调用扫描一次所有按键读取电平后根据当前状态执行迁移逻辑。void key_scan(key_t *key, uint8_t level) { uint8_t active (level key-active_level) ? 1 : 0; switch (key-state) { case KEY_STATE_IDLE: if (active) { key-debounce_cnt 1; key-state KEY_STATE_PRESS_DETECTED; } break; case KEY_STATE_PRESS_DETECTED: if (active) { if (key-debounce_cnt key-debounce_threshold) { key-state KEY_STATE_PRESS_CONFIRMED; key-debounce_cnt 0; key-press_timer 0; } } else { key-debounce_cnt 0; key-state KEY_STATE_IDLE; } break; case KEY_STATE_PRESS_CONFIRMED: key-press_timer; if (key-press_timer key-long_press_threshold) { key-state KEY_STATE_LONG_PRESS_ACTIVE; key-event_flags | KEY_EVENT_LONG_PRESS; } if (!active) { key-debounce_cnt 1; key-state KEY_STATE_RELEASE_DETECTED; } break; case KEY_STATE_RELEASE_DETECTED: if (!active) { if (key-debounce_cnt key-debounce_threshold) { key-state KEY_STATE_RELEASE_CONFIRMED; key-debounce_cnt 0; key-double_click_timer 0; key-state KEY_STATE_DOUBLE_CLICK_WAIT; } } else { key-debounce_cnt 0; key-state KEY_STATE_PRESS_CONFIRMED; } break; case KEY_STATE_DOUBLE_CLICK_WAIT: key-double_click_timer; if (active) { key-debounce_cnt 1; key-state KEY_STATE_PRESS_DETECTED; } else if (key-double_click_timer key-double_click_window) { key-event_flags | KEY_EVENT_SINGLE_CLICK; key-state KEY_STATE_IDLE; } break; case KEY_STATE_LONG_PRESS_ACTIVE: if (!active) { key-debounce_cnt 1; key-state KEY_STATE_RELEASE_DETECTED; } break; } }上面的代码逻辑是简化版本的框架重点展示了状态迁移的基本骨架。实际项目中还有一些细节需要处理RELEASE_DETECTED到DOUBLE_CLICK_WAIT的跳转过程我合并成了一个赋值动作正常实现建议拆成两个状态释放确认和双击等待分别处理LONG_PRESS_ACTIVE状态下如果还想要连发机制需要额外加一个连发周期计数器。4.3 事件上报与判定窗口的时序配合状态机扫描函数只负责更新内部状态和设置event_flags不直接处理业务逻辑。事件的上报通常在主循环或者事件分发器中统一处理检查每个按键的event_flags如果有事件标志清除标志并调用对应的业务回调函数。这种设计可以确保按键检测模块和业务逻辑完全解耦后续如果要换UI框架或者修改交互逻辑只需要改回调函数的内容状态机部分完全不用动。在实际测试中我发现单击事件因为要等待双击窗口超时才触发在时序上会比按下释放晚约200ms到400ms。如果你做的应用是游戏手柄这类对按键响应延迟极度敏感的场景建议把单击事件的触发方式改为“按下时预触发、双击时撤销”的模式虽然逻辑复杂了一些但能显著降低操作延迟感。如果是普通的菜单导航、工业控制面板延迟触发完全没问题。void key_process_event(key_t *key) { if (key-event_flags KEY_EVENT_SINGLE_CLICK) { key-event_flags ~KEY_EVENT_SINGLE_CLICK; on_single_click(key-pin_id); } if (key-event_flags KEY_EVENT_DOUBLE_CLICK) { key-event_flags ~KEY_EVENT_DOUBLE_CLICK; on_double_click(key-pin_id); } if (key-event_flags KEY_EVENT_LONG_PRESS) { key-event_flags ~KEY_EVENT_LONG_PRESS; on_long_press(key-pin_id); } }4.4 状态机方案的内存与算力开销评估对于资源受限的MCU来说一套完整的状态机实现需要多少资源是一个很实际的问题。以8位MCU比如STM8或者AVR为例每个按键实例的结构体大约占用10到14字节的RAM。如果设备有16个按键总共约200字节不到的RAM这个开销完全可以接受。算力方面每个扫描周期内每个按键的代码路径都是常数级别的不需要循环搜索10ms扫描周期内处理几十个按键毫无压力。相比传统的延时消抖方案状态机方案在RAM开销上多了每个按键几个字节的状态计数器和计时器字段但赢来的是非阻塞、可扩展、多事件支持的能力。对于RAM极其紧张的场合还可以把按键数量多的场景拆成组分时扫描每组共享一套数据结构进一步降低资源占用。5. 边界条件与疑难杂症排查5.1 抖动参数的血泪教训参数设定是按键状态机里最容易出问题的地方。我在一个量产项目中遇到过这样的情况按键在实验室测试完全正常结果客户现场使用后反馈说经常出现一次按下触发两次单击的现象。排查了很久最后发现是现场环境温度偏高按键簧片的弹跳特性发生了变化释放抖动时间比实验室环境下长了将近一倍。我们原本的释放消抖阈值是3次扫描实际现场的释放抖动有时候能持续到6次扫描以上导致释放边沿被反复确认触发了多次单击事件。这个案例给我的教训很深刻消抖阈值的设定不能只参考按键规格书上的标称值一定要实测而且要预留充足的冗余量。建议的做法是取按键规格书中最大抖动时间的2到3倍作为消抖阈值对应的总时间。比如标称最大抖动是15ms扫描周期是10ms那么消抖阈值取3到5次扫描比较稳妥。5.2 双击检测中的反人类设计双击检测有个天然的矛盾点判定窗口越长双击识别率越高但单击响应越慢。窗口过短则用户双击稍微慢一点就识别成两次单击。这里要做实际用户测试来获取合理的参数。以我的经验双击窗口设置在250ms到300ms是比较稳妥的区间。超过350ms之后用户会明显感觉到单击操作“迟滞”低于200ms则对用户的点击速度要求过高很多普通人做不到在200ms内完成两次点击。我做过一组简单的用户测试让10个人分别用100ms、150ms、200ms、250ms、300ms、350ms的间隔进行双击操作观察状态机的识别率。结果显示大部分人的自然双击间隔集中在120ms到280ms之间少数人习惯较慢的操作间隔能到300ms以上。因此我的建议是窗口下限取250ms上限不超过350ms如果产品目标用户是老年人或者操作习惯较慢的人群窗口应适当放宽。5.3 多按键组合与矩阵扫描的注意事项当按键数量增多尤其是使用矩阵扫描方式时状态机的设计需要额外考虑“伪按键”问题。矩阵扫描中存在按键冲突Ghost Key和按键粘连Stuck Key的情况。状态机方案因为每个按键都有独立的状态实例在逻辑上可以天然规避一部分问题但底层扫描的有效性必须保证——如果矩阵扫描本身在同一时刻只能检测到部分按键那么状态机扫描周期就不是恒定的计时器就会产生偏差。解决这个问题的一种方案是在扫描周期不稳定的场景下不使用简单的计数器累加来计算时间而是记录上一次扫描的真实时间戳用当前时间减去时间戳得到真实间隔再将时间累加到计时器中。这种方式在多任务抢占严重的嵌入式环境中特别有用能保证长按和双击的时长判定不受调度延迟影响。5.4 一种隐蔽的状态丢失问题我在调试中遇到过一个隐蔽的bug按键在极短的时间内按下并释放整个事件过程的持续时间比消抖阈值总时间还短。这种情况下状态机在PRESS_DETECTED状态时可能还没来得及累计足够的消抖计数就检测到了释放边沿于是状态直接回到IDLE整个按键事件就完全丢失了。物理上一个快速的“点射”操作人眼和手完全感知不到但的确发生过按键动作。解决这个问题的思路是如果检测到按下检测态中提前出现了释放边沿不要直接丢弃事件而是保留一个“短按疑似”标志等释放确认完成后再触发一个单击事件。虽然这种极短按键在正常使用中很少见但在高速连点测试、自动化测试脚本中可能会暴露出来处理不好会被测试团队当成bug提上来。这也是状态机设计需要覆盖的“短脉冲”边界情况。6. 基于状态机的进阶扩展编码器、摇杆与触摸按键的复用思路6.1 从按键到旋转编码器的移植状态机的设计思路完全不局限于机械按键。旋转编码器Rotary Encoder的信号输出包括A相和B相两路方波通过两路信号的相位关系可以判断旋转方向。如果套用按键状态机的思路可以把A、B两相信号的组合看作一个4状态的循环序列。每次扫描时比较当前状态和上一次状态如果状态按照正常序列变化则方向为正反方向变化则方向为负。这种检测方式天然有消抖效果因为编码器在中间位置抖动时状态变化序列会被打断不会产生有效的旋转事件。我在实际项目中就复用了一套类似的机制来处理旋转编码器的倍率调节和菜单导航代码结构和按键状态机几乎一样只是把电平读取替换成了AB相组合读取状态表从按键的高低电平变成了4组组合状态。整体实现大约半小时就完成了对比传统的“读电平→延时→再读”方式代码量少了一半可靠性却高了很多。6.2 摇杆回中检测中的状态机应用模拟摇杆虽然输出的是模拟量但摇杆的回中检测同样可以用状态机建模。摇杆从推动状态回到中心位置时因为机械结构和弹簧的原因输出值不会立刻稳定到中心点而是会围绕着中心位置来回振荡几次。如果按传统的阈值判断方式摇杆回中的瞬间可能被误判为向反方向推动了。处理方式是定义一个“回中确认态”检测到摇杆输出值进入中心阈值范围内时不立即确认回中而是要求连续N次采样都稳定在阈值范围内才真正进入中心态。这个思路和按键消抖的状态迁移完全同构。我甚至在同一个代码框架下同时管理了按键、编码器和摇杆三个模块的检测逻辑每个模块复用同样的状态机基础结构只是状态定义和迁移条件各自不同。6.3 触摸按键的电容采样与状态融合触摸按键的检测时序和机械按键有很大差异但状态机架构依然适用。触摸按键的原始数据是电容采样值需要先经过滤波和阈值比较转换成“触摸状态”和“释放状态”再送入状态机进行消抖和事件识别。这样做的好处是电容采样模块只需要关注数据质量的优化状态机模块只需要关注事件逻辑的判定两者分层清晰维护起来方便很多。我做过一个混合输入设备机械按键和触摸按键共存两者的检测逻辑都使用了状态机架构只是底层的信号获取方式不同。整体代码保持了非常好的统一性业务逻辑完全不用区分事件来源是机械按键还是触摸按键。7. 调试与验证方法7.1 状态可视化是最大的调试利器按键状态机调试中最有效的工具就是状态可视化。简单做法是在每个状态迁移时通过串口打印一行日志格式为“时间戳 按键ID 旧状态→新状态”。在调试双击问题时我通常在PC端写一个小脚本读取串口日志实时显示每个按键的状态流转曲线。这样能清晰地看到每次扫描的状态变化定位问题是发生在消抖环节、单击判定环节还是双击等待环节。我建议打印日志时把消抖计数器的值和计时器的值也一并输出这样能直观地看到计数是增长还是被清零很快就能判断是消抖策略问题还是参数设置问题。我在调试中发现过一种奇怪的“间歇性双击失效”问题通过日志看到第一下释放等待期间消抖计数被偶尔出现的抖动电平干扰导致清零了一次虽然最后依然触发了双击但整个过程多花了几十毫秒如果双击窗口设置得紧就会失效。7.2 自动化测试脚本的设计思路按键状态机的自动化测试很值得投入精力。最简单的做法是使用信号发生器直接给按键输入引脚注入模拟的按键波形通过改变波形的时间参数验证状态机的各种边界条件按下抖动宽度变化时消抖功能是否正常按下持续时间为长按阈值临界值时是否稳定分界两次按键间隔略大于和略小于双击窗口时是否正确区分释放抖动叠加在长按结束位置时长按事件是否完整快速连续敲击超过双击窗口时是否每个敲击都能识别为单击我在实际项目中用Python写了一套自动测试脚本通过一个简易的GPIO模拟器向被测板卡注入按键波形再把状态机的反馈事件通过串口回传给脚本统一比对整套流程跑下来只需要十几分钟就能覆盖几百个测试用例。这种做法在按键状态机这种逻辑密集的模块上特别划算能省下大量手工测试时间。7.3 实测数据与参数推荐根据我在多个项目中的测试数据下面是一组比较通用且经过验证的参数推荐实际使用时需要根据具体的按键型号、扫描周期和使用场景做调整参数推荐值说明扫描周期5ms ~ 10ms越短响应越快但MCU负担越大按下消抖阈值3 ~ 5次扫描对应总时间15ms ~ 50ms释放消抖阈值3 ~ 5次扫描与按下消抖一致释放抖动更需重视双击判定窗口250ms ~ 350ms从第一次释放确认后开始计时长按阈值500ms ~ 1000ms根据应用场景调整误触风险高则加大长按连发周期150ms ~ 300ms仅在需要连发功能的场景使用这组参数在我的项目中经历了多个批次的硬件验证各种品牌的按键开关都能稳定工作。但一定要记住参数是死的设备是活的批量生产前一定要针对最终选型的按键做充分的实测用数据说话而不是靠经验直接定参数。
返回列表