Question about "delay()"

Status
Not open for further replies.

ALDad

Member
Hiya, folks!
I've got a footswitch button connected to my Teensy 2.0 and this code is working beautifully, except for one thing: I'd like the "PLAY START" function to start a few milliseconds after the button's been pressed. I'm very, VERY new at this, but from my research it seems like "delay()" is the simplest and best option for me. However, no matter where I place that code, it doesn't work the way I need it to. I've tried putting "delay(1000)" beneath almost every line in the code (see below), one line at a time, and either:
  • nothing happens,
  • the target will play immediately, go for 1 second and then stop (whereas I *want* it to wait for 1 second and then START playing), or
  • I can see that the target is receiving a message of some kind (an indicator light flashes) 1 second after the button is pressed, but then nothing else happens (no play start, etc.).

All of the above seems to only depend on where the "delay(1000)" code is placed, but I can't make heads nor tails of it. I know I'm missing something; this seems like it should be really simple. Is anyone able to lend a noob like me a hand with this?

TIA!

Here's the code:

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() {
  if (buttons[0]->update()) {
  // PLAY START
    if (buttons[0]->wasPressed()) {
      sendMMC(1, (uint8_t*)"\x02"); // Play
    }
  // RESET
    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
}
 
Code:
  // PLAY START
    if (buttons[0]->wasPressed()) {
      //            [B]<----  Try adding the delay here![/B]
      sendMMC(1, (uint8_t*)"\x02"); // Play
    }
 
Thanks, Paul! Unfortunately though, when I add the delay there all that happens is that I can see that the target is receiving a message of some kind (an indicator light flashes) 1 second after the button is pressed, but then nothing else happens (no play start, etc.). Do you have any thoughts as to why that might be?
 
Thanks, Paul! Unfortunately though, when I add the delay there all that happens is that I can see that the target is receiving a message of some kind (an indicator light flashes) 1 second after the button is pressed, but then nothing else happens (no play start, etc.). Do you have any thoughts as to why that might be?

@ALDad:

Posting your modified sketch (see Forum Rule above) would make it much easier for anyone else to analyze why it might not be working as you expect.

So, without benefit of the modified sketch, I'll propose a slightly different approach: since you only want either the short-press or the long-press to be detected with each release of the button, maybe you could try this (which, if my thinking is right, *should* allow a long-press to take precedence over a short-press):

Code:
void loop() {
  if (buttons[0]->update()) {
    // check if long-press (RESET) has been detected
    if (buttons[0]->wasLongPressed()) {
      sendMMC(1, (uint8_t*)"\x01"); // Stop
      sendMMC(8, (uint8_t*)"\x44\x06\x01\x00\x00\x00\x00\x00"); // Locate zero
    } else {
      // if a long-press was NOT detected, then check if a short-press (PLAY START) has been detected
      if (buttons[0]->wasPressed()) {
        // if you want a short delay before the PLAY command is sent, then add your call to delay() here (as Paul previously indicated)
        sendMMC(1, (uint8_t*)"\x02"); // Play
      }
    }
  }
  
  while (usbMIDI.read()) {} // ignore incoming messages
}
 
Try to place a delay(1000) both directly and after before sending the play message.
 
Try to place a delay(1000) both directly and after before sending the play message.

Thanks so much, mlu! It works... sort of. Here's my code:

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() {
  if (buttons[0]->update()) {
  // PLAY START
    if (buttons[0]->wasPressed()) {
    delay(1000);  //<---- THIS IS WHERE I ADDED DELAY
      sendMMC(1, (uint8_t*)"\x02"); // Play
    delay(4000);  //<---- THIS IS WHERE I ADDED DELAY
    }
  // RESET
    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
}

What happens now is that it waits to start playback for 1 second, and then plays for 4 seconds. That's actually fine. The problem is that now the long-press also waits for 4 seconds to work and I need that delay to be much shorter, or none at all. I've tried adding more delay() lines before, after, and both before AND after the "sendMMC" lines in the RESET code, but nothing changes. I've also tried delay() lines ONLY in the RESET code (before and after the "sendMMC" lines, but NOT in the PLAY START code). I think @kd5rxt-mark is right in that I need to somehow separate the different presses more, but unfortunately that code didn't work either.

Any other thoughts?
 
What Button library are you using?

Here's the Button.cpp I'm using (borrowed code):

Code:
#include "Button.h"

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->fell();
}

bool Button::wasLongPressed() {
  return isLongPress;
}


...and Button.h (also borrowed):

Code:
#include <Arduino.h>
#include <Bounce2.h>

#ifndef Button_h
#define Button_h

#define DEBOUNCE_DELAY 10
#define LONG_PRESS 613

class Button {
public:
  Button(int pin);
  bool update();
  bool wasPressed();
  bool wasLongPressed();

private:
  Bounce *debouncer;
  long pressedAt;
  bool isActive;
  bool isLongPress;
};

#endif
 
Ok, this is using Bounce in the background. AFAIK you are supposed to call update as often as possible. Your delays (where you don't update the buttons) might confuse the debounce algorithm.

You can try to place a

Code:
void yield()
{
  buttons[0]-> update()
}

after your loop() function. This will call buttons[0]->update() while delay spins. Best to use the version Paul recommended in #2.

BTW: If you want to get quick help it is always a good idea to post everything needed to reproduce your problem. E.g. you now sent the button.cpp but the button.h is still missing to reproduce your problem....

EDIT: Sorry, must have overlooked button.h in your post
 
Played a bit with your code. The problem is that "wasPressed" is true for a short press and a long press which makes detecting a long press somehow difficult. I changed your button class to be able to distinguish between a short and a long press which makes using it more easy:

button.h
Code:
#include <Arduino.h>
#include <Bounce2.h>

#ifndef Button_h
#define Button_h

#define DEBOUNCE_DELAY 10
#define LONG_PRESS 613

class Button {
public:
  Button(int pin);
  bool update();
  bool wasLongPressed();
  bool wasShortPressed();

  private:
  Bounce *debouncer;
  long pressedAt;
  bool isLongPress;
};

#endif

button.cpp
Code:
#include "Button.h"

Button::Button(int pin)
{
    pinMode(pin, INPUT_PULLUP);
    debouncer   = new Bounce(pin, DEBOUNCE_DELAY);
    pressedAt   = 0;
    isLongPress = false;
}

bool Button::update()
{
    if (debouncer->update())
    {
        if (debouncer->fell())
        {
            pressedAt = millis();
            return false;
        }
        if (debouncer->rose())
        {
            isLongPress = millis() - pressedAt > LONG_PRESS;
            return true;
        }
    }
    return false;
}

bool Button::wasShortPressed()
{
    return !isLongPress;
}

bool Button::wasLongPressed()
{
    return isLongPress;
}

In your sketch I replaced your MMC calls by simple printouts to visualize what happens.
Code:
#include "Arduino.h"
#include "Button.h"

#define BUTTON_1 0

Button* buttons[1];

void setup()
{
    buttons[0] = new Button(BUTTON_1);
}

void loop()
{
    if (buttons[0]->update())
    {
        // PLAY START
        if (buttons[0]->wasShortPressed())
        {
            // sendMMC(1, (uint8_t*)"\x02"); // Play
            Serial.println("short press detected, now waiting");
            delay(1000);
            Serial.println("Play");
        }
        else if (buttons[0]->wasLongPressed()) // RESET
        {
            Serial.println("RESET");
            // 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
}

Works here (T3.2) without issue. I don't have a T2 for testing but I assume that the code should also run on a T2. Hope that fits your needs
 
Status
Not open for further replies.
Back
Top