2 DFMini mp3 players not working

I have 2 DFmini MP3 players attached to one Nano. This is not my first MP3 project, but it is the first with 2 players.
I can only get one or the other to play when I don't start the other one.
Both players will start and return the message that they have started, and the two "delay loops" will run. When the sketch reaches the point where it is to play the selected file, the sketch locks up.

If I start only one player and run only its respective "delay loop" that player will play.

As you can see in the attached code,

  • I have included the libraries "SoftwareSerial.h" and "DFRobotDFPlayerMini.h" and
  • I have declared two different players and SoftwareSerial serials.
  • I have resistors (1K) on both the TX and RX pins. This is something I have always done with my mp3 projects. It might be overkill, but it works for me.
  • I use the "busy pin" of the player to get feed back from the player. I have tried commenting that part out and the sketch still locks up.

Has anyone run into this issue, and if so, how did you fix it?

Thank you in advance,
Maxairedale

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

#define SM true
#define BusyPin_1 12
#define BusyPin_2 13
#define rxPin_1 10  // pin 3 on player 1 with 1K resistor
#define txPin_1 11  // pin 2 on player 1 with 1K resistor
#define rxPin_2 8   // pin 3 on player 2 with 1K resistor
#define txPin_2 9   // pin 2 on player 2 with 1K resistor

DFRobotDFPlayerMini Mp3Player1;
SoftwareSerial MySerial_1(rxPin_1, txPin_1);

DFRobotDFPlayerMini Mp3Player2;
SoftwareSerial MySerial_2(rxPin_2, txPin_2);

unsigned long player_1_loopDelay = 0;
unsigned long player_1_PreviousMillis;
unsigned long player_2_loopDelay = 0;
unsigned long player_2_PreviousMillis;
int player_1_fileNumber;
int player_2_fileNumber;
int Player_1_lastPlayed = 0;
int Player_2_lastPlayed = 0;


void setup() {
  Serial.begin(9600);
  pinMode(BusyPin_1, INPUT);
  pinMode(BusyPin_2, INPUT);
  startPlayer_1();
  startPlayer_2();
}

void loop() {
  Player_1_delayLoop();
  Player_2_delayLoop();
}

void startPlayer_1() {
  Serial.println("Starting Player 1");
  MySerial_1.begin(9600);
  if (!Mp3Player1.begin(MySerial_1)) {
    Serial.println("Player 1 Did Not Start");
    while (true)
      ;
  }
  Mp3Player1.setTimeOut(500);                   // Set Serial communictaion time out 500ms
  Mp3Player1.volume(30);                        // Set volume value (0~30).
  Mp3Player1.EQ(DFPLAYER_EQ_BASS);              // Set EQ to BASS (normal/pop/rock/jazz/classic/bass)
  Mp3Player1.outputDevice(DFPLAYER_DEVICE_SD);  // Set device we use SD as default
  Mp3Player1.enableDAC();
  Serial.println("Player 1 Online");
}
void startPlayer_2() {
  Serial.println("Starting Player 2");
  MySerial_2.begin(9600);
  if (!Mp3Player2.begin(MySerial_2)) {
    Serial.println("Player 2 Did Not Start");
    while (true)
      ;
  }
  Mp3Player2.setTimeOut(500);                   // Set Serial communictaion time out 500ms
  Mp3Player2.volume(30);                        // Set volume value (0~30).
  Mp3Player2.EQ(DFPLAYER_EQ_BASS);              // Set EQ to BASS (normal/pop/rock/jazz/classic/bass)
  Mp3Player2.outputDevice(DFPLAYER_DEVICE_SD);  // Set device we use SD as default
  Mp3Player2.enableDAC();
  Serial.println("Player 2 Online");
}

void Player_1_delayLoop() {
  if (player_1_loopDelay == 0) {
    player_1_PreviousMillis = millis();
    player_1_loopDelay = 10000;
  }
  unsigned long player_1_CurrentMillis = millis();
  while (player_1_CurrentMillis - player_1_PreviousMillis >= player_1_loopDelay) {
    pick_player_1_Sound();
    player_1_loopDelay = 0;
    break;
  }
  player_1_CurrentMillis = millis();
  Serial.println("Player1 loop delay");
}

