I have put together a piece of code through suggestions on this forum that I finally go to work perfectly. When a button is pressed a relay opens then four different dfplayers play simultaneously. When one designated player (4) finishes the relay is closed and the hardware waits for another input. The only issue I found is that after a week or so the arduino freezes and you have to turn it off then back on again. I assumed that this would be easily fixable via software but I can't figure out how to do it. Every attempt I have tried to implement creates an endless loop of cycling through the restarting of the dfplayers. I don't really care if it resets after every cycle or after a certain number of cycles....It just doesn't seem to work at all for me. All I tried was the software reset. I understand that there is a way to use a jumper wire from the reset pin but I didn't know how to mesh that code with my own. I got suggestions from here but couldn't make it work. - How to Reset Arduino Programmatically
Here is my initial code:
#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
// Start 4 serial ports
SoftwareSerial mySerial1(3, 4); // RX, TX dfplayer 1
SoftwareSerial mySerial2(5, 6); // RX, TX dfplayer 2
SoftwareSerial mySerial3(7, 8); // RX, TX dfplayer 3
SoftwareSerial mySerial4(9, 10); // RX, TX dfplayer 4
// We declare variables for the 4 dfplayer
DFRobotDFPlayerMini DFPlayer1;
DFRobotDFPlayerMini DFPlayer2;
DFRobotDFPlayerMini DFPlayer3;
DFRobotDFPlayerMini DFPlayer4;
const int relayPin = 13; // Pin connected to the relay module
const int busyPin = 11; // Pin connected to the Busy pin of DFPlayer4
void setup() {
pinMode(relayPin, OUTPUT); // Set the relay pin as OUTPUT
pinMode(busyPin, INPUT); // Set the Busy pin as INPUT
// Definition of the button connected to pin 2 and GND
pinMode(2, INPUT_PULLUP);
// We initialize the 4 serial channels
mySerial1.begin(9600);
mySerial2.begin(9600);
mySerial3.begin(9600);
mySerial4.begin(9600);
// Initialize the 4 players
DFPlayer1.begin(mySerial1);
DFPlayer2.begin(mySerial2);
DFPlayer3.begin(mySerial3);
DFPlayer4.begin(mySerial4);
// set volume for dfplayers
DFPlayer1.volume(25); // Set volume value (0~30).
DFPlayer2.volume(25); // Set volume value (0~30).
DFPlayer3.volume(25); // Set volume value (0~30).
DFPlayer4.volume(10); // Set volume value (0~30).
}
void loop() {
if (digitalRead(2) == LOW) {
DFPlayer1.play(1);
DFPlayer2.play(1);
DFPlayer3.play(1);
DFPlayer4.play(1);
digitalWrite(relayPin, HIGH); // Turn on the relay module
}
delay(250); // Small delay for the players to start playing
// Check if DFPlayer4 is still playing
while (digitalRead(busyPin) == LOW) {
// Code stopped here until DFPlayer4 finishes playing.
}
digitalWrite(relayPin, LOW); // Turn off the relay module
}
The best way for your situation would be probably to set up the watchdog let say for 4 seconds.
It have to be "renewed" within this time otherwise it will cause a reset, so if the programs hangs up the watchdog will reset the Nano.
I modified the code to add a watchdog. Great suggestion. Clearly, I did something wrong. What it does now is start playing, then 8 seconds into the audio clip it starts a loud clicking which I would assume is the nano resetting but it doesn't stop playing.
#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
#include <avr/wdt.h> // Include the Watchdog Timer library
// Start 4 serial ports
SoftwareSerial mySerial1(3, 4); // RX, TX dfplayer 1
SoftwareSerial mySerial2(5, 6); // RX, TX dfplayer 2
SoftwareSerial mySerial3(7, 8); // RX, TX dfplayer 3
SoftwareSerial mySerial4(9, 10); // RX, TX dfplayer 4
// We declare variables for the 4 dfplayer
DFRobotDFPlayerMini DFPlayer1;
DFRobotDFPlayerMini DFPlayer2;
DFRobotDFPlayerMini DFPlayer3;
DFRobotDFPlayerMini DFPlayer4;
const int relayPin = 13; // Pin connected to the relay module
const int busyPin = 11; // Pin connected to the Busy pin of DFPlayer4
void setup() {
pinMode(relayPin, OUTPUT); // Set the relay pin as OUTPUT
pinMode(busyPin, INPUT); // Set the Busy pin as INPUT
// Definition of the button connected to pin 2 and GND
pinMode(2, INPUT_PULLUP);
// We initialize the 4 serial channels
mySerial1.begin(9600);
mySerial2.begin(9600);
mySerial3.begin(9600);
mySerial4.begin(9600);
// Initialize the 4 players
DFPlayer1.begin(mySerial1);
DFPlayer2.begin(mySerial2);
DFPlayer3.begin(mySerial3);
DFPlayer4.begin(mySerial4);
// set volume for dfplayers
DFPlayer1.volume(25); // Set volume value (0~30).
DFPlayer2.volume(25); // Set volume value (0~30).
DFPlayer3.volume(25); // Set volume value (0~30).
DFPlayer4.volume(10); // Set volume value (0~30).
wdt_enable(WDTO_8S); // Enable Watchdog Timer with an 8-second timeout
}
void loop() {
if (digitalRead(2) == LOW) {
DFPlayer1.play(1);
DFPlayer2.play(1);
DFPlayer3.play(1);
DFPlayer4.play(1);
digitalWrite(relayPin, HIGH); // Turn on the relay module
}
delay(250); // Small delay for the players to start playing
// Check if DFPlayer4 is still playing
while (digitalRead(busyPin) == LOW) {
// Code stopped here until DFPlayer4 finishes playing.
}
digitalWrite(relayPin, LOW); // Turn off the relay module
wdt_reset(); // Reset the Watchdog Timer to prevent reset
// Insert other code here as needed
}
In your loop function you have this while loop. If that while loop takes more than 8 seconds then the watchdog will time out. You can either keep resetting the watchdog in there or you can rewrite this so that it doesn't need to block there.
void loop() {
// Check if DFPlayer4 is still playing
if (digitalRead(busyPin) == LOW) {
// Code does nothing because DF player is playing
// But DOES NOT stop running.
} else {
digitalWrite(relayPin, LOW); // Turn off the relay module
if (digitalRead(2) == LOW) {
DFPlayer1.play(1);
DFPlayer2.play(1);
DFPlayer3.play(1);
DFPlayer4.play(1);
digitalWrite(relayPin, HIGH); // Turn on the relay module
delay(250); // if you really need this...
}
}
wdt_reset(); // Reset the Watchdog Timer to prevent reset
// Insert other code here as needed
}
That will let you reset from code. But you were describing code that is locked up. If the code is freezing up then it won't be able to execute that statement. But the watchdog will still reset the board.
Most of it just proves the thing out.
The essential lines are --
void (* resetFunc) (void) = 0; and
resetFunc();
Place void (* resetFunc) (void) = 0;
before setup() ("as per" the example).
The function call gets placed as appropriate (some criterion is met / not met and the function is called).
It's not clear, to me, why a software reset is necessary.
If you know when the freeze is coming. It sounds like the OP doesn't.
Look I'm just saying how it could be done. If it were my project I'd find out why it was freezing. I wouldn't just stick the watchdog in and hope. I'd be afraid that it meant something more.
I had a quick look at the DFPlayer Mini MP3 Player - DFRobot manual and deep in there they mention that if the device hangs up then you need to disconnect and reconnect power.
I also looked that their library and samples. The challenge therefore is whether the arduino has hung or the other hardware on the end of the serial ports has hung and then what can you do about it?
There is a timeout parameter in the DFRobot library so maybe look into that. Some means of controlling the power to the other devices may be needed (i.e. another relay to control the power to them) and code to see if they are responding is needed (as per the samples for the library) and if not then cut their power, wait a few seconds and then see if they come alive.
Good luck. Be patient. These kinds of problems are very difficult to isolate and fix.