• @Gordon's code implements an state machine with two states and dynamic behavior: press false and true and timer driven return to false.

    A very first 'spike' transitions from false to true, executes the application function (invert and apply LED state), AND becomes unresponsive - ignores any pin state changes - for the next 100ms and then flips automatically back to state false. Returning to state false puts it back into responsive state.

    'Unfortunately', it implements only half of 'the world'. With this setup of repeat: true, holding the switch for longer than 100ms AND THEN releasing it, creates another trigger of the application function: invert and apply LED state. This means that a press longer than 100ms switches twice the LED. (Yellow(?) LED goes either on for the pressed time or off.

    To verify this - I assume - unintended behavior with - PICO or Legacy - on-board components BTN1 and LED1, load and run this code... and you notice: it is difficult to toggle LED1 (ledrougestate... ;-) ). You have press the button for less than 100ms, which is more like a 'gentle hitting' / tapping:

    var ledjaunestate = false;
    var press = false;
    // pinMode(B10, 'input_pullup');
    pinMode(BTN1, 'input_pulldown');
    setWatch(function() {
      if (press) return;
      press=true;
      setTimeout(function(){press=false;},100)­;
      ledjaunestate = !ledjaunestate;
    //  digitalWrite(B10, ledjaunestate);
      digitalWrite(LED1, ledjaunestate);
    // }, B10, { repeat: true, edge: "both" });
    }, BTN1, { repeat: true, edge: "both" });
    

    The code has some more (inherent) flaws: press the button for more than 100ms, then release it for less than 100ms with - finally - pressing it for A) more or B) less than 100ms, you get a toggle or a double toggle. Not necessarily the expected UX.

    To (partially) complete the state machine, setting of press to false has to be conditioned similarly to the setting to true. Before 'the LED switch' - accepts a new trigger, the triggering button has to return to its original state for a defined time. To achieve a SINGLE LED switch for ONE PRESS OF ANY DURATION of the button, the state of the button has to be tested (repeatedly) and only if the button has (solidly, after a defined time) switched to off, press is set back to false.

    var ledjaunestate = false;
    var press = false;
    // pinMode(B10, 'input_pullup');
    pinMode(BTN1, 'input_pulldown');
    function resetPressOnBtnOff() {
      // if/then/else specific to BTN1's pulldown
      if (digitalRead(BTN1)) {
        setTimeout(resetPressOnBtnOff, 60);
      } else {
        press = false;
      }
    }
    setWatch(function() {
      if (press) return;
      press=true;
    //  setTimeout(function(){press=false;},100)­;
      setTimeout(resetPressOnBtnOff, 100);
      ledjaunestate = !ledjaunestate;
    //  digitalWrite(B10, ledjaunestate);
      digitalWrite(LED1, ledjaunestate);
    // }, B10, { repeat: true, edge: "both" });
    }, BTN1, { repeat: true, edge: "both" });
    

    A cleaned up version of the code (for BTN1):

    var ledredstate = false;
    var pressed = false;
    pinMode(BTN1, 'input_pulldown');
    function resetPressedOnBtn1Off() {
      if (digitalRead(BTN1)) {
        setTimeout(resetPressedOnBtn1Off, 60);
      } else {
        pressed = false;
      }
    }
    setWatch(function() {
      if (pressed) return;
      pressed = true;
      setTimeout(resetPressedOnBtn1Off, 100);
      ledredstate = !ledredstate;
      digitalWrite(LED1, ledredstate);
    }, BTN1, { repeat: true, edge: "rising" });
    

    Note the edge: "rising" option. No need for both...

    Even though the button test is added, there is still a 'window of opportunity' for a jitter: when the button is released about the time of the pin test, a bouncing may be experienced...

    Furthermore, there are still inherent flaws: between the repeated testing of the button state, the user can have - after some decent press time - released, pressed very briefly, and released the button again, and that action gets lost. Since by experience mechanical button presses are usually longer than 100ms, choosing shorter interval makes it work... something between the (button's typical) bouncing (time) and the 100ms. If it is shorter than the (button's typical) bouncing (time), unpredictable behavior creeps in again.

    Therefore, only making the state machine switching symmetrical makes it more predictable... It boils down to the UX specifications: Presses and releases of a switch have to be pressMs and releaseMS* in order to reliably detect and execute a toggle.

    Debouncing is not a simple task... and buttons with consistent and short bouncing avoid to make it worse... (the buttons picked - as described in post #14 - seem to be decent... except you got a 'lemon' or 'monday' or 'friday late' lot version...)

    PS: Looks like a toggle module could come in handy to take the tedious work off of the hand of the application...

About

Avatar for allObjects @allObjects started