Arduino/ESP8266 仅当脉冲之间的时间差为零时,去抖动(使用中断)才会失败

Arduino/ESP8266 debounce (using interrupt) fails only when time difference is zero between pulses

我有一块ESP8266(NodeMCU)开发板。我正在尝试在使用中断时在连接到 GPIO5 的触觉按钮上实现软件去抖动。对于“relayPin”,我暂时使用板载 LED (GPIO16)。

当我尝试按下按钮并非常快速地摆动它时,去抖动在大多数情况下都有效。然而,它在极少数情况下会失败,并且仅当两个不同检测到的脉冲之间的时间间隔为零时才会失败。所以基本上,当时间间隔大于 0 且小于去抖时间 (200ms) 时,它永远不会失败。请查看串行监视器的图像。

虽然这个问题发生在极端条件下(开关不会以这种方式使用),但我仍然想弄清楚这是否与我的代码有关或我不知道的其他方面.

Image 1: Push-button circuit

Image 2: Code & serial monitor

int swButton = 5;
int relayPin = 16;

bool relayOn = false;   // Present on/off state of the relay.

int debounceTime = 200;   // Debounce time in ms.

volatile bool switchToggle = false;   // True when button press is valid (and not bounce noise).
volatile unsigned long nowPush = 0;   // The millis() time of the present button press.
volatile unsigned long lastPush = 0;  // The millis() time of the previous button press.
volatile unsigned long timeGap = 0;  // The difference of the nowPush and lastPush times.


// Interrupt Service Routine on button press (falling edge).
ICACHE_RAM_ATTR void swButtonISR() {
  nowPush = millis();
  timeGap = nowPush - lastPush;
  
  // Debouncing stuff, recognizing this button-press as a valid one.
  if (timeGap > debounceTime) {
    switchToggle = true;
    lastPush = nowPush;
  }
}

// Function that toggles the relay when called upon.
void toggleRelay () {
    if (relayOn) {
      digitalWrite(relayPin, LOW);   // Turn off relay.
      relayOn = false;
      Serial.println((String)"Relay ON.   Time gap: "+timeGap);
      return;
    }
    else {
      digitalWrite(relayPin, HIGH);    // Turn on relay.
      relayOn = true;
      Serial.println((String)"Relay OFF.  Time gap: "+timeGap);
      return;
    }
    return;
}


void setup() {  
  Serial.begin(115200);
  pinMode(swButton, INPUT);
  pinMode(relayPin, OUTPUT);
  pinMode(greenLED, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(swButton), swButtonISR, FALLING);
}

void loop() {
  if (switchToggle == true) {
    toggleRelay();
    switchToggle = false;
  }
}

您可以进行一些更改,以在“释放按钮”后强制延长延迟时间。 (您也可以只附加一个带有 CHANGE 条件的中断处理程序,以捕获 FALLINGRISING边。)

添加这个

attachInterrupt(digitalPinToInterrupt(swButton), swButtonISR2, RISING);

改变这个

ICACHE_RAM_ATTR void swButtonISR() {
    nowPush = millis();
    timeGap = nowPush - lastPush;

    // Debouncing stuff, recognizing this button-press as a valid one.
    if (timeGap > debounceTime) {
        switchToggle = true;
    }
    lastPush = nowPush;
}

添加这个

ICACHE_RAM_ATTR void swButtonISR2() {
    lastPush = millis();
}