DFPLayer + Multiple Serial Ports

Hi

I'm using a DFPLayerMini to play some audio inside an old telephone.

As I have a few of these phones I am communicating between them with Software Serial.
This makes it a little tricky as I also want to communicate with my DFplayer - so I'm doing this with the RX,TX Pins 0,1.

All of which is fine but makes it a little hard to debug my code as I build it as the DFPlayer needs the serial port and doesn't initialize if the port is connected to the USB.

All of this is probably manageable but I'm having a little trouble with the player itself.

On one device I'm running this simple code - and it's fine and playing my test mp3s.

On the other device with what should - and appears to be the same wiring - I only get a clickig playing back from the device.

The blue playing indicator comes on the same as the other but the playback is just a click. I've tried this with a couple of speakers and with a speaker that I've tested with the other player and which works fine.

I would be inclined to think maybe its a problem with the board - but since it seems there are lots of people out there that have had clicking issues I thought I'd check to see if anyone has found any solutions.

Thanks

/***************************************************
DFPlayer - A Mini MP3 Player For Arduino
 <https://www.dfrobot.com/product-1121.html>
 
 ***************************************************
 This example shows the basic function of library for DFPlayer.
 
 Created 2016-12-07
 By [Angelo qiao](Angelo.qiao@dfrobot.com)
 
 GNU Lesser General Public License.
 See <http://www.gnu.org/licenses/> for details.
 All above must be included in any redistribution
 ****************************************************/

/***********Notice and Trouble shooting***************
 1.Connection and Diagram can be found here
 <https://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299#Connection_Diagram>
 2.This code is tested on Arduino Uno, Leonardo, Mega boards.
 ****************************************************/

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

#if (defined(ARDUINO_AVR_UNO) || defined(ESP8266))   // Using a soft serial port
#include <SoftwareSerial.h>
SoftwareSerial softSerial(/*rx =*/4, /*tx =*/5);
#define FPSerial softSerial
#else
#define FPSerial Serial1
#endif

DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int value);

void setup()
{
#if (defined ESP32)
  FPSerial.begin(9600, SERIAL_8N1, /*rx =*/D3, /*tx =*/D2);
#else
  FPSerial.begin(9600);
#endif

  Serial.begin(115200);

  Serial.println();
  Serial.println(F("DFRobot DFPlayer Mini Demo"));
  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));
  
  if (!myDFPlayer.begin(FPSerial, /*isACK = */true, /*doReset = */true)) {  //Use serial 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(10);  //Set volume value. From 0 to 30
  myDFPlayer.play(1);  //Play the first mp3
}

