一只轻触开关同时干两件事:长按2秒开关机,短按循环换档。听着简单,真做过大批量出货的人都在这上面栽过------误触发、连击、长按识别不准、静电一打就跳档。
这篇把按键检测这件事从软件到硬件过一遍,再说说为什么不值得为一个固定功能写这套代码。
软件方案要做的事
用MCU实现,核心是一个按键状态机加一个计时器。我习惯5ms扫一次,状态这么划:
typedef enum { KEY_IDLE = 0, // 无按键 KEY_DEBOUNCE, // 消抖中 KEY_PRESSED, // 已确认按下 KEY_LONG_DONE // 长按已响应,等释放 } key_state_t; void key_scan_5ms(void) { static key_state_t st = KEY_IDLE; static uint16_t hold_ms = 0; uint8_t level = KEY_READ(); // 0 = 按下 switch (st) { case KEY_IDLE: if (level == 0) { st = KEY_DEBOUNCE; hold_ms = 0; } break; case KEY_DEBOUNCE: if (level == 0) { if (++hold_ms >= 4) { st = KEY_PRESSED; hold_ms = 0; } // 20ms } else st = KEY_IDLE; break; case KEY_PRESSED: if (level == 0) { hold_ms += 5; if (hold_ms >= 2000) { on_long_press(); st = KEY_LONG_DONE; } } else { on_short_press(); st = KEY_IDLE; } break; case KEY_LONG_DONE: if (level != 0) st = KEY_IDLE; // 长按已执行,释放时不再补短按 break; } }
关键在KEY_LONG_DONE这个状态。很多新手代码长按响应完,松手时又触发了一次短按,表现就是"长按关机后自己又开了"。这个状态位必须留。
短按判定放在释放时刻,长按判定放在按住满2秒那一刻,这样用户手感最顺:按住不放,到2秒就动作,不用等松手。
还有一个容易漏的点:计时过程中的短按要同样有效。也就是定时跑到一半再按一下,直接切下一档,不能要求用户先关机再开机。把切档逻辑和开关机逻辑解耦,写成分开的两个函数,这块就不容易乱。
另外提醒一句,按键扫描的5ms时基如果用内部RC,2秒阈值本身也有误差。要求不严的场合无所谓,产品如果标称"长按2秒",最好用外部时基或者至少校准一遍。
软件方案的隐性成本
上面这段代码本身不值钱,值钱的是它后面跟着的一串事。
休眠时怎么扫。电池供电的产品大部分时间睡着,按键要能做唤醒源,唤醒后时钟要稳定,计时不能跑偏。低功耗下用内部RC做时基,15分钟能飘出多少,得实测,别拿数据手册典型值当承诺。
产测工装。每块板要烧一次程序,要留烧录口或者做针床,量产爬坡时这就是瓶颈。程序版本管理、改一版时间要重新烧一批货,这些成本不进BOM但进项目周期。
EMC。MCU方案在群脉冲和静电测试上比专用料更容易出问题,IO口多,受影响的面就大。
硬件方案省掉的就是这些
专用定时芯片把消抖、长按计时、档位循环全部做进去了,留给工程师的只有KEY脚的外围。

KEY脚低电平触发,外部上拉。常规10k,引线长的场合降到4.7k,必要时再并1nF~10nF对地做RC消抖。
这里有个取舍要自己把握:RC时间常数按τ=R×C估,取到几毫秒量级就够压掉机械抖动,取到几十毫秒会让长按的2秒阈值在手感上"变糊",用户按住会犹豫到底生效没有。
我的经验值是上拉10k配2.2nF起步,实测不误触发就往上加,别照抄参考图。
专用料内部怎么做消抖我们看不到,但从外部行为上能反推个大概:连着快速点按,响应稳定,不丢也不重。自己在MCU上做到这个程度,按键扫描那套代码加上调试,快的话半天,慢的两三天。
走线抗干扰的经验
KEY走线是这块板子上最娇气的一根。
远离输出驱动。尤其不要和MOS漏极走线、加热丝驱动线、继电器线平行走长距离。输出跳变通过寄生电容耦合过来,示波器上KEY脚能看到尖刺,超过芯片识别阈值就是一次误触发。
面板按键走线双绞,或者一根信号一根地并排走,地线上再串一颗磁珠也行。走线超过10cm的,在芯片端并100pF对地,电容放芯片侧不要放按键侧。
有条件的包地。KEY走线两侧铺地打屏蔽过孔,成本几乎为零,效果明显。
ESD别省。按键是人手能摸到的地方,TVS管或者至少一颗1nF高压电容加串阻,测试过不去再补就晚了一版板。
按键外壳是金属的,金属件一定要接地,并且和KEY走线之间留出爬电距离。见过最离谱的一次是静电打在金属按键上,直接把芯片打坏。
上拉电阻靠近芯片放,不要靠近按键放。靠近按键的话,芯片到按键那段线等于悬空天线,上拉电阻的钳位作用要走过整根线才生效。
什么时候值得自己写
如果你要的是固定的三档、固定的时长、固定的输出极性,那这段代码一个项目写一次,第二个项目再写一次,本质上是在重复劳动。
要联网、要屏显、要APP改档位,那另说,MCU该上还得上。
手上项目档位和时间跟标准品不一样也没关系,这款可以按你的功能要求重新定制开发程序,把需求发过来评估就行。