Implement Long Press button

Hello I cannot wrap my head around how to implement a long press funktion in my sketch.
I have tried a bunch of things but it doesn't work.

Basically I want every button press to be a long press, because the button I have is spring loaded and it sometimes make a fast double press which gives false readings.

Therefore to eliminate that issue I want the button to be press at least 1 second before it gets detected as a press.

Here is my sketch:

#define trButton 2      // training/reset button (being eliminated/modified)
#define processInput 2  // needs the sensor from the process
#define faultLED 3
#define readyLED 13
#define runningLED 10

bool needCalibration;  // set this to force a calibration run

enum bar { IDLE = 0,
           MEASURE,
           CHECK,
           IFAULT,
           NFAULT,
};

void setup() {
  Serial.begin(9600);
  Serial.print("\nhello world.\n");

  pinMode(readyLED, OUTPUT);
  pinMode(runningLED, OUTPUT);
  pinMode(faultLED, OUTPUT);
  pinMode(trButton, INPUT_PULLUP);
  pinMode(processInput, INPUT_PULLUP);

  needCalibration = true;  // first run, and any run after a fault
}

unsigned int counter;
unsigned char state = IDLE;  // does. is.

unsigned long now;
unsigned long timeLimit;
unsigned long timer;

void loop() {
  delay(20);

  now = millis();

  bool controlX = digitalRead(processInput) == HIGH;
  bool buttonState = digitalRead(trButton) == HIGH;

  static bool lastButtonState;
  static bool buttonPress;

  if (buttonState != lastButtonState) {
    if (buttonState) {
      buttonPress = !buttonPress;
    }
    lastButtonState = buttonState;
  }

  switch (state) {
    case IDLE:
      digitalWrite(readyLED, HIGH);
      digitalWrite(runningLED, LOW);
      if (controlX) {
        timer = now;
        //      if (buttonPress || needCalibration) {
        if (needCalibration) {
          state = MEASURE;
          Serial.print("training for time\n");
          buttonPress = false;
          needCalibration = false;
        } else {
          state = CHECK;
          Serial.print("X up. monitoring time\n");
        }
      }
      break;

    case CHECK:
      digitalWrite(readyLED, LOW);
      digitalWrite(runningLED, HIGH);
      if (now - timer > timeLimit) {
        state = IFAULT;
        break;
      }
      if (!controlX) {
        Serial.print("X down     made it by ");
        Serial.println(timeLimit - (now - timer));
        state = IDLE;
      }
      break;

    case MEASURE:
      digitalWrite(readyLED, LOW);
      digitalWrite(runningLED, HIGH);
      if (!controlX) {
        timeLimit = now - timer;
        timeLimit += timeLimit / 10;  // comfort margarine 10 percent here
        Serial.print("X down    new period = ");
        Serial.println(timeLimit);

        state = IDLE;
      }
      break;

    case IFAULT:
      Serial.print(" initialize fault mechanism");
      state = NFAULT;
      Serial.print(" / perpetuate fault mechanism\n");

      digitalWrite(faultLED, HIGH);
      buttonPress = false;  // eat any stray button presses
      break;

    case NFAULT:
      digitalWrite(readyLED, LOW);
      digitalWrite(runningLED, LOW);
      digitalWrite(faultLED, millis() & 512 ? HIGH : LOW);
      if (buttonPress) {
        Serial.print("sytem to IDLE\n");
        digitalWrite(faultLED, LOW);
        buttonPress = false;
        needCalibration = true;
        state = IDLE;
      }
      break;
  }
}

If that is the case then what you need to do is to implement debouncing in your sketch

There is an example in the IDE showing one way to do it. As an alternative you could consider using a library to handle the button presses. The library code would then take care of debouncing for you

Yeah I looked at that both the Debounce example and the PushButton library.

But I get kind of confused on how to implement them in my sketch.

