AIGC标识 ESP32 工程实践:用状态机实现按键消抖与长按识别

机械按键按下时,触点往往会在短时间内反复通断。如果直接把每次电平变化都当成一次点击,菜单可能跳过多个选项。加入 delay(20) 虽然容易理解,却会暂停主循环里的网络维护与其他任务。本篇用状态机把“输入采样”和“确认事件”分开。

示例面向经典 ESP32 开发板和 Arduino-ESP32 3.x。代码是教学示例,未在本文中完成实机验证;消抖时间与接线请根据实际硬件调整。

接线与输入约定

按键一端连接 GPIO27,另一端连接 GND,配置为 INPUT_PULLUP。松开读到 HIGH,按下读到 LOW。这里使用普通外接按键;其他型号或带外设的开发板应先核对 GPIO27 是否可用。

长线和强干扰场景中,内部上拉可能不足,应结合外部上拉、布线与必要的硬件滤波处理。不要把 5 V 信号直接接入 ESP32 的 GPIO。

状态机如何工作

保存原始电平、确认后的稳定电平,以及原始电平最后一次变化的时间。只有新电平持续 25 ms,才更新稳定状态。按下确认时记录起点;持续按下 800 ms 产生一次长按事件;松开时,如果此前没有产生长按,才产生短按事件。

这样一次按压最多产生一种事件。注意这里的时间从“确认按下”开始,而不是从触点第一次闭合开始。

完整最小示例

#include <Arduino.h>

constexpr uint8_t KEY_PIN = 27;
constexpr uint32_t DEBOUNCE_MS = 25;
constexpr uint32_t LONG_MS = 800;
bool rawLevel = HIGH;
bool stableLevel = HIGH;
bool longSent = false;
uint32_t rawChangedAt = 0;
uint32_t pressedAt = 0;

void setup() {
  Serial.begin(115200);
  pinMode(KEY_PIN, INPUT_PULLUP);
  rawChangedAt = millis();
}

void loop() {
  const uint32_t now = millis();
  const bool sample = digitalRead(KEY_PIN);
  if (sample != rawLevel) {
    rawLevel = sample;
    rawChangedAt = now;
  }

  if (rawLevel != stableLevel &&
      uint32_t(now - rawChangedAt) >= DEBOUNCE_MS) {
    stableLevel = rawLevel;
    if (stableLevel == LOW) {
      pressedAt = now;
      longSent = false;
    } else if (!longSent) {
      // 即使循环偶尔延迟,也按持续时间区分松开事件。
      if (uint32_t(now - pressedAt) >= LONG_MS) {
        Serial.println("LONG");
      } else {
        Serial.println("SHORT");
      }
    }
  }

  if (stableLevel == LOW && rawLevel == LOW && !longSent &&
      uint32_t(now - pressedAt) >= LONG_MS) {
    longSent = true;
    Serial.println("LONG");
  }
  delay(1);  // 让出调度机会,不承担消抖计时。
}

时间比较使用无符号减法,避免把 millis() 回绕直接误判为超时。该写法仍要求计时间隔合理,不能用于跨越一个完整计数周期的持续时间测量。

如何验证

在串口监视器以 115200 波特率观察:连续短按应每次出现一个 SHORT;按住超过 800 ms 应只出现一个 LONG,松开后不追加 SHORT。重点测试临界时长、快速连按以及上电时一直按住。

代码会把上电时持续按住的按键视为一次按压。如果产品不希望开机触发动作,需要先等待一次稳定松开,再允许事件识别。

本例依赖主循环持续采样。若主循环阻塞几秒,软件无法还原期间发生的多次按压;应先消除耗时操作,或把输入扫描放入独立任务。涉及任务间传递时,把事件送入队列,让业务层决定动作,避免在输入扫描里直接写文件或访问网络。

参考资料

posted on 2026-11-02 22:01  潇洒石头  阅读(3)  评论(0)    收藏  举报

导航