How can I ignore when an input goes high every other time?

I am having trouble expanding on this code.

What I am doing is tapping into an existing consumer products multi- function button. This allows me to retain its current functionality in the menu system of this device when needed but allows me to trigger it remotely when its is in another mode outside of the menu.

I have a microswitch wired into the XIAO SAMD21 microcontrollers input (pin 6 with pulldown resistor) that is pressed by a mechanical device momentarily. When pressed, PIN 2 goes high. This Output is what is connected to this devices button I wish to control remotely.

The device needs to see that HIGH signal for 50ms and then back to low for the device to act.

The problem is, it will see a second input on pin 6 shortly after the first as it retracts and I need that second input to be ignored.

Yeah, this is base level stuff for most of you but im lost.

I have a simple code that works great but it does not ignore that second, unwanted input on PIN 6.

I have played with the attached code "State change detection (edge detection)" and added that 50ms debounce delay I need but it just keeps repeating the ELSE section until the INPUT button is pressed again. I've plugged a few things in there to try and get it to stop after a single sequence of the below excerpt.

digitalWrite(ledPin, HIGH);
delay(50);
digitalWrite(ledPin, LOW);

I cant figure it out.

Any help would be appreciated.

/*
  State change detection (edge detection)

  Often, you don't need to know the state of a digital input all the time, but
  you just need to know when the input changes from one state to another.
  For example, you want to know when a button goes from OFF to ON. This is called
  state change detection, or edge detection.

  This example shows how to detect when a button or button changes from off to on
  and on to off.

  The circuit:
  - pushbutton attached to pin 2 from +5V
  - 10 kilohm resistor attached to pin 2 from ground
  - LED attached from pin 13 to ground through 220 ohm resistor (or use the
    built-in LED on most Arduino boards)

  created  27 Sep 2005
  modified 30 Aug 2011
  by Tom Igoe

  This example code is in the public domain.

  https://www.arduino.cc/en/Tutorial/BuiltInExamples/StateChangeDetection
*/

// this constant won't change:
const int buttonPin = 6;  // the pin that the pushbutton is attached to
const int ledPin = 2;     // the pin that the LED is attached to

// Variables will change:
int buttonPushCounter = 0;  // counter for the number of button presses
int buttonState = 0;        // current state of the button
int lastButtonState = 0;    // previous state of the button

void setup() {
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);
  // initialize serial communication:
  Serial.begin(9600);
}


void loop() {
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      buttonPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes: ");
      Serial.println(buttonPushCounter);
    } else {
      // if the current state is LOW then the button went from on to off:
      Serial.println("off");
    }
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;


  // turns on the LED every four button pushes by checking the modulo of the
  // button push counter. the modulo function gives you the remainder of the
  // division of two numbers:
  if (buttonPushCounter % 2 == 0) {
    digitalWrite(ledPin, LOW);
  } else {
    Serial.println("on");
    digitalWrite(ledPin, HIGH);
    delay(50);
    digitalWrite(ledPin, LOW);
    delay(50);

    //while (digitalRead(buttonPin) == LOW);
  }
}

Try delaying a little longer.

You've got this code out in the main loop where it's going to happen every time loop repeats. I think you want this check inside the if statement where the button press is detected. You only want this to happen once per press right?

Remove the ...

else {
  // ...
}

... and all you will see is the button counter.

Thanks for the guidance, I will give these suggestions a try after dinner.

Note change the delay time in the setDevice() function to what you need.

const int  buttonPin = 6;    // the pin that the pushbutton is attached to
const int triggerPin = 2;
int buttonState = 0;         // current state of the button
int lastButtonState = 0;
unsigned long lastMillis = 0;
int interval = 30;
int buttonPushCounter = 0;

void setup() {
  Serial.begin(115200);
  pinMode(buttonPin, INPUT); // do you know about INPUT_PULLUP? 
  pinMode(triggerPin, OUTPUT);
  digitalWrite(triggerPin, LOW);
}

void loop() {
  unsigned long currentMillis = millis();
  buttonState = digitalRead(buttonPin);
  if (currentMillis - lastMillis >= interval) {
    lastMillis = millis();
    if (buttonState != lastButtonState) {
      buttonState = digitalRead(buttonPin);
      if (buttonState == HIGH) { // this should be HIGH for button w/ pulldown resistor
        buttonPushCounter ++;
        Serial.print("number of button pushes:  ");
        Serial.println(buttonPushCounter);
        setDevice();
      }
      lastButtonState = buttonState;
    }
  }
}

void setDevice() {
  digitalWrite(triggerPin, HIGH);
  Serial.println("ON");
  delay(5000); // change to the time that suits ya
  digitalWrite(triggerPin, LOW);
  Serial.println("OFF");
}

I am realizing I might not have been clear as to what this input button sees. It is a brief press and then release as this device moves past. It is not a limit switch arrangement if that makes sense. It does not get pressed and held closed by the mechanism. It simply gets touched by a cam momentarily and that needs to signal the output sequence.

So I tried to move the code around as suggested but i'm still getting the repeating loop

Delta_G,
Yes I only want the output to go high for 50ms then drop back to low and that is all I want. The second button press is dropping the output to low which is good but the "else" loop repeating is no desired.

xfpd,
I pulled the "else" line but it behaves like before except the output is high on power on which will not work for me.

hallowed31,

This code works better for certain but the output goes high when the button is pressed a second time,

I need the 1st input made to cause the output to go HIGH for 50ms (which I edited as you suggested) and as this mechanism retracts and touched that input button a second time the press should be ignored.
Basically alternating:

1st input press... OUTPUT HIGH for 50ms, then LOW
2nd input press... OUTPUT remains LOW
3rd input press... OUTPUT HIGH for 50ms, then LOW
4nd input press... OUTPUT remains LOW
and so on.

