Та же кнопка одним кликом и двойным кликом

Я надеюсь получить помощь с моим кодом.

Я пытаюсь отличить одиночное нажатие от быстрого двойного нажатия кнопки с устранением дребезга.

Я делаю какую-то глупую ошибку в своем коде и не могу понять, в чем проблема. Если я дважды нажму кнопку, на последовательном мониторе будут напечатаны как «одиночный», так и «двойной».

Заранее спасибо за помощь.

const int buttonPin = 5;
unsigned long lastPressTime;
int buttonState = 0;
int singlePress = 0;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);

  lastPressTime = millis();
  Serial.begin(9600);
}

void loop() {
  if (!digitalRead(buttonPin) == HIGH && buttonState == 0) {
    unsigned long currentPressTime = millis();

    //два нажатия в течение 500 мс
    if (currentPressTime - lastPressTime < 500) {
      singlePress = 0;
      // Делаем двойное нажатие
      Serial.println("double");
    } else {
      singlePress = 1;
    }

    //обновляем время последнего нажатия
    lastPressTime = currentPressTime;
    buttonState = 1;
  } else if (!digitalRead(buttonPin) == LOW) {
    buttonState = 0;
  }

  //проверяем, прошло ли 500 мс без нажатия второй кнопки
  if (singlePress == 1 && lastPressTime  - millis() > 500) {
    singlePress = 0;
    // Делаем однократное нажатие
    Serial.println("single");
  }
}

, 👍0

Обсуждение

почему бы не использовать библиотеку? например Bounce2, @Juraj

@Juraj ... Я знаю, что для таких ситуаций есть несколько библиотек. Я знаю Bounce2 и обычно использую библиотеку OneButton. В этом случае я пытаюсь заставить его работать без использования библиотеки., @Carlos Costa

оба 'single' и 'double' печатаются на последовательном мониторе... вы почти у цели... добавьте код, чтобы выбрать один, затем напечатайте, @jsotola

Это выглядит странно, lastPressTime - millis() > 500, так как lastPressTime будет меньше, чем millis(), но я не думаю, что это ваша единственная проблема. Я реструктурировал ваше решение как более явный конечный автомат и поместил его в симулятор: https://wokwi.com/projects/347070000856564307., @6v6gt


2 ответа


1

Проблема заключается в следующем утверждении:

lastPressTime  - millis() > 500

Поскольку время хранится как unsigned long, этот тест в том виде, в каком он написан сейчас, всегда верен.

Вы хотите измерить время, прошедшее с момента последнего нажатия, поэтому вам следует вычесть отметку времени последнего нажатия из текущего времени. Замените его на:

millis() - lastPressTime > 500

И код будет работать нормально.

,

Если ваш «ответ» на 100% получен из чьего-то предыдущего комментария, указывающего на очевидную ошибку, было бы вежливо хотя бы признать это. Еще лучше было бы подождать, пока создатель кода не исправит свой код и не сообщит о результатах, прежде чем делать заявление типа «И код будет работать нормально». . (Я не верю, что это так), @6v6gt


0

Спасибо всем за помощь...

Определенно проблема в моем коде, чтобы заставить работать один щелчок и двойной щелчок, как написал @mhopeng, заключалась в следующем утверждении:

lastPressTime  - millis() > 500

изменить его на это

millis() - lastPressTime > 500

заработало.

Но я понимаю, что мой подход недостаточно гибок. Использование подхода @6v6gt намного лучше моего. Реакция намного более отзывчивая и плавная.

// обратите внимание, что скорость симуляции составляет около одной трети реального времени
// настроить тайминги при использовании на реальном оборудовании.

const int buttonPin = 5;
unsigned long inStateAtMs = millis() ;
int buttonState ;  // 0 = ожидание нажатия, 1 = ожидание отпускания 2 = различение одиночного или двойного 3 = ожидание отпускания кнопки (двойное)

void setup() {
 pinMode(buttonPin, INPUT_PULLUP);
 Serial.begin(9600);
}

void loop() {

 if ( buttonState == 0 ) {
   // ждем нажатия кнопки
   if ( millis() - inStateAtMs > 100 ) {
     if (!digitalRead(buttonPin)) {
       buttonState = 1 ;
       inStateAtMs = millis();
     }
   }
 }
 else if ( buttonState == 1 ) {
   // ждем стабильного отпускания кнопки 1
   if ( millis() - inStateAtMs > 100 && digitalRead(buttonPin) ) {
     buttonState = 2 ;
     inStateAtMs = millis();
   }
 }
 else if ( buttonState == 2 ) {
   // различаем одинарное и двойное нажатие
   if ( millis() - inStateAtMs > 400 ) {
     // таймаут - однократное нажатие
     Serial.println("single");
     buttonState = 0 ;
     inStateAtMs = millis() ;
   }
   else if (  ( ! digitalRead(buttonPin) ) && (millis() - inStateAtMs > 100 ) ) {
     // получено второе нажатие в течение тайм-аута - double
     Serial.println("double");
     buttonState = 3 ;
     inStateAtMs = millis() ;
   }
 }
 else if ( buttonState == 3 ) {
   // ждем стабильного отпускания кнопки 2
   if ( millis() - inStateAtMs > 100 && digitalRead(buttonPin) ) {
     buttonState = 0 ;
     inStateAtMs = millis();
   }
 }
}

Еще раз спасибо всем за помощь

,

Я рад, что у вас есть что-то, что работает для вас. Я поместил ваш оригинальный скетч, но с исправлением, в тот же симулятор, и он не работает. Тем не менее, он [симулятор], похоже, реализует преувеличенный отскок кнопки, который вы можете не встретить на физическом Arduino. Он здесь, если вы хотите поиграть с ним: https://wokwi.com/projects/347070013621928531, @6v6gt

Я заметил, что в симуляторе мой код не работает, а на физической Ардуино работает., @Carlos Costa