[SOLVED] One shot momentary switch edge detection trigger

With the below, I obtain "1" as long as the momentary switch button is depressed, but I want to obtain a "1" only once every time the button is pressed and switchState goes LOW, and "0" if it were held down after, whether for half a second or much longer. How would I have to change the code?

What for? I am TXing the value of nodeTX.momentaryswitch to RX and, if RX constantly receives more than one "1" per button press on TX, a tone() function at RX would be repeatedly triggered, if the button were held in the depressed state, something I want to avoid. In other words, one button press on TX shall trigger one 50 millisecond sound on RX, even when the button on TX is held down after being pressed.

void readMomentarySwitch()
{
  byte switchState = digitalRead (pinSwitch);

  if (switchState != lastSwitchState)
  {
    lastSwitchState = switchState;

    if (switchState == LOW)
    { // TX a 1
      nodeTX.momentaryswitch = true;
    }
    else
    {
      // TX a 0
      nodeTX.momentaryswitch = false;
    }
  }
}

Look at the State Change Detection example sketch in the IDE.

Thanks, but with that code, buttonState or a flag bool in the if-else statement constantly evaluates to either 0 or 1 also, for as long as the momentary switch button is held down, while the Serial.println statements execute only once either on LOW and HIGH. What am I missing?

Lagom:
Thanks, but with that code, buttonState or a flag bool in the if-else statement constantly evaluates to either 0 or 1 also, for as long as the momentary switch button is held down, while the Serial.println statements execute only once either on LOW and HIGH. What am I missing?

That's because the transition from OFF to ON triggers the "on" to be printed. The transition from ON to OFF triggers the "off" to be printed. The comparison to the last button state results in the if code block only being entered once per transition.

Lagom:
What for? I am TXing the value of nodeTX.momentaryswitch to RX and, if RX constantly receives more than one "1" per button press on TX, a tone() function at RX would be repeatedly triggered, if the button were held in the depressed state, something I want to avoid. In other words, one button press on TX shall trigger one 50 millisecond sound on RX, even when the button on TX is held down after being pressed.

You need to add a debounce delay in the if code block. Also only set the flag to true on an off to on transition like this:

void readMomentarySwitch()
{
  byte switchState = digitalRead (pinSwitch);

  nodeTX.momentaryswitch = false;
  if (switchState != lastSwitchState)
  {
    lastSwitchState = switchState;

    if (switchState == LOW)
    { // TX a 1
      nodeTX.momentaryswitch = true;
    }
    delay(50);
  }
}

In your loop() just check the flag after you call readMomentarySwitch() and if the flag is true then trigger one 50 millisecond sound. Even if someone holds the button down the flag will remain false until someone releases and presses the button again.

Thanks, I'm debouncing the button with a capacitor. A delay() in the code will interfere with the TX code.

I need a "one shot" functionality, like a camera shutter button in single shot mode, so I TX only a single "1" upon pressing the button down, otherwise always a "0".

As I have it now, the nodeTX.momentaryswitch struct variable is "latched" to true while the button is held down, like with a camera's B setting, which I don't want in my case.

I figured it out.

In loop(), after readMomentarySwitch() and the TX code, I set nodeTX.momentaryswitch = false; and so I only ever send a single "1" to RX, also in case the momentary switch button is pressed and held down.

Lagom:
Thanks, I’m debouncing the button with a capacitor. A delay() in the code will interfere with the TX code.

That is a misconception. A properly written debounce routine returns results immediately upon THE FIRST change of state. It is only subsequent transitions that have to wait for the debounce delay to complete.

However, it is better practice to implement the delay using the millis() timer, instead of delay() so that other code in the loop() won’t block.

Thanks, no debounce code or delays needed though. The oscilloscope shows a nice trace with the capacitor debouncing method as described in Nick Gammon's switches discussion/tutorial. It was simply a question of where to set nodeTX.momentaryswitch to false.

Lagom:
I figured it out.

In loop(), after readMomentarySwitch() and the TX code, I set nodeTX.momentaryswitch = false; and so I only ever send a single "1" to RX, also in case the momentary switch button is pressed and held down.

My version would have done the same but I'm glad you got it working.

Thanks ToddL1962, I'm grateful for any input that helps.