ESP, IoT Нужна помощь. Как избежать дребезга в прерывании?

LordZET

✩✩✩✩✩✩✩
1 Мар 2022
12
2
53
Здравствуйте!
Использую WEMOS esp8266, библиотека EncButton, нужно увеличивать счетчик в прерывании по кнопке.
Возможно что-то упустил в настройках, но вот результат: три нажатия и получаю непоследовательные числа
Как избежать дребезга в прерывании?
2025-01-27_12-17-02.png
C++:
// кнопка и прерывания
#include    <Arduino.h>
#include    <EncButton.h>
#define EB_DEB_TIME 80     // таймаут гашения дребезга кнопки (кнопка)
#define        BTN_PIN    D3
Button eb(BTN_PIN);
volatile byte screen = 0;  // текущий экран

// esp8266/esp32
IRAM_ATTR void isr() {
  screen++;
  if (screen > 9)screen = 0;
  eb.pressISR();
}

void setup() {
  Serial.begin(115200);
  attachInterrupt(BTN_PIN, isr, FALLING);
}

void loop() {
  eb.tick();
  if (eb.click()) {
    Serial.print("screen ");
    Serial.println(screen);
  }
  delay(100);  // имитация загруженной программы
}
Есть конечно же рабочее решение, и даже без дополнительной библиотеки по примеру Ловим событие,
C++:
#define        BTN_PIN    D3
volatile bool intFlag = false;   // флаг
volatile byte screen = 0;  // текущий экран

// esp8266/esp32
IRAM_ATTR void isr() {
  intFlag = true;   // подняли флаг прерывания
}

void setup() {
  Serial.begin(115200); // открыли порт для связи
  pinMode(BTN_PIN, INPUT_PULLUP);
  attachInterrupt(BTN_PIN, isr, FALLING);
}

void loop() {
  if (intFlag) {
    intFlag = false;    // сбрасываем
    screen++;
    if (screen > 9)screen = 0;
    Serial.print("screen ");
    Serial.println(screen);
  }
}
Но неужели EncButton с кучей настроек не может этого? Тем более что иногда всё таки есть необходимость выполнить короткое событие, которое обязательно обрабатывать сразу.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,276
1,303
Москва
В библиотеке EncButton предусмотрен программный антидребезг, т.е. событие клика будет срабатывать не чаще чем установленное значение. Все клики , что чаще будут просто игнорироваться.
А событие вызывает isr каждый раз с дребезгом.
Варианты рещения:
1. Программное. Запоминать время события и так же игнорировать если прошло слишком мало времени.
2. Аппаратное. собрать RC цепочку для кнопки. Поиск в помощь.
 

poty

★★★★★★✩
19 Фев 2020
3,268
949

@LordZET, прочитайте внимательно описание библиотеки. Класс сам считает нажатия и обрабатывает дребезг, но для этого нужно всё убрать из прерывания и пользоваться методами класса!
 

bort707

★★★★★★✩
21 Сен 2020
3,070
915
@LordZET, все просто и банально. Если вам понадобится антидребезг - значит процесс у вас не быстрый и вам не нужно прерывание.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,276
1,303
Москва
@poty, Кстати да, если надо только что бы экран менялся, то достаточно сделать так:

C++:
// кнопка и прерывания
#include    <Arduino.h>
#include    <EncButton.h>
#define EB_DEB_TIME 80     // таймаут гашения дребезга кнопки (кнопка)
#define        BTN_PIN    D3
Button eb(BTN_PIN);
volatile byte screen = 0;  // текущий экран

// esp8266/esp32
IRAM_ATTR void isr() { 
  eb.pressISR();
}

void setup() {
  Serial.begin(115200);
  attachInterrupt(BTN_PIN, isr, FALLING);
}

void loop() {
  eb.tick();
  if (eb.click()) {
    Serial.print("screen ");
    Serial.println(screen++);
    if (screen > 9)screen = 0;
  }
  delay(100);  // имитация загруженной программы
}