Thank you all for the continued assistance. I've got one more addition to this code once this hurdle is crossed. Hopefully I can figure it out on my own once I have a good outline to follow from the help you've provided.

That's because you've got it in a place where it's run every loop. Notice that the button press count only gets incremented once per press. That's because the line for that is inside the if that only runs when the state changes to pressed. That's where you want the last if else code to be.

Didn't have time to play around with it tonight but ill see about removing the "else" line to see if it will fix it.

Thank you,

Just count the inputs and act only on the odd counts.

Oh ok, didn't understand this was the thing first time around. So like this? I think I adjusted pin numbers and timing to what you're after, as well as logic vs the INPUT_PULLUP test copy I had.

const int  buttonPin = 6;    // the pin that the pushbutton is attached to
const int triggerPin = 13;
int buttonState = 0;         // current state of the button
int lastButtonState = 0;
unsigned long lastMillis = 0;
int interval = 30;
int buttonPushCounter = 0;

void setup() {
  Serial.begin(115200);
  pinMode(buttonPin, INPUT); 
  pinMode(triggerPin, OUTPUT);
  digitalWrite(triggerPin, LOW);
}

void loop() {
  unsigned long currentMillis = millis();
  buttonState = digitalRead(buttonPin);
  if (currentMillis - lastMillis >= interval) {
    lastMillis = millis();
    if (buttonState != lastButtonState) {
      buttonState = digitalRead(buttonPin);
      if (buttonState == HIGH) { // this should be HIGH for button w/ pulldown resistor
        buttonPushCounter ++;
        Serial.print("number of button pushes:  ");
        Serial.println(buttonPushCounter);
        if(buttonPushCounter % 2){
        setDevice();
        }
      }
      lastButtonState = buttonState;
    }

  }
}

void setDevice() {
  digitalWrite(triggerPin, HIGH);
  Serial.println("ON");
  delay(50); // change to the time that suits ya
  digitalWrite(triggerPin, LOW);
  Serial.println("OFF");
}

1 Like

I used @hallowed31's code and found a small matter that kept it from working well, and at the same time made a few stylistic but otherwise inconsequential changes.

Key is not reading the digital input more that once per loop.

All (I hope) my changes are marked with

//...  <-- a commented ellipsis 

So:

const int  buttonPin = 6;    // the pin that the pushbutton is attached to
const int triggerPin = 13;

bool buttonState;         //... current state of the button, true is pressed
bool lastButtonState;

unsigned long lastMillis = 0;

//... doesn't matter here, but best to use unsogned long for any timing stuff
int interval = 30;
int buttonPushCounter = 0;

void setup() {
  Serial.begin(115200);
//... pushed switch will read LOW
  pinMode(buttonPin, INPUT_PULLUP); 
  pinMode(triggerPin, OUTPUT);
  digitalWrite(triggerPin, LOW);
}

//... change this if your button is upside down (or is that right side up?)
# define PRESST LOW

void loop() {
  unsigned long currentMillis = millis();
//... make the switch read true or false
  buttonState = digitalRead(buttonPin) == PRESST;
  if (currentMillis - lastMillis >= interval) {
    if (buttonState != lastButtonState) {
//... don't read again! it could still be bouncing
//      buttonState = digitalRead(buttonPin);
      if (buttonState) { //… true is pressed, here means just got pressed 
        buttonPushCounter ++;
        Serial.print("pressed :  ");
        Serial.println(buttonPushCounter);
        if(buttonPushCounter % 2){
          setDevice();
        }
      }
    }
    //... I look for these at the end of button processing
    lastMillis = currentMillis;  //... use the current time! 
    lastButtonState = buttonState;
  }
}

void setDevice() {
  digitalWrite(triggerPin, HIGH);
  Serial.print("                 Have you tried turning it ON");
  delay(100); // change to the time that suits ya
  digitalWrite(triggerPin, LOW);
  Serial.println("  then back OFF again?");
}

a7

hallowed31,

This latest sketch you attached is working perfectly. Minor change is the "triggerPin" is 2 instead of 13. But it works right out of the box with that change.

The only addition I need to get this prototype working as designed at this stage is for the output be allowed only 5 times (triggering my the device) before the sketch delays for 20,000ms. Then normal operations resume.

I figure this could be implemented to read the OUTPUT... only allowing 5 events before the 20,000ms delay takes over. The same could be done on the INPUT but instead allowing 10 events before entering the 20,000ms delay.

alto777,

I uploaded your edited code and it is bringing the output high after release of the switch. I am limited by the consumer device I am controlling with the output. It has a 50ms debounce incorporated that I have to live with. It sees the button I have tapped into go high and will not activate the device until it goes low. The fastest this can occur is 50ms from my testing, any less delay and it wont trigger the device. Because of this, it is important that as soon as the input goes HIGH, the output does the same immediately and is applied for 50ms then back to LOW.

I appreciate the help you all have provided. I am much more familiar with mechanical design/ fabrication/ soldering/ welding/ machining than I am code. To be honest I only have a basic grasp of "if" and "else". So while this is probably childsplay for you folks I am looking at a foreign language when we are talking about button state, millis, etc. I can grasp what they mean but I dont know well enough to put these commands where they belong.

Thanks again,

This is a good thing, and explains why @hallowed31's code works well.

Using a debounced input masks any flaws in the logic that looks like it should be denouncing an input; testing the code with good old bouncy pushbutton reveals them.

Some designs use hardware debouncing, which methods would include specialized chips that can be used to handle multiple bouncing inputs and output good clean logic states to be presented to the microprocessor.

a7