Blinking LED while .mp3 is being played from SD-card

Hello there!
First of all, thanks for having clicked on my topic.

I would really appreciate some help as I am stuck since a few days with a project for a diorama. I believe it might be a relatively simple issue to solve for somebody less "newbie" than me.

I am using a Mega2560 R3 to which I attached a LED, a DFPlayer (SD-card reader) and a speaker. Basically, I want the LED to blink in the same rythm as the gunfire (latter is the audiofile on the SD-card) when pressing a button.
Both the codes for the LED and the audio file work perfectly in a seperate way, but I can't seem to combine them in a proper manner. The best I was able to do is the following code, which upon uploading plays the audio file, but when I press the button, only the LED blinks.
Also, it is intended that the LED-blinking sequence and the audio only run for one time after the button was pressed, which so far I was able to achieve.

#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
int Schalterzustand;
int InputPin = 2;
int LEDPin = 13;
void setup()
{
  Serial.begin(9600);
  pinMode(InputPin, INPUT);
  pinMode(LEDPin, OUTPUT);
  mySoftwareSerial.begin(9600);

  Serial.println();
  Serial.println(F("DFRobot DFPlayer Mini Demo"));
  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));

  if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while (true) {
      delay(0); // Code to compatible with ESP8266 watch dog.
    }
  }
  Serial.println(F("DFPlayer Mini online."));

  myDFPlayer.volume(5);  //Set volume value. From 0 to 30
  myDFPlayer.play(1);  //Play the first mp3
}

void loop() {
  Schalterzustand = digitalRead(InputPin);
  Serial.println(Schalterzustand, DEC);

  if (Schalterzustand == 1)
  {
    static unsigned long timer = millis();

    if (millis() - timer > 3000) {
      timer = millis();
      //   myDFPlayer.next();  //Play next mp3 eve
    }
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    delay(800);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    delay(1000);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    delay(3000);
  }
  if (Schalterzustand == 0)
  {
    digitalWrite(LEDPin, LOW);
  }
}

I am aware of that there are probably options to simplify the long LEDPin sequence, but that is, for now, not my priority.
The diorama is, btw for an exposition regarding the Spanish Civil War in Barcelona next Thursday. If anyone of you guys is around and up to join, please feel free to send me a message.

Thanks in advance, any kind of help is highly appreciated!!

Greetings,
Ole

I'm not sure if I understand right what you want to achieve.
IMHO the best method to describe something like that is to write down a "watching-protocol"
What would a person that is watching your Arduino see if everything works as intended?

What I understand so far is:

press a button and as soon as the button is pressed start playing the MP3-file and in parallel while the MP3-file is playing blink the LED ON/OFF as long as the MP3-file is played?

So the questions are
how long is each MP3-file?
how many different mp3-files do you want to play?

In your code there is something that should be something that starts the next mp3-file after 3 seconds.

The blink-sequence blinks for 1,4 seconds
keep LED off for 0,98 seconds
blink for 0,6 seconds
keep LED off for 1 second
blink for 3 seconds
keep LED off for 3 seconds

Does this pattern match with the audio-file?

describe a time-protocol where each time when something new starts / ends is mentioned with example-numbers

You should post code by using code-tags
There is an automatic function for doing this in the Arduino-IDE
just three steps

  1. press Ctrl-T for autoformatting your code
  2. do a rightclick with the mouse and choose "copy for forum"
  3. paste clipboard into write-window of a posting

best regards Stefan

Not clear. Do you mean the audio stops when you press the button that starts the LED, or that the button doesn't work until the audio is finished or... what?

You've commented out the "play another song in three seconds" attempt, so it is not an issue. I say attempt becuase I am too lazy to look close just now.

How is your button wired?

If you could draw a schematic or at least be very specific about the button wiring and any other components associated with the button if there are.

I have the LED blinking away, but I did tinker a bit and I am faking the DFPlayer stuff, so.

TIA

And yes, look forward to doing the whole LED flashing thing differently. But no prob now, this looks straight ahead like some trivial noob issue.

a7

Thanks for your relpy and the hint regarding the code-tags, I updated the original post accordingly.
I used the word "Schalterzustand" in my original script, which translates to "button-state" or "button-status". Hope that doesn't cause confusion.

"What I understand so far is:
press a button and as soon as the button is pressed start playing the MP3-file and in parallel while the MP3-file is playing blink the LED ON/OFF as long as the MP3-file is played?"

  • Yes, that is pretty much what I want to achieve. If everything works properly, upon pressing a button, a person would hear a series of around 15 gunshots which are accompanied by a blinking LED (it blinks once for each gunshot).

The sequence of gunshots is a single audio file, which I uploaded on a SDcard. The audio file has a total length of 7 seconds (although around the last three seconds are merely the echo of the shots). So there is only that single file that I want to be played only once every time a button is being pressed.

The pattern of the LEDs dos not match 100% with the audio file yet, but I was about to play with the delays of the LED-flashings once the audio file runs at the same time as the LEDs. Thought it might be easier that way, so no worries about that :slight_smile:

The LED-blinking works properly upon pressing the button, but I am failing to add the sound being played as well.

To achieve the sound being played, I used a code that I shamelessly stole from the following website:

The code worked fine for me (the audio file was played upon pressing the button), so I proceeded to cut out unnessasary parts until I had a reduced code (that still worked, though), which I then tried to integrate into the code that I used to make the LED blink with the intention to combine both. The result is the mess above haha.

Hey Alto777, thanks for your reply.

I described a bit more in detail my desired outcome in the answer to Stefan, i think it might be better to understand now.

Basically what I tried to explain was that only the LED-sequence runs when pressing the button. The speaker, i.e. the SDcard-reader seems not to get triggered, HOWEVER, when I upload the code above, the sound-sequence plays one time all the way through (as explained in my reply to Stefan, it's just a single sound file), but in contrary, the LED does not get triggered.
When I, then, press the button, only the LED blinks as it is supposed to do, but the sound does not play. I will try to make a video of what I mean, let's see if it's possible to upload one.

For now, I will upload a drawing of my wiring. Please don't judge, it's the first time I drew sth like this :smiley:

The MP3-player seems to need a single command to start playing.
So this should be very straight forward.

There are a few basic things that are really a must to understand about programming an Arduino:

the function setup() is executed only once after power on or a reset. And then never again until power off/on or a reset.

the function loop() is executed infinitly until you turn power off or press the reset-button.

So what the code posted above does is
play mp3-file once right after power-on
then if the button is pressed start the blinking

If everything should start with the button-press the command to start playing the MP3-file
has to be inside that code-block below the if-condition that checks for the button-press

if (Schalterzustand == 1)
  {
  // start playing the song
 // start blinking

Your required functionality is one of the really rare cases where it is sufficient to use blocking code.
The blocking comes from the delay().
In your case a longer button-press or a repeated button-press shall not re-start the playback before the initial playback has finished.

The easiest way to achive this is to use the command delay()
A visitor can press the button as long or as often as she/he/it wants.
The blocking nature of the blink-sequence makes sure that the play-back only starts if the blink-sequence has finished.

@the arduino-developper-team:
you should modify the basic examples in a way that guides newcomers to three things:
let them practically experience by demo-codes that uses serial output what

  • setup does

  • loop does

  • using functions to structure their code.

Put even the smallest two-liner into its own function. IMHO making newcomers believe
all my code has to be put into it's own function is a better guiding than putting code directly into loop.

@ole_frie
If you want to learn more about programming arduinos from scratch you could
Take a look into this tutorial:

Arduino Programming Course

It is easy to understand and has a good mixture between explaining important concepts and example-codes to get you going. So give it a try and report your opinion about this tutorial.

best regards Stefan

Here is a mistake you really should fix:

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX

So the 3 other hardware serial ports are not being used, but you are using software serial?

It may not help with your problem, but it's still always best to use hardware serial ports in preference to software serial, if you have them. Pick one of the other hardware serial ports on the mega and use that instead of software serial. For example if you choose TX2 / RX2 pins, change your code to "Serial2.xxx()" instead of "mySoftwareSerial.xxx()"

Stefan, once more, thanks a lot!

I moved the code regarding the sound-playing from the "setup" section into the "if-part" of the loop-section and the sound and the LEDblinking are now being played at the same time.

However, it works only once. In other words, after it plays one time through, even though I press the button, nothing happens.
I would appreciate a lot if you could give me a final hint to fix this issue. Also, I would be happy to invite you for a beer, if you tell me a way through which I can pay you (Paypal(?)) in order to compensate you for your time.

Thanks for the hint, Paul. I think for now I will leave is as it is, as I am scared to break anything hahaha.
But I will have it in mind the next time I try to do something like this.

Cheers!

Here is once more the now updated code:

#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
int Schalterzustand;
int InputPin = 2;
int LEDPin = 13;
void setup()
{
  Serial.begin(9600);
  pinMode(InputPin, INPUT);
  pinMode(LEDPin, OUTPUT);
}

void loop() {
  Schalterzustand = digitalRead(InputPin);
  Serial.println(Schalterzustand, DEC);

  if (Schalterzustand == 1)
  {
    mySoftwareSerial.begin(9600);
    Serial.println();
    Serial.println(F("DFRobot DFPlayer Mini Demo"));
    Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));
    if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
      Serial.println(F("Unable to begin:"));
      Serial.println(F("1.Please recheck the connection!"));
      Serial.println(F("2.Please insert the SD card!"));
      while (true) {
        delay(0); // Code to compatible with ESP8266 watch dog.
      }
    }
    Serial.println(F("DFPlayer Mini online."));

    myDFPlayer.volume(15);  //Set volume value. From 0 to 30
    myDFPlayer.play(1);  //Play the first mp3
    static unsigned long timer = millis();

    if (millis() - timer > 3000) {
      timer = millis();
      //   myDFPlayer.next();  //Play next mp3 eve
    }
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    delay(800);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    delay(1000);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    delay(3000);
  }
  if (Schalterzustand == 0)
  {
    digitalWrite(LEDPin, LOW);
  }
}

I'm not familiar with the details how to control the MP3-player

a simple call of

myDFPlayer.play(1);  //Play the first mp3

seems not to work.

This starts to become a "remotely instructed keyboard-typing"
No need for paying anything.

Without knowing almost anything about programming I would have to post some corrections you do the corrections and report back the new behaviour
repeat (this procedure for about fifty times)
I won't do that. Maybe John Wasser enjoys coding for you.

I suggest that you go reading the usermanual of how this MP3-player-module is controlled
provide a link to this manual and go googling with the keywords

arduino DFPlayer "additional words of interest"

where "additional words of interest" describes the information you are looking for.

and then come back with a new attempt and a question how this particular contro-command of what you like to have can be programmed.
best regards Stefan

Yeah, that's understandable. Thanks a lot for your great help, Stefan! I'll figure out the rest somehow :slight_smile:

That is a splendid diagram, perfectly adequate.

Pro tip: along with pens and pencils, you can get a little bottle of “white out” that is used in offices to paint over mistakes, I noticed the little piece of paper hiding something…

Anyway, the two processes are coupled, so should be triggered at the same time, got it.

+1 on @StefanL38’s advices. A bit more experience and knowledge will be valuable.

The basic idea you need to learn is to react to when a button becomes pressed, rather than to react while it is pressed.

Denouncing a button contacts is usually part of this.

This is a very basic idea and is explained and exemplified and so forth here in these fora on a daily basis.

But srsly I mainly write to say nice schematic! You def earned that merit badge.

a7

Thanks for the advices! I will look into that :slight_smile:

For anyone, who might be interested in the solution:

In the end, I included a reset function in the very beggining
void(* resetFunc) (void) = 0;

and used
resetFunc();

In the end of the LED-sequence to fix the problem. Now both, light and sound is being played every time the button is pressed :slight_smile:

Please post the entire code. What you have shared is hard to understand with no context.

TIA

a7

Sure thing, there you go :slight_smile:

#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
int Schalterzustand;
int InputPin = 2;
int LEDPin = 13;
void(* resetFunc) (void) = 0;
void setup()
{
  Serial.begin(9600);
  pinMode(InputPin, INPUT);
  pinMode(LEDPin, OUTPUT);
}

void loop() {
  Schalterzustand = digitalRead(InputPin);
  Serial.println(Schalterzustand, DEC);

  if (Schalterzustand == 1)
  {
    mySoftwareSerial.begin(9600);
    Serial.println();
    Serial.println(F("DFRobot DFPlayer Mini Demo"));
    Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));
    if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
      Serial.println(F("Unable to begin:"));
      Serial.println(F("1.Please recheck the connection!"));
      Serial.println(F("2.Please insert the SD card!"));
      while (true) {
        delay(0); // Code to compatible with ESP8266 watch dog.
      }
    }
    Serial.println(F("DFPlayer Mini online."));

    myDFPlayer.volume(30);  //Set volume value. From 0 to 30
    myDFPlayer.play(1);  //Play the first mp3
    static unsigned long timer = millis();

    if (millis() - timer > 3000) {
      timer = millis();
      //   myDFPlayer.next();  //Play next mp3 eve
    }
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    delay(800);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    delay(1000);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    digitalWrite(LEDPin, HIGH);
    delay(20);
    digitalWrite(LEDPin, LOW);
    delay(180);
    delay(3000);
    resetFunc();
  }
  if (Schalterzustand == 0)
  {
    digitalWrite(LEDPin, LOW);

  }

}

Crude and hacky. But effective, I guess.

This line, at file scope, doesn’t make any sense to me. I’ll look around, but mebbe someone cou,d hand me a fish and ‘splain this.

I assume it compikles and fixes a problem, I’m just not seeing how it does either.

a7

It creates a function pointer (named resetFunc) that points to location 0 in program memory space. Calling it -- resetFunc(); -- forces the processor execution starting at 0 and a reboot. Like I said, a hack at best.