void Player_2_delayLoop() {
  if (player_2_loopDelay == 0) {
    player_2_PreviousMillis = millis();
    player_2_loopDelay = 30000;
  }
  unsigned long player_2_CurrentMillis = millis();
  while (player_2_CurrentMillis - player_2_PreviousMillis >= player_2_loopDelay) {
    pick_player_2_Sound();
    player_2_loopDelay = 0;
    break;
  }
  player_2_CurrentMillis = millis();
  Serial.println("Player2 loop delay");
}

void pick_player_1_Sound() {
  randomSeed(analogRead(0));
  player_1_fileNumber = random(1, 13);
  while (player_1_fileNumber == Player_1_lastPlayed) {  // prvents playing same file as before
    randomSeed(analogRead(0));
    player_1_fileNumber = random(1, 13);
  }
  Player_1_lastPlayed = player_1_fileNumber;
  play_Player1();
}

void play_Player1() {
  Mp3Player1.play(player_1_fileNumber);
  int x = digitalRead(BusyPin_1);
  while (x == 1) {
    x = digitalRead(BusyPin_1);
  }

  delay(250);
  while (x == 0) {
    Serial.print("Playing File # ");
    Serial.println(player_1_fileNumber);
    x = digitalRead(BusyPin_1);
  }
  if (x == 1) {
    player_1_loopDelay = 0;
  }
}


void pick_player_2_Sound() {
  randomSeed(analogRead(0));
  player_2_fileNumber = random(1, 38);
  while (player_2_fileNumber == Player_2_lastPlayed) {  // prvents playing same file as before
    randomSeed(analogRead(0));
    player_2_fileNumber = random(1, 38);
  }
  Player_2_lastPlayed = player_2_fileNumber;
  play_Player2();
}

void play_Player2() {
  Mp3Player2.play(player_2_fileNumber);
  int x = digitalRead(BusyPin_2);
  while (x == 1) {
    x = digitalRead(BusyPin_2);
  }

  delay(250);
  while (x == 0) {
    Serial.print("Playing File # ");
    Serial.println(player_2_fileNumber);
    x = digitalRead(BusyPin_2);
  }
  if (x == 1) {
    player_2_loopDelay = 0;
  }
}

It looks like you enter while() loops, and only exit when the sound is complete. Write a one-DFPlayer sketch that plays a file while blinking LED_BUILTIN. That will show you if the audio routine is blocking.

Maybe not as fun as your two-way async comms, but I/O Mode only needs short grounding of the "Next/Prev" pin to start a file.

What do you see on serial monitor just before and when that happens?

With both players started and both delay loops running, I see,
"Player1 loop delay"
"Player2 loop delay"
repeatedly until the first loop passes the need delay time, which is 10 seconds in the sketch as I provided it.

I think the problem is that neither pick_player_1_Sound() or pick_player_1_Sound() are ever called.

I suggest you add some Serial.println() lines at the start of those functions to see if my theory is correct.

If I'm right, see if you can figure out why they are not called.

The while loop continues until the conditions are met, which is when the player_1_CurrentMillis - player_1_PreviousMillis >= player_1_loopDelay

while (player_1_CurrentMillis - player_1_PreviousMillis >= player_1_loopDelay) {
pick_player_1_Sound();
player_1_loopDelay = 0;
break;
}

At that point, it jumps out of the loop and picks one of the 12 sounds ( player_1_fileNumber = random(1, 13)) for player1 to play. I have printed that number to the screen after modifying the code I provided.
It is when it attempts to play the file that it locks up. That is when both players have started, and one or both delay loops are being used.

At the point, it jumps out of the loop and picks one of the 12 sounds ( player_1_fileNumber = random(1, 13)) for player1 to play. I have printed that number to the screen after modifying the code I provided.
It is when it attempts to play the file that it locks up. That is when both players have started, and one or both delay loops are being used.

No, that's not what a while loop does :slight_smile:

You are correct.

I misspoke there; it jumps into the while loop when the conditions are met by the constant rerunning of the delay loop by the loop() portion of the sketch. When it has met the conditions where the current millis minus the previous millis is a greater value than the loop delay millis ("player_1_CurrentMillis - player_1_PreviousMillis >= player_1_loopDelay" ), the code within the while loop is activated. and the break stops the while loop.

Is it truly a loop if it only ever loops 1 time? Why not simply use an if statement?

That is a valid point.

But that is not the problem I'm having. Those delay loop functions work with the while inside them.

