Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 5 of 5

Thread: teensy usb footswitch button code

  1. #1
    Junior Member
    Join Date
    May 2021
    Posts
    7

    teensy usb footswitch button code

    I've got a simple (SPST) footswitch button connected to a Teensy 2.0 that I'm trying to create multiple button-press events for. I've got it working in every way but one so far (so frustrating!!). Here's what's working:

    The "short press" event sends the correct commands on the rising edge of the button (i.e. when the footswitch button has reached the top of its spring-loaded post).
    The "long press" event sends the correct commands after the button has been pressed for the correct amount of time.

    My problem is that once I let go of the button after a "long press" event, the commands for the "short press" event are sent even though I don't want them to, because the button has returned to its rising edge (it's spring-loaded, as I mentioned). Can someone help me figure this out?. I'm new at this, and this is mostly code I've cobbled together from elsewhere.

    Thanks in advance!


    Here's the code for the button:

    Here are the .h and .cpp files we've cobbled together from sample code that we found. How do we get the long press to both work and sync with the 2 devices:

    Button.h
    Code:
    #include <Arduino.h>
    #include <Bounce2.h>
    
    #ifndef Button_h
    #define Button_h
    
    #define DEBOUNCE_DELAY 10
    #define LONG_PRESS 250
    
    class Button {
    public:
      Button(int pin);
      bool update();
      bool wasPressed();
      bool wasLongPressed();
    
    private:
      Bounce *debouncer;
      long pressedAt;
      bool isActive;
      bool isLongPress;
    };
    
    #endif
    Button.cpp
    Code:
    Button::Button(int pin) {
      pinMode(pin, INPUT_PULLUP);
      debouncer = new Bounce(pin, DEBOUNCE_DELAY);
      pressedAt = 0;
      isActive = false;
      isLongPress = false;
    }
    
    bool Button::update() {
      bool didChange;
      isLongPress = false;
      didChange = debouncer->update();
      if (debouncer->fell()) {
        pressedAt = millis();
        isActive = true;
      }
      if (debouncer->rose()) {
        isActive = false;
      }
      if (isActive && (millis() - pressedAt) > LONG_PRESS) {
        isActive = false;
        isLongPress = true;
        didChange = true;
      }
      return didChange;
    }
    
    bool Button::wasPressed() {
      return debouncer->rose();
    }
    
    bool Button::wasLongPressed() {
      return isLongPress;
    }
    Footswitch.cpp
    Code:
    #include <Arduino.h>
    #include "Button.h"
    
    #define BUTTON_1 PIN_B0
    
    Button *buttons[1];
    
    void setup() {
      buttons[0] = new Button(BUTTON_1);
    }
    
    void sendMMC(uint16_t length, uint8_t* msg) {
      static uint8_t buffer[20] = { 0xf0, 0x7f, 0x7f, 0x06 };
      memcpy(buffer + 4, msg, length);
      buffer[length + 4] = 0xf7;
      usbMIDI.sendSysEx(length + 5, buffer, true);
    }
    
    void loop() {
      // PLAY START
      if (buttons[0]->update()) {
        if (buttons[0]->wasPressed()) {
          sendMMC(1, (uint8_t*)"\x02"); // Play
        }
        if (buttons[0]->wasLongPressed()) {
          sendMMC(1, (uint8_t*)"\x01"); // Stop
          sendMMC(8, (uint8_t*)"\x44\x06\x01\x00\x00\x00\x00\x00"); // Locate zero
        }
      }
    
      while (usbMIDI.read()) {} // ignore incoming messages
    }
    Last edited by ALDad; 05-03-2021 at 11:13 PM.

  2. #2
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,101
    Figure out the states you need to represent this, I think you probably need:

    IDLE
    PRESSED
    PRESSED_LONG

    Use a variable to explicitly record the current state so you can respond to the combination of current state and input
    change (or timeout).

    Then only transistions from PRESSED->IDLE trigger a short press event, whereas PRESSED->PRESSED_LONG triggers
    a long press event

  3. #3
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,687
    I think it might be a problem with this:
    Code:
    bool Button::wasPressed() {
      return debouncer->rose();
    }
    The problem is that wasPressed will return true whether this is the end of a short press or a long press. You need to modify this so that it only returns true after a short press. This might do it:
    Code:
    bool Button::wasPressed() {
      return debouncer->rose() && !isLongPress;
    }
    Pete

  4. #4
    Junior Member
    Join Date
    May 2021
    Posts
    7
    Thanks, guys!

    @MarkT, that seems promising, but I'm such a noob. Would you mind please posting your solution in line with my code, or maybe an example of how it could work?

    and Pete, your solution seems like it should TOTALLY work, but it doesn't. Do you happen to have any thoughts as to why? Or any other solutions?

  5. #5
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,101
    Quote Originally Posted by ALDad View Post
    Thanks, guys!

    @MarkT, that seems promising, but I'm such a noob. Would you mind please posting your solution in line with my code, or maybe an example of how it could work?
    I'd suggest starting with a good tutorial on state machines, this is rather lengthy but looks to be a good guide:
    https://barrgroup.com/Embedded-Syste...Driven-Systems

    This might be more accessible and gets down to examples like the classic traffic light controller:
    https://codelikethis.com/lessons/cs/state-machines

    Most interactions (formally "protocols") are coded with state machines, from mouse-clicks to ethernet packets,
    its really useful tool in the toolbox. Just the act of drawing the transition diagram will help one's understanding
    of what the behaviour needs to be.

    Your initial version of your code seemed to be a reasonable (but not-yet-working) informal state-machine,
    which was set running and later quized for the last action it detected. It might be simpler to drive things
    the other way, get the state-machine to callback directly it detects an action. It will probably be more
    readable to make the states named, and explicit, rather than implicit. enumeration types are handy for
    state names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •