teensy usb footswitch button code

Status
Not open for further replies.

ALDad

Member
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:
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
 
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
 
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?
 
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-Systems/How-To/State-Machines-Event-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.
 
Status
Not open for further replies.
Back
Top