The issue is that when both dfplayers are initialized, the players will not play.

Not the cause of your problem, of course, but yes, it is overkill. The second 1k resistor to the DFR TX is unnecessary. In fact that connection itself may sometimes be redundant.

I’ve never tried playing two DFR modules simultaneously. I’m curious; what’s the application?

I didn’t see what Arduino device you’re using? Do you have one - perhaps a Mega2560- with hardware serial pins you can try instead ?

Yes, I get the problem. I've read through your code several times now trying to figure out why. Your code is very difficult to read and follow. Using while loops that can only ever loop once because they have a break inside them, when it's normal to use an if statement, doesn't make the code any easier to understand!

One theory I have is that the problem could be something related to using 2 software serial ports. The Arduino can only ever receive on one port or the other, and it's important to use the .listen() method to tell the Arduino which port to expect data to arrive on, and your code isn't using that method. However, because of the commands you are using to control the players, I don't think the players will ever send any data anyway. So I can't think exactly how using 2 software serial ports is causing an actual problem right now.

As I suggested earlier, try adding more Serial.println() statements to the various functions so you can see what functions are getting called, or not getting called. Hopefully this will help figure out why the code appears to be hanging.

As to the application, I have two spots on a model railroad that I wish to put some sound in.

  1. A swamp/pond where I will be playing frog sounds and other critters.
  2. A railroad yard where idling locomotives are parked.

I am using an Arduino Nano (knock off)

Try I/O Mode.

What will the nano contribute in each location? Could the frogs be croaking permanently, using a realistic recording? Or triggered by simple reed relays or micro switches. Leaving you needing only the single nano for possibly more complex triggering at the sidings.

The frog recording(s) could be managed using the inbuilt IO pins (9 and 11) and ADKEY 1 (pin 12). Read up on the details and come back when you have some code and a wiring diagram.

There are 12 different swamp sounds and 37 locomotive sounds.
My code is in my first post. A wiring diagram is coming.

After reading and rereading the replies, I have

  1. Modified the sketch (see code below) by
  2. Changing the while loop that was being run only one time to an "if"
  3. Added "Serial.print()" and "Serial.println()" calls
  4. Merged different functions to make a total of 4 functions
    • 2 functions that start the two players which are called in the "setup()" area
    • 2 loop delay functions that are in the main "loop()"

Here is the wiring diagram

Here is a screenshot of the serial monitor and where the sketch stops when both players are started (Serial.println("attempting to play player 1");) is at line 60 in the sketch

This is the serial monitor when only player 1 is started

After the sound is played, the delay loops start being displayed again.

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

#define BusyPin_1 12
#define BusyPin_2 13
#define rxPin_1 10  // pin 3 on player 1 with 1K resistor
#define txPin_1 11  // pin 2 on player 1 with 1K resistor
#define rxPin_2 8   // pin 3 on player 2 with 1K resistor
#define txPin_2 9   // pin 2 on player 2 with 1K resistor

DFRobotDFPlayerMini Mp3Player1;
SoftwareSerial MySerial_1(rxPin_1, txPin_1);

DFRobotDFPlayerMini Mp3Player2;
SoftwareSerial MySerial_2(rxPin_2, txPin_2);

unsigned long player_1_loopDelay = 0;
unsigned long player_1_PreviousMillis;
unsigned long player_2_loopDelay = 0;
unsigned long player_2_PreviousMillis;
int player_1_fileNumber;
int player_2_fileNumber;
int Player_1_lastPlayed = 0;
int Player_2_lastPlayed = 0;


void setup() {
  Serial.begin(9600);
  pinMode(BusyPin_1, INPUT);  // PIN 12 ON NANO
  pinMode(BusyPin_2, INPUT);  // PIN 13 ON NANO

  startPlayer_1();
  startPlayer_2();
  
}

void loop() {
  Player_1_delayLoop();
  Player_2_delayLoop();
}

/* delay loops follow */

