Comprobación de pulsaciones cortas y largas con antirrebote

Soy un principiante completo con Arduino, pero he buscado bastante y parece que no puedo solucionar este problema.

Estoy tratando de crear un procedimiento que se llama repetidamente en el principal loop()que establecerá una variable según el estado actual de un botón, así como la duración del botón o durante el cual se presionó. Este código es probablemente más complicado de lo que debe ser, pero parece dejar la variable en 0. ¿Qué me estoy perdiendo?

Hay un código en loop()sí mismo que restablece la rotaryButtonToActionvariable noPressuna vez que se ha actuado.

#define noPress 0
#define shortPressReleased 1
#define longPressReleased 2
#define shortPressHolding 3
#define longPressHolding 4

int rotaryButtonState;
int rotaryButtonReading;
int lastRotaryButtonReading = HIGH;
int timeOfLastRotaryButtonReadingChange = 0;
int debounceDelay = 50;
int longPressDelay = 300;
int rotaryButtonToAction = 0;

void checkRotaryButton() {
  if (rotaryButtonToAction == noPress) { // if there is nothing to action, check the state of the button
    rotaryButtonReading = digitalRead(ROTARY_BUTTON); // store pin's current state
    if (rotaryButtonReading != lastRotaryButtonReading) { // if pin state has changed from the last reading, set timeOfLastRotaryButtonReadingChange to the time of the change
      timeOfLastRotaryButtonReadingChange = millis();
    }
    if (millis() - timeOfLastRotaryButtonReadingChange > debounceDelay) { // if more time has passed than the debounce delay, change the action state of the button
      if (rotaryButtonReading = LOW) { // if the button is still pressed, set the action to indicate it has been pressed and is still pressed
        rotaryButtonToAction = shortPressHolding;
      }
    else { // if the button was pressed for longer than the debounce delay and was released, set the action
      rotaryButtonToAction = shortPressReleased;
      }
    }
  } 

  if (millis() - timeOfLastRotaryButtonReadingChange > longPressDelay) { // if more time has passed than the long press delay, change the action state of the button
    if (rotaryButtonReading == LOW) { // if the button is still pressed, set the action to indicate it has been pressed and is still pressed
      rotaryButtonToAction = longPressHolding;
    }
    else { // if the button was pressed for longer than the long press delay and was released, set the action
      rotaryButtonToAction = longPressReleased;
    }
  }

} // end checkRotaryButton

Respuestas (2)

Nunca usé Arduino, pero ¿no necesita usar signos iguales dobles en una función de comparación?

Entonces, ¿ if (rotaryButtonToAction = noPress)debería ser if (rotaryButtonToAction == noPress)en su lugar?

Casi trabajando ahora. Publicaré la solución de trabajo tan pronto como la tenga.
No soy un gran microcodificador, pero esto podría ser más simple usando temporizadores de vigilancia (WDT) e interrupciones. Definitivamente vale la pena aprender si no lo usa en este proyecto. Además, el código de muestra es una buena manera de aprender. ¡Buena suerte!
Definitivamente miraré los temporizadores de vigilancia. No es algo con lo que me haya encontrado todavía (compré mi primer Arduino hace dos semanas). Desafortunadamente para este proyecto, ya tengo un codificador rotatorio que ocupa los dos pines con capacidad de interrupción del Arduino UNO, por lo que no puedo poner el botón pulsador en una interrupción.
es mejor usar la constante primero en tales casos: el compilador detectará un error si comete un error accidentalmente (eso nos sucede a todos), es decir, use if (0 == variable) en lugar de if (variable == 0) porque si escribe if(0 = variable), el compilador detectará el error, mientras que if(variable = 0) es una expresión C perfectamente normal

Bueno, después de mucho jugar, adopté un enfoque completamente diferente que parece hacer justo lo que necesito. Creo que este es un ejemplo de una "máquina de estado", aunque soy nuevo en todo esto...

void checkRotaryButton() {
  rotaryButtonReading = digitalRead(ROTARY_BUTTON); // store pin's current state
  if (rotaryButtonReading != lastRotaryButtonReading) { // if pin state has changed from the last reading
    timeOfLastRotaryButtonChange = millis(); // if pin state different, store the time of the state change
  }
  timeSinceLastRotaryButtonChange = millis() - timeOfLastRotaryButtonChange;

  if (rotaryButtonReading == LOW && timeSinceLastRotaryButtonChange < debounceDelay) {
    // has only been low for less than the debounce time - do nothing
  }
  if (rotaryButtonReading == LOW && timeSinceLastRotaryButtonChange > longPressDelay && rotaryButtonToAction != longPressed) {
      rotaryButtonToAction = longPressed;
      Serial.println("button pressed long");  
  }
  if (rotaryButtonReading == LOW && timeSinceLastRotaryButtonChange > debounceDelay && timeSinceLastRotaryButtonChange < longPressDelay && rotaryButtonToAction != holdingPress) {
      rotaryButtonToAction = holdingPress;
      Serial.println("holding button pressed");  
  }
  if (rotaryButtonReading == HIGH && timeSinceLastRotaryButtonChange > debounceDelay && rotaryButtonToAction == holdingPress) {
      rotaryButtonToAction = shortPressed;
      Serial.println("released short press");    
  }


  lastRotaryButtonReading = rotaryButtonReading; // store this reading for comparison the next time the procedure loops
} // end checkRotaryButton