Do not read button until time is up

I'm using code to read a button with single click/double click/hold, from this older post:

It works fine except for one thing...I added an MP3 player, so that different MP3s are triggered when you single click/double click/hold. These take a few seconds each, and the code sends the command to the MP3 player and goes back to watching the button...which means that you can click the button again and interrupt the currently playing MP3, by starting one of the others. I would like the code to ignore the button until the MP3 is done playing.

I've timed the different MP3s so I know how long they play. I can't quite figure out the logic for a non-blocking "ignore until time up" command.

// Single press, double press and hold button
// https://forum.arduino.cc/t/single-double-and-hold-button/42601

// Note: Original code was set up for pull-down resistors, I swapped it to
// use internal pullups.

// DY MP3 player
#include <Arduino.h>
#include "DYPlayerArduino.h"
#include <SoftwareSerial.h>
#define ARDUINO_RX 7   // (Optional) should connect to TX of the Serial MP3 Player module
#define ARDUINO_TX A5  //  connect to RX of the module
SoftwareSerial mp3Serial(ARDUINO_RX, ARDUINO_TX);
DY::Player player(&mp3Serial);  // Initialize on Software Serial port

const int button = A2;
const int led = 13;

int bounceTime = 50;   // Originally 50
int holdTime = 250;    // Originally 250
int doubleTime = 500;  // Originally 500

int lastReading = HIGH;
int hold = 0;
int single = 0;
int LEDstate = 0;

long onTime = 0;
long lastSwitchTime = 0;


void setup() {
  pinMode(button, INPUT_PULLUP);
  pinMode(led, OUTPUT);
  digitalWrite(led, LOW);
  Serial.begin(9600);

  // DY MP3 player
  player.begin();
  player.setEq(DY::Eq::Rock);  // Rock is best-sounding for small speakers
  player.setVolume(15);        // 0 - 30, 30 is full

   Serial.println("Ready");
}

void loop() {

  int reading = digitalRead(button);

  //first pressed
  if (reading == LOW && lastReading == HIGH) {
    onTime = millis();
  }

  //held
  if (reading == LOW && lastReading == LOW) {
    if ((millis() - onTime) > holdTime) {
      invertLED();
      hold = 1;
    }
  }

  //released
  if (reading == HIGH && lastReading == LOW) {
    if (((millis() - onTime) > bounceTime) && hold != 1) {
      onRelease();
    }
    if (hold == 1) {
      Serial.println("held");    // Held and released
      digitalWrite(led, LEDstate);
      player.playSpecified(12);  // MP3 12 - 5250
      hold = 0;
    }
  }
 // lastReading = reading;  // This was in the wrong spot, needed to be at the end of the loop

  if (single == 1 && (millis() - lastSwitchTime) > doubleTime) {
    Serial.println("single press");
    player.playSpecified(11);  // MP3 11 - 3400
    single = 0;
  }
  lastReading = reading;
}


void onRelease() {

  if ((millis() - lastSwitchTime) >= doubleTime) {
    single = 1;
    lastSwitchTime = millis();
    return;
  }

  if ((millis() - lastSwitchTime) < doubleTime) {
    toggleLED();
    Serial.println("double press");
    player.playSpecified(13);   // MP3 13 - 1500
    single = 0;
    lastSwitchTime = millis();
  }
}

void toggleLED() {
  if (LEDstate == 0) {
    LEDstate = 1;
  } else {
    LEDstate = 0;
  }
  digitalWrite(led, LEDstate);
}

void invertLED() {
  if (LEDstate == 0) {
    digitalWrite(led, 1);
  } else {
    digitalWrite(led, 0);
  }
}


What player do you use the dfplayer?

I'm using the one in the first post:

Library is here:

I see, but in this case it's the same, both have the "busy" pin.
In your case the pin marked as "com3" goes LOW while the player is playing.
Bind that pin to a free pin, declare it as IMPUT and add to your ifs a new condition " && digitalRead (com3) == LOW ". and removes everything concerning conometring timing.

Thanks, that was it. Current code below.
Note that the original code has some odd handling of the LEDs, that will need to be updated.