void Player_1_delayLoop() {
  if (player_1_loopDelay == 0) {
    player_1_PreviousMillis = millis();
    player_1_loopDelay = 10000;
  }
  unsigned long player_1_CurrentMillis = millis();
  if (player_1_CurrentMillis - player_1_PreviousMillis >= player_1_loopDelay) {
    randomSeed(analogRead(0));
    player_1_fileNumber = random(1, 13);
    while (player_1_fileNumber == Player_1_lastPlayed) {  // prvents playing same file as before
      randomSeed(analogRead(0));
      player_1_fileNumber = random(1, 13);
    }
    Serial.print("Player 1 file number = ");
    Serial.println(player_1_fileNumber);
    Player_1_lastPlayed = player_1_fileNumber;
    Serial.println("attempting to play player 1");
    Mp3Player1.play(player_1_fileNumber);
    int x = digitalRead(BusyPin_1);
    while (x == 1) {
      x = digitalRead(BusyPin_1);
    }

    delay(250);
    while (x == 0) {
      Serial.print("Playing File # ");
      Serial.println(player_1_fileNumber);
      x = digitalRead(BusyPin_1);
    }
    if (x == 1) {
      player_1_loopDelay = 0;
    }
  }
  player_1_CurrentMillis = millis();
  Serial.println("Player1 loop delay");
}

/* end of delay loop 1 */

void Player_2_delayLoop() {
  if (player_2_loopDelay == 0) {
    player_2_PreviousMillis = millis();
    player_2_loopDelay = 30000;
  }
  unsigned long player_2_CurrentMillis = millis();
  if (player_2_CurrentMillis - player_2_PreviousMillis >= player_2_loopDelay) {
    randomSeed(analogRead(0));
    player_2_fileNumber = random(1, 38);
    while (player_2_fileNumber == Player_2_lastPlayed) {  // prvents playing same file as before
      randomSeed(analogRead(0));
      player_2_fileNumber = random(1, 38);
    }
    Serial.print("Player 2 file number = ");
    Serial.println(player_2_fileNumber);
    Player_2_lastPlayed = player_2_fileNumber;
    Serial.println("attempting to play player 2");
    Mp3Player2.play(player_2_fileNumber);
    int x = digitalRead(BusyPin_2);
    while (x == 1) {
      x = digitalRead(BusyPin_2);
    }

    delay(250);
    while (x == 0) {
      Serial.print("Playing File # ");
      Serial.println(player_2_fileNumber);
      x = digitalRead(BusyPin_2);
    }
    if (x == 1) {
      player_2_loopDelay = 0;
    }
  }
  player_2_CurrentMillis = millis();
  Serial.println("Player2 loop delay");
}
/* end of delay loop 2 */



/* player startups follow */

void startPlayer_1() {
  Serial.println("Starting Player 1");
  MySerial_1.begin(9600);
  if (!Mp3Player1.begin(MySerial_1)) {
    Serial.println("Player 1 Did Not Start");
    while (true)
      ;
  }
  Mp3Player1.setTimeOut(500);                   // Set Serial communictaion time out 500ms
  Mp3Player1.volume(30);                        // Set volume value (0~30).
  Mp3Player1.EQ(DFPLAYER_EQ_BASS);              // Set EQ to BASS (normal/pop/rock/jazz/classic/bass)
  Mp3Player1.outputDevice(DFPLAYER_DEVICE_SD);  // Set device we use SD as default
  Mp3Player1.enableDAC();
  Serial.println("Player 1 Online");
}
void startPlayer_2() {
  Serial.println("Starting Player 2");
  MySerial_2.begin(9600);
  if (!Mp3Player2.begin(MySerial_2)) {
    Serial.println("Player 2 Did Not Start");
    while (true)
      ;
  }
  Mp3Player2.setTimeOut(500);                   // Set Serial communictaion time out 500ms
  Mp3Player2.volume(30);                        // Set volume value (0~30).
  Mp3Player2.EQ(DFPLAYER_EQ_BASS);              // Set EQ to BASS (normal/pop/rock/jazz/classic/bass)
  Mp3Player2.outputDevice(DFPLAYER_DEVICE_SD);  // Set device we use SD as default
  Mp3Player2.enableDAC();
  Serial.println("Player 2 Online");
}

Thanks for looking at this mess,
Maxairedale

Please do not post screen shots of the serial monitor. Copy the text from serial monitor and paste it into your post between code tags.

More Serial.println() needed!

    Serial.println("attempting to play player 1");
    Mp3Player1.play(player_1_fileNumber);
    int x = digitalRead(BusyPin_1);
    while (x == 1) {
      x = digitalRead(BusyPin_1);
    }

Either the code is stuck in .play() method, or x remains 1 forever. Use more Serial.println() to figure out which it is.