void loop()
{
  static unsigned long timer = millis();
  
  if (millis() - timer > 10000) {
    Serial.println("playingNext");
    timer = millis();
    myDFPlayer.next();  //Play next mp3 every 3 second.
  }
  
  if (myDFPlayer.available()) {
    printDetail(myDFPlayer.readType(), myDFPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states.
  }
}

void printDetail(uint8_t type, int value){
  switch (type) {
    case TimeOut:
      Serial.println(F("Time Out!"));
      break;
    case WrongStack:
      Serial.println(F("Stack Wrong!"));
      break;
    case DFPlayerCardInserted:
      Serial.println(F("Card Inserted!"));
      break;
    case DFPlayerCardRemoved:
      Serial.println(F("Card Removed!"));
      break;
    case DFPlayerCardOnline:
      Serial.println(F("Card Online!"));
      break;
    case DFPlayerUSBInserted:
      Serial.println("USB Inserted!");
      break;
    case DFPlayerUSBRemoved:
      Serial.println("USB Removed!");
      break;
    case DFPlayerPlayFinished:
      Serial.print(F("Number:"));
      Serial.print(value);
      Serial.println(F(" Play Finished!"));
      break;
    case DFPlayerError:
      Serial.print(F("DFPlayerError:"));
      switch (value) {
        case Busy:
          Serial.println(F("Card not found"));
          break;
        case Sleeping:
          Serial.println(F("Sleeping"));
          break;
        case SerialWrongStack:
          Serial.println(F("Get Wrong Stack"));
          break;
        case CheckSumNotMatch:
          Serial.println(F("Check Sum Not Match"));
          break;
        case FileIndexOut:
          Serial.println(F("File Index Out of Bound"));
          break;
        case FileMismatch:
          Serial.println(F("Cannot Find File"));
          break;
        case Advertise:
          Serial.println(F("In Advertise"));
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }
  
}

Which Arduino board are you using ?

Uno Wifi Rev4

What exactly is connected to which pins on the Arduino ?

This is the set up.
As I mentioned it is working fine in one case and not in the other.

The DFPlayer is fed from TX & RX Pins 0 and 1 as shown.
The VCC on the DFPlayer is connected to the 5V rail on my matrix baord
The 2 SPK pins on the DFplyaer are connected to the speaker
The GND on the DFPLayer is connected to the GND rail of my matrix board.

The DFplayer appears to be on and functioning - as it is sending serial back to the arduino but when the play light is on there is just a clicking.

I've tried using a different power supply also.

Please post your sketch, using code tags when you do

In my experience the easiest way to tidy up the code and add the code tags is as follows

Start by tidying up your code by using Tools/Auto Format in the IDE to make it easier to read. Then use Edit/Copy for Forum and paste what was copied in a new reply. Code tags will have been added to the code to make it easy to read in the forum thus making it easier to provide help.

Hold on a minute !

Are you using SoftwareSerial on pins 0 and 1 ?

Oh - I thought it posted with code tags?

No - just plain old Serial

My apologies. I forgot that you had already posted your code and, yes, you did use code tags

No worries.
The code attached is just the example code which is working on one device and not the other.

My own code is a patchwork of things at the moment as I'm trying to get a few aspects of it working while I sort this out.

You mean just plain old Serial1, of course :grinning:

What happens if you swap the devices on the two serial interfaces ?

Good question - will try find out tomorrow!
Will post back.
Although as I said above the fact that teh device is sending back serial comms is maybe a sign of somthing else.

Hello

So I de-soldered the DFplayer from my main board to see if it's working on it's own.
I connected it up to a different arduino (Uno SMD).

I'm using the DFplayer basic sketch as above to cycle through the files.

So - the player is initialising and is in good serial comms with the computer. I'm using software serial on 4,5 for DFplayer comms here.

The player is cyling through the tracks and playing them - as far as it is concerned - but there is no sound on either of the little speakers I've used.

I decided to look a little closer and put an oscillioscope on the DAC outputs and get the following graphs when not playing and playing -

I then put the scope on the SPK outputs and get a very similar graph -


This suggests that perhaps the amp is not working. Any thoughts on this?

I initially was connected to an old telephone handset speaker. This seems to have been broken and I wonder if a short could have fried the amp in the DFPLayer?
I've also connected to another headphone driver - which was playing on my other (working) version and which worked but is doing nothing in this instance.

ah - I can't upload a video of the clicking sound I get when I attempt to play it.
but I can upload of the speaker output just being a noisy click (green channel) and the DAC (blue channel) being and audio signal.

So again - it would look like the playing part of the device is working but that it becomes garbled at the amp part of the circuit (I presume the DAC signal is just the pre-amp signal)

Update: Got a new player - works grand.
Looks like the amp was blown.
Hopefully something in my circuit didn't blow it.
Tom

Hi

So having a nightmare with this DFplayer (mainly because one is working fine and the other is acting up).

To summarize the set up - I've two phones - each has an arduino R4 wifi.
They are connected to each other using software serial on pins 8 and 9.
This communication is working fine.

Both arduino are connected to a DFplayer mini on pins 0 and 1. This is working fine with one player and not with the other.

Both also connect to a HBridge on pins 3 and 4 to ring the phones bell - this works fine.

One phone acts as the parent and triggers the second - they both ring if the hooks are down on both - if the hooks are not neither ring - if either phone is lifted while ringing they both stop and the lifted phone plays an mp3. If either phone is lifted outside the ring cycle they play a different track.

I have a number of switches in the code to turn off the bell, audio, serial logging, and remote logging.
Because I cannot use the serial monitor when connecting to the dfplayer I have been sending messages to the 2nd arduino where i can read them in the serial monitor.

As I said - one phone is fine the other is not.
I desoldered the dfplayer from the board and tested it with a simple circuit and it did work so theDFplayer is working.
When I put it back in my circuit it stops working.
I've checked and there are no shorts across any of the pins and so it seems like the arduino/serial/something else is causing the problem.

The code is below - but as I said it seems not to matter as the code works on the other phone

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

bool logging = true;   /////////////////////////////////// enable to print serial values
bool remoteLog = false;  //send log messages via arduinoSerial.
bool verbose = false;   //////// enable for full printing to serial
bool audio = true;      /////////////////////////////////// enable to use DF player
bool bell = false;      //// enable to activagte bell

//// serial stuff that I don't understand fully
#if (defined(ARDUINO_AVR_UNO) || defined(ESP8266))  // Using a soft serial port
#include <SoftwareSerial.h>
SoftwareSerial softSerial(/*rx =*/4, /*tx =*/5);
#define FPSerial softSerial
#else
#define FPSerial Serial1
#endif

///////// Variables for hardware connections
uint8_t hookPin = 2;  // connection to phone hook
uint8_t Ha_pin = 3;   // ConnectionA to HBridge
uint8_t Hb_pin = 4;   // ConnectionB to HBridge
uint8_t commsRX = 8;  // RX from Arduino2 TX
uint8_t commsTX = 9;  // TX to Arduino2 RX

///////////////////////////////// DFplayer
DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int value);


//////////////////////////////////////////  Variables for Arduino<->Arduino Communication
const byte numChars = 3;  //arduinoComms data size
char receivedChars[numChars];
boolean newData = false;                         //serial data received`
SoftwareSerial arduinoSerial(commsRX, commsTX);  // RX, TX for arduino comms

/////////////////////////////////  Variables for ringer cycle
const uint32_t HALF_WAVE_PERIOD = 25;  // 25mS = 20Hz
uint32_t lastHalfWaveAtMs;
uint32_t cycleStart;
bool toggle = false;
bool isSwitchOn;
uint32_t switchStateChangeAtMs;
volatile uint32_t pinChangeInterruptAtMs;


///////////////////////////////////////////// control variables
///////////////////////////////////////////// control variables

int ringDuration = 10 * 1000;  // match to other arduino
int timerGap = 1 * 30 * 1000;

bool localHook = false;
bool localHook_prev = false;

bool ringTrigger = false;
bool remoteHook = false;

int triggerTimerStart;
bool timerTrigger = false;
int ringTimerStart;
bool ringTimerActive = false;

bool audioTrigger = false;
bool bellTrigger = false;

int audioTrack = 2;

//SETUP/////SETUP////SETUP/////SETUP//////SETUP//////SETUP/////SETUP///////
///////SETUP/////SETUP////SETUP/////SETUP//////SETUP//////SETUP/////SETUP//
//SETUP/////SETUP////SETUP/////SETUP//////SETUP//////SETUP/////SETUP//////


void setup() {
#if (defined ESP32)
  FPSerial.begin(9600, SERIAL_8N1, /*rx =*/D3, /*tx =*/D2);
#else
  FPSerial.begin(9600);
#endif
  Serial.begin(9600);

  if (logging) {
    logSerial("Setup Initialised - Arduino1");
    logSerial("Logging enabled");
  }


  // delay(100);

  arduinoSerial.begin(9600);  //enable serial for arduinoCOmms
  arduinoSerial.println("<Arduino1 has connected>");
  logSerial("DFSerial & arduinoSerial enabled");

  if (remoteLog) sendChars("LL");  // send LL for end of setup


  // delay(100);

  if (audio) initDFPlayer();  //initalise DFplayer routing if audio has been enabled
  else logSerial("Sending:initDFPlayer()");


  pinMode(hookPin, INPUT);
  pinMode(Ha_pin, OUTPUT);  //set pins for HBridge
  pinMode(Hb_pin, OUTPUT);

  uint32_t ms = millis();  // set initial values for finger cycle
  lastHalfWaveAtMs = ms;
  cycleStart = ms;
  isSwitchOn = false;
  switchStateChangeAtMs = ms;
  pinChangeInterruptAtMs = ms;

  delay(ringDuration);  //delay to wait for initial ring cycle

  sendLocalValues();  //send intial states
  alignAudio();       // send at startup to ensure both phones on same track

  receivedChars[0] == 'B';

  logSerial("Setup Complete");
  if (remoteLog) {
    sendChars("L1");  // send L1 for end of setup
  }
}

///////MAIN LOOP////MAIN LOOP////MAIN LOOP////MAIN LOOP////MAIN LOOP////MAIN LOOP
//MAIN LOOP////MAIN LOOP////MAIN LOOP////MAIN LOOP////MAIN LOOP////MAIN LOOP/////
///////MAIN LOOP////MAIN LOOP////MAIN LOOP////MAIN LOOP////MAIN LOOP////MAIN LOOP


void loop() {
  unsigned long currentTime = millis();

  // if (remoteLog) sendChars("M1");  // send A1 for playing audio

  //////// Conditions

   localHook = digitalRead(hookPin);  // localHook = 1 = TRUE - Phone is ON the Hook

  recvWithStartEndMarkers();  //// Arduino Comms Receive
  parseRemote();              /// update local variables based on remote conditions
  showNewData();              /// Arduino Comms to Serial

  sendLocalValues();  //// send local values to remote

  /// timer to see if trigger ringing
  if (currentTime - triggerTimerStart > timerGap) {
    timerTrigger = true;
    triggerTimerStart = currentTime;
  }
  // if (remoteLog) sendChars("M7");  // send A1 for playing audio

  /// timer to see if ring timeer is within ring lenght
  if (currentTime - ringTimerStart < ringDuration) {
    ringTimerActive = true;
  }
  // if (remoteLog) sendChars("M8");  // send A1 for playing audio
  ////// actions

  if (timerTrigger) {    //// time to make call
    if (localHook) {     /// check if local phone is avaialble to take call
      if (remoteHook) {  /// check if remote phone is avaialble to take call
        ringTimerStart = currentTime;
        sendTrigger();  /// send trigger to phone 2
        incrementAudio();
        logSerial("Starting Ring Timer");
        // if (remoteLog) sendChars("L3");  ///send L3 for starting ring Timer
      } else logSerial("timertrigger - remote hook is up");
    } else logSerial("timertrigger - local hook is up");
  }
  // if (remoteLog) sendChars("M9");  // send A1 for playing audio

  if (ringTimerActive) {  /// ring timer is active ring bell
    if (!localHook) {     /// check if local phone has been picked up
      /// trigger local audio

      if (audio) {
        myDFPlayer.play(audioTrack);
         if (remoteLog) sendChars("A1");  
      } else {
        logSerial("Trigger Audio Track");
        logSerial(String(audioTrack));
      }
      ringTimerStart = 0;      //if picked up cancel ring timer
      bellTrigger = false;     //reset bell trigger
    } else if (!remoteHook) {  /// check if remote phone has been picked up
      ringTimerStart = 0;      /// if picked up cancel ring timer
      bellTrigger = false;     //reset bell trigger
    } else {
      if (bell) ringCycle();
      logSerial("BellRinging");
    }
  } else {
    if (!localHook) {
      if (localHook != localHook_prev)  /// check if local phone has been picked up
        if (audio) myDFPlayer.play(1);
        if (remoteLog) sendChars("A2");  
        else logSerial("Trigger Wrong Dial");
    }
  }

  // if (remoteLog) sendChars("N1");  // send A1 for playing audio


  if (audio) {  // stop any audio if phone is on hook
    if (localHook) {
      if (localHook != localHook_prev) {
        if (remoteLog) sendChars("Y7");  // send Y7 for marker here
        myDFPlayer.stop();
        // delay(100);
        // logSerial("Stopping Audio");
      }
    }
  }

  // if (remoteLog) sendChars("N2");  // send A1 for playing audio

  ringTimerActive = false;  //resetRingTimer trigger
  audioTrigger = false;     //reset audio trigger
  timerTrigger = false;     //reset timer trigger
  localHook_prev = localHook;
}

///END LOOP////END LOOP////END LOOP////END LOOP////END LOOP////END LOOP/////////
////////END LOOP////END LOOP////END LOOP////END LOOP////END LOOP////END LOOP////
///END LOOP////END LOOP////END LOOP////END LOOP////END LOOP////END LOOP/////////

void parseRemote() {
  if (receivedChars[0] == 'R') {
    // if (verbose) logSerial("remote hook is down - ready to receive - ring phone");
    remoteHook = true;  /// if remote hook is down
  } else if (receivedChars[0] == 'B') {
    // if (verbose) logSerial("remote hook is up - Busy -  do nothing");
    remoteHook = false;  /// if remote hook is up
  } else if (receivedChars[0] == 'Q') {
    audioTrack = 2;
    logSerial("audioTrack = 2");
  }
}

void sendTrigger() {
  logSerial("sendingTrigger to remote");
  arduinoSerial.print("<");
  arduinoSerial.print("T");
  arduinoSerial.println(">");
}

void sendChars(char myMsg[]) {
  arduinoSerial.print("<");
  arduinoSerial.print(myMsg);
  arduinoSerial.println(">");
}

void incrementAudio() {
  if (audioTrack < 17) {
    audioTrack++;
  } else {
    audioTrack = 2;
    alignAudio();
  }
}

void alignAudio() {
  logSerial("sendingTrigger to remote");
  arduinoSerial.print("<");
  arduinoSerial.print("Q");
  arduinoSerial.println(">");
}

void sendLocalValues() {
  if (localHook != localHook_prev) {
    logSerial("hook Changed State");
    arduinoSerial.print("<");
    arduinoSerial.print("C");
    arduinoSerial.println(">");
    if (localHook) {
      ///// hook is down ready to ring or receive calls.
      ///// hook is down = hook is true
      arduinoSerial.print("<");
      arduinoSerial.print("R");
      arduinoSerial.println(">");
    } else {
      /////// hook is up - phone is busy
      /////// hook is false
      arduinoSerial.print("<");
      arduinoSerial.print("B");
      arduinoSerial.println(">");
    }
  }
}


void printDetail(uint8_t type, int value) {

  switch (type) {
    case TimeOut:
      logSerial("Time Out!");
      break;
    case WrongStack:
      logSerial("Stack Wrong!");
      break;
    case DFPlayerCardInserted:
      logSerial("Card Inserted!");
      break;
    case DFPlayerCardRemoved:
      logSerial("Card Removed!");
      break;
    case DFPlayerCardOnline:
      logSerial("Card Online!");
      break;
    case DFPlayerUSBInserted:
      logSerial("USB Inserted!");
      break;
    case DFPlayerUSBRemoved:
      logSerial("USB Removed!");
      break;
    case DFPlayerPlayFinished:
      logSerial("Number:");
      logSerial(String(value));
      logSerial(" Play Finished!");
      break;
    case DFPlayerError:
      logSerial("DFPlayerError:");
      switch (value) {
        case Busy:
          logSerial("Card not found");
          break;
        case Sleeping:
          logSerial("Sleeping");
          break;
        case SerialWrongStack:
          logSerial("Get Wrong Stack");
          break;
        case CheckSumNotMatch:
          logSerial("Check Sum Not Match");
          break;
        case FileIndexOut:
          logSerial("File Index Out of Bound");
          break;
        case FileMismatch:
          logSerial("Cannot Find File");
          break;
        case Advertise:
          logSerial("In Advertise");
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }
}

void initDFPlayer() {
  sendChars("X");  // send X for initDFplayer
  logSerial("DFRobot DFPlayer Mini Demo");
  logSerial("Initializing DFPlayer ... (May take 3~5 seconds)");

  if (!myDFPlayer.begin(FPSerial, /*isACK = */ true, /*doReset = */ true)) {  //Use serial to communicate with mp3.
    logSerial("Unable to begin:");
    logSerial("1.Please recheck the connection!");
    logSerial("2.Please insert the SD card!");
    sendChars("X1");  // send X1 for unable to init DFPlayer
    while (true) {
      delay(0);  // Code to compatible with ESP8266 watch dog.
    }
  }
  // myDFPlayer.begin(Serial,true,true);
  logSerial("DFPlayer Mini online.");
  sendChars("L2");        // send L2 for DFplayers Initialised
  myDFPlayer.volume(15);  //Set volume value. From 0 to 30
}

void ringCycle() {
  uint32_t ms = millis();
  if (!bellTrigger) cycleStart = ms;  // prevent retrigger of cycle
  bellTrigger = true;

  // cycle is 500 ms off, 700mS on, 300mS off, 700ms on, 3300mS off
  uint32_t msIntoCycle = ms - cycleStart;
  if (verbose) logSerial(String(msIntoCycle));
  bool inRingBurst = (msIntoCycle > 300 && msIntoCycle < 1200) || (msIntoCycle > 1600 && msIntoCycle < 2500);
  if (msIntoCycle > 2500) cycleStart = ms;

  // alternate and enable/disable H-Bridge
  if (inRingBurst) {
    if (verbose) logSerial("In ring burst");
    if (ms - lastHalfWaveAtMs > HALF_WAVE_PERIOD) {
      toggle = !toggle;
      digitalWrite(Ha_pin, toggle);
      digitalWrite(Hb_pin, !toggle);
      lastHalfWaveAtMs = ms;
    }
  }
}

void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  while (arduinoSerial.available() > 0 && newData == false) {
    rc = arduinoSerial.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      } else {
        receivedChars[ndx] = '\0';  // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}

void showNewData() {

  if (newData == true) {

    logSerial("AR2: ");
    logSerial(receivedChars);
    newData = false;
    
  }
}

void logSerial(String message) {
  // Handled overhere so logging to serial can easily be switched to send to other device.
  if (logging) Serial.println(message);
  return;
}

Straight away I don't understand what you mean. In what way do the 'phones have an Arduino ?

Using pins 0 and 1 for a Serial link on most Arduinos is not a good idea. Are these hardware of software serial links ?

Remember what I said about not using pins 0 and 1 ?

I couldn't help but notice that you've connected an Arduino pin (a 5V logic level output) directly to the DFPlayer's Rx pin (a 3.3V logic level input). The datasheet recommends a 1K resistor to drop the 5V signal down to something the DFPlayer can handle without problems.

While it may have nothing to do with your current problems, it wouldn't surprise me in the least if it ended up, directly or indirectly, being the cause of them; Murphy has a mean side. Could you explain please why you've omitted the resistor?

Hi.

Thanks - yeah that's a good point. I've used the dfplayer a few times without the resistor without problem and so that is why I've continued that here.

I did test the player earlier on breadboard again without and it worked - so while you're right - I'm not sure it's the cause of my problem.