// Single press, double press and hold button, with MP3 player

// DY MP3 player
#include <Arduino.h>
#include "DYPlayerArduino.h"
#include <SoftwareSerial.h>
#define ARDUINO_RX 7   // (Optional) should connect to TX of the Serial MP3 Player module
#define ARDUINO_TX A5  //  connect to RX of the module
SoftwareSerial mp3Serial(ARDUINO_RX, ARDUINO_TX);
DY::Player player(&mp3Serial);  // Initialize on Software Serial port

const int busyPin = 3;
const int button = A2;
const int led = 13;

int bounceTime = 50;   // Originally 50
int holdTime = 250;    // Originally 250
int doubleTime = 500;  // Originally 500

int lastReading = HIGH;
int hold = 0;
int single = 0;
int LEDstate = 0;

long onTime = 0;
long lastSwitchTime = 0;


void setup() {
  pinMode(button, INPUT_PULLUP);
  pinMode(led, OUTPUT);
  pinMode(busyPin, INPUT);
  digitalWrite(led, LOW);
  Serial.begin(9600);

  // DY MP3 player
  player.begin();
  player.setEq(DY::Eq::Rock);  // Rock is best-sounding for small speakers
  player.setVolume(15);        // 0 - 30, 30 is full

  Serial.println("Ready");
}

void loop() {

  int reading = digitalRead(button);
  int busyState = digitalRead(busyPin);

  //first pressed
  if (reading == LOW && lastReading == HIGH && busyState == LOW) {
    onTime = millis();
  }

  //held
  if (reading == LOW && lastReading == LOW && busyState == LOW) {
    if ((millis() - onTime) > holdTime) {
      invertLED();
      hold = 1;
    }
  }

  //released
  if (reading == HIGH && lastReading == LOW && busyState == LOW) {
    if (((millis() - onTime) > bounceTime) && hold != 1) {
      onRelease();
    }
    if (hold == 1) {
      Serial.println("held");  // Held and released
      digitalWrite(led, LEDstate);
      player.playSpecified(12);  // MP3 12 - 5250
      hold = 0;
    }
  }
  // lastReading = reading;  // This was in the wrong spot, needed to be at the end of the loop

  if (single == 1 && (millis() - lastSwitchTime) > doubleTime && busyState == LOW) {
    Serial.println("single press");
    toggleLED();
    player.playSpecified(11);  // MP3 11 - 3400
    single = 0;
  }
  lastReading = reading;
  digitalWrite(led, LOW);
}


void onRelease() {

  if ((millis() - lastSwitchTime) >= doubleTime) {
    single = 1;
    lastSwitchTime = millis();
    return;
  }

  if ((millis() - lastSwitchTime) < doubleTime) {
    toggleLED();
    Serial.println("double press");
    player.playSpecified(13);  // MP3 13 - 1500
    single = 0;
    lastSwitchTime = millis();
  }
}

void toggleLED() {
  if (LEDstate == 0) {
    LEDstate = 1;
  } else {
    LEDstate = 0;
  }
  digitalWrite(led, LEDstate);
}

void invertLED() {
  if (LEDstate == 0) {
    digitalWrite(led, 1);
  } else {
    digitalWrite(led, 0);
  }
}

I'm sorry, I think I didn't explain myself well before, the con3 pin goes LOW when it is playing, so its button can only work when that pin is HIGH,

To do this, in your new code you must change your LOW to HIGH.
Or maybe the trick is to add to your old code the following line as the first line of the loop:

while (digitalRead (busyPin) == LOW); // Standing here until the playback stops

I think that's an error in the docs - they say that the Busy pin outputs 0V when playing and 3.3V when waiting. But it's the opposite, I even used a multimeter to verify.

Here's someone who did the same thing:

If you have tried it, nothing to object to, the code in post#5 is correct, does it work?
Try adding the line at the beginning of the loop:

while (digitalRead (busyPin) == HIGH); // Standing here until the playback stops

You will avoid adding the condition to each "if" reading the button.

Thanks, that makes things easier!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.