Look at the bounce2 library. There are multiple examples, including a button. During setup(), just set the debounce time to something like 750 msec

Okay I figured out some kind of solution to my problem.

May not be the most correct way to do it, but it works.

It is implemented in the "CASE" called "NFAULT"

#define trButton 2      // training/reset button (being eliminated/modified)
#define processInput 2  // needs the sensor from the process
#define faultLED 3
#define readyLED 13
#define runningLED 10

bool needCalibration;  // set this to force a calibration run

enum bar { IDLE = 0,
           MEASURE,
           CHECK,
           IFAULT,
           NFAULT,
};

void setup() {
  Serial.begin(9600);
  Serial.print("\nhello world.\n");

  pinMode(readyLED, OUTPUT);
  pinMode(runningLED, OUTPUT);
  pinMode(faultLED, OUTPUT);
  pinMode(trButton, INPUT_PULLUP);
  pinMode(processInput, INPUT_PULLUP);

  needCalibration = true;  // first run, and any run after a fault
}

unsigned int counter;
unsigned char state = IDLE;  // does. is.

unsigned long now;
unsigned long timeLimit;
unsigned long timer;

unsigned long previousMillis = 0; // Gemmer det tidspunkt, hvor LED'en sidst blev opdateret
const long interval = 1000; // Blink interval (i millisekunder)

void loop() {
  delay(20);

 unsigned long currentMillis = millis(); // Hent antallet af millisekunder siden Arduino startede

  now = millis();
  

  bool controlX = digitalRead(processInput) == HIGH;
  bool buttonState = digitalRead(trButton) == HIGH;

  static bool lastButtonState;
  static bool buttonPress;

  if (buttonState != lastButtonState) {
    if (buttonState) {
      buttonPress = !buttonPress;
    }
    lastButtonState = buttonState;
  }

  switch (state) {
    case IDLE:
      digitalWrite(readyLED, HIGH);
      digitalWrite(runningLED, LOW);
      if (controlX) {
        timer = now;
        //      if (buttonPress || needCalibration) {
        if (needCalibration) {
          state = MEASURE;
          Serial.print("training for time\n");
          buttonPress = false;
          needCalibration = false;
        } else {
          state = CHECK;
          Serial.print("X up. monitoring time\n");
        }
      }
      break;

    case CHECK:
      digitalWrite(readyLED, LOW);
      digitalWrite(runningLED, HIGH);
      if (now - timer > timeLimit) {
        state = IFAULT;
        break;
      }
      if (!controlX) {
        Serial.print("X down     made it by ");
        Serial.println(timeLimit - (now - timer));
        state = IDLE;
      }
      break;

    case MEASURE:
      digitalWrite(readyLED, LOW);
      digitalWrite(runningLED, HIGH);
      if (!controlX) {
        timeLimit = now - timer;
        timeLimit += timeLimit / 10;  // comfort margarine 10 percent here
        Serial.print("X down    new period = ");
        Serial.println(timeLimit);

        state = IDLE;
      }
      break;

    case IFAULT:
      Serial.print(" initialize fault mechanism");
      state = NFAULT;
      Serial.print(" / perpetuate fault mechanism\n");

      digitalWrite(faultLED, HIGH);
      buttonPress = false;  // eat any stray button presses
      break;

    case NFAULT:
      digitalWrite(readyLED, LOW);
      digitalWrite(runningLED, LOW);
      digitalWrite(faultLED, millis() & 512 ? HIGH : LOW);

if (currentMillis - previousMillis >= interval) { // Tjek om det er tid til at tænde/slukke LED'en
    previousMillis = currentMillis; // Gem det aktuelle tidspunkt
 //   Serial.println(previousMillis);


      if (buttonPress) {
        Serial.print("sytem to IDLE\n");
        digitalWrite(faultLED, LOW);
        buttonPress = false;
        needCalibration = true;
        state = IDLE;
      }
}
      break;
  }
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.