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);
}
}
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.