Help with understanding the example code of a Serial MP3 player module.

Hi fellow Arduino'ers :slight_smile:
I recently took up arduino, and bought a kit of different components. Now I have finished all of the beginners' tutorials and I am beginning to make some projects on my own. My main reason for wanting to learn Arduino, was to be able to make a cloud sculpture complete with lightning and speakers inspiration from this guy. Until now, I have been able to get the "lightning" running pretty decently, but my newest addition is causing me troubles. It's a MP3 serial player module (bought on dx.com). I have trouble understanding the example code, and I was wondering if you guys could help me a bit? I can make it play the mp3 files on my SD card (following the code), but I don't know how to control it further than that. Help me understand what 0X0F01 etc. means :slight_smile:

Test example:

#include <SoftwareSerial.h>

#define ARDUINO_RX 5//should connect to TX of the Serial MP3 Player module
#define ARDUINO_TX 6//connect to RX of the module
SoftwareSerial mySerial(ARDUINO_RX, ARDUINO_TX);

static int8_t Send_buf[8] = {0} ;

#define CMD_PLAY_W_INDEX 0X03
#define CMD_SET_VOLUME 0X06
#define CMD_SEL_DEV 0X09
 #define DEV_TF 0X02
#define CMD_PLAY 0X0D
#define CMD_PAUSE 0X0E
#define CMD_SINGLE_CYCLE 0X19
 #define SINGLE_CYCLE_ON 0X00
 #define SINGLE_CYCLE_OFF 0X01
#define CMD_PLAY_W_VOL 0X22

void setup() 
{
mySerial.begin(9600);
delay(500);//Wait chip initialization is complete
   sendCommand(CMD_SEL_DEV, DEV_TF);//select the TF card  
delay(200);//wait for 200ms
sendCommand(CMD_PLAY_W_VOL, 0X0F01);//play the first song with volume 15 class
}
void loop() 
{

}

void sendCommand(int8_t command, int16_t dat)
{
 delay(20);
 Send_buf[0] = 0x7e; //starting byte
 Send_buf[1] = 0xff; //version
 Send_buf[2] = 0x06; //the number of bytes of the command without starting byte and ending byte
 Send_buf[3] = command; //
 Send_buf[4] = 0x00;//0x00 = no feedback, 0x01 = feedback
 Send_buf[5] = (int8_t)(dat >> 8);//datah
 Send_buf[6] = (int8_t)(dat); //datal
 Send_buf[7] = 0xef; //ending byte
 for(uint8_t i=0; i<8; i++)//
 {
   mySerial.write(Send_buf[i]) ;
 }
}

Hi,
Can you please edit your post using code tags?
They are made with the </> icon in the reply Menu.
See section 7 http://forum.arduino.cc/index.php/topic,148850.0.html

Doing this will get ride of the smiley in the middle of your sketch.

Tom.... :slight_smile:

Thx Tom.
Now it's done!

Do you have any tips for me regarding the code? :slight_smile:

Hi,
Is it this one?

A quick search google MP3 serial player catalex

http://202.146.210.146/forum/forum_posts.asp?TID=7319

pan.baidu.com/s/1hqilpB2#path=%252FSerial%2520MP3%2520Player a manual.

Tom... :slight_smile:
Got to g to work, but will look in later.

Hi Tom.

Yes, that's the one!
The manual you've linked is great, however it does not clear things for me :slight_smile:
Like how do I use the "command bytes", or what this part of the arduino code does:

void sendCommand(int8_t command, int16_t dat)
{
 delay(20);
 Send_buf[0] = 0x7e; //starting byte
 Send_buf[1] = 0xff; //version
 Send_buf[2] = 0x06; //the number of bytes of the command without starting byte and ending byte
 Send_buf[3] = command; //
 Send_buf[4] = 0x00;//0x00 = no feedback, 0x01 = feedback
 Send_buf[5] = (int8_t)(dat >> 8);//datah
 Send_buf[6] = (int8_t)(dat); //datal
 Send_buf[7] = 0xef; //ending byte
 for(uint8_t i=0; i<8; i++)//
 {
   mySerial.write(Send_buf[i]) ;
 }

Basically I'm not understanding the code. I'm used to all of the code taking place in the void loop part, but
in this case, there is so much more going on.
Is there some site or guide I can read, for understanding the logic of the test example?

Sorry for all the questions, I'm just eager to learn more about this :slight_smile:

Kind Regards

I can make it play the mp3 files on my SD card (following the code),

I don't see any code there for an SD card , is the SD connected to the arduino or directly connected to the device ?

What is going on there, is that the arduino is sending 8-byte serial messages to the device. The format and contents of those messages would be defined by the device. You would need some kind of documentation for the device to understand all of the possible commands that the device might have.

There are two meaningful components of your command message to the device.

The first is the "command", and the available commands would appear to be shown by the #define's. The second is the "data", which is a number which would mean different things for different commands.

The 0x0F01 means a 2-byte integer, with the hexadecimal value 0F01. From the context, it appears that this 16 bit data value is actually two separate bytes stuck together. The first byte is 0F, which is hexadecimal for 15, and has something to do with volume. The second byte is 01, which is hexadecimal for 1, and means play the first file, apparently.

If you want to play the second file on the SD card, try changing 0x0f01 to 0x0F02, and see what you get.

I'm used to all of the code taking place in the void loop part, but

The reason for this, is you only want to tell the device what to start doing once, you don't want to tell it what to do, millions of times, which is what would happen if you put that code into loop( ).

Do you have any tips for me regarding the code?

TomGeorge has found the manual. It's not that good, but I suggest you read it.

The obstacle I perceive you will have with this device, is that although there is a field for "feedback", there is no information about it. The communication between the arduino and the device all one-way.

In particularly, there seems to be no way for the arduino to ask the device if the track is finished yet, in order to ask for a different one.

Hey Michinyon.
Thank you for taking the time explaining this for me.
To answer your question, the micro SD card slot is located on the mp3 player module.
It seems (from the manual) that you are also able to play specific tracks on the SD card.

But you are right in that it's tricky to understand the feedback mechanism.

Have I understood it right, that if the command: CMD_PLAY_W_VOL, 0X1E01, would play the first song at volume 30 then? Because 30 = 1E in hexadecimal?

If you were to implement the mp3-capabilities in the void loop, how would you do it?
The cloud I'm making will be controlled via an infrared remote, triggering different functions.
Would this work?:

if (digitalRead=some specific IR code){

*some lightning show* and then
sendCommand(CMD_SEL_DEV, DEV_TF);             //select the TF card  
delay(100);//wait for 200ms
sendCommand(CMD_PLAY_W_VOL, 0X0F0random(10));       //play a random song out of 9 songs (15Vol)
delay(15000);                  //delay for 15 seconds, making sure the lightning sound has been played

}

It just seems so rough, because I have to use the delay function.
I would love to be able to make some moodlightning while sound is playing (like the continous sound of rain mixed with small flashes and lightning).

Sorry for the wall of text. :slight_smile:

Kind Regards

Hi there.....

same Problem here... got an Catalex YX5300 MP3 Board ..... using this Demo_Sketch

/***********************************************************/
// Demo for the Serial MP3 Player Catalex (YX5300 chip)
// Hardware: Serial MP3 Player *1
// Board:  Arduino UNO
// http://www.dx.com/p/uart-control-serial-mp3-music-player-module-for-arduino-avr-arm-pic-blue-silver-342439#.VfHyobPh5z0 
//
// 
//


// Uncomment SoftwareSerial for Arduino Uno or Nano.  

#include <SoftwareSerial.h>

#define ARDUINO_RX 5  //should connect to TX of the Serial MP3 Player module
#define ARDUINO_TX 6  //connect to RX of the module

SoftwareSerial mp3(ARDUINO_RX, ARDUINO_TX);
//#define mp3 Serial3    // Connect the MP3 Serial Player to the Arduino MEGA Serial3 (14 TX3 -> RX, 15 RX3 -> TX)

static int8_t Send_buf[8] = {0}; // Buffer for Send commands.  // BETTER LOCALLY
static uint8_t ansbuf[10] = {0}; // Buffer for the answers.    // BETTER LOCALLY

static int8_t pre_vol, volume = 0x0f; // Volume. 0-30 DEC values. 0x0f = 15. 

String mp3Answer;           // Answer from the MP3.   

boolean playing = false;    // Sending 'p' the module switch to Play to Pause or viceversa.   

/************ Command byte **************************/
#define CMD_NEXT_SONG     0X01  // Play next song.
#define CMD_PREV_SONG     0X02  // Play previous song.
#define CMD_PLAY_W_INDEX  0X03
#define CMD_VOLUME_UP     0X04
#define CMD_VOLUME_DOWN   0X05
#define CMD_SET_VOLUME    0X06

#define CMD_SNG_CYCL_PLAY 0X08  // Single Cycle Play.
#define CMD_SEL_DEV       0X09
#define CMD_SLEEP_MODE    0X0A
#define CMD_WAKE_UP       0X0B
#define CMD_RESET         0X0C
#define CMD_PLAY          0X0D
#define CMD_PAUSE         0X0E
#define CMD_PLAY_FOLDER_FILE 0X0F

#define CMD_STOP_PLAY     0X16
#define CMD_FOLDER_CYCLE  0X17
#define CMD_SHUFFLE_PLAY  0x18 //
#define CMD_SET_SNGL_CYCL 0X19 // Set single cycle.

#define CMD_SET_DAC 0X1A
  #define DAC_ON  0X00
  #define DAC_OFF 0X01
  
#define CMD_PLAY_W_VOL    0X22
#define CMD_PLAYING_N     0x4C

/************ Opitons **************************/  
#define DEV_TF            0X02  
#define SINGLE_CYCLE_ON   0X00
#define SINGLE_CYCLE_OFF  0X01


/*********************************************************************/

void setup() 
{
  Serial.begin(9600);
  mp3.begin(9600);
  delay(500);
                                          
        sendCommand(CMD_SEL_DEV, DEV_TF);  
  delay(200);
//  sendCommand(CMD_PLAY_W_VOL, 0X0F28); // Playing a 15 (0x0F) Vol the song num 40 (0x28). 
}


void loop() 
{
 char c=' ';
  
  // If there a char on Serial call sendMP3Command to sendCommand
   if( Serial.available() )
    {
    c = Serial.read();
    sendMP3Command(c);
    }
    
  // Check for the answer.
  if (mp3.available())
  {
    Serial.println(decodeMP3Answer());
  }
  delay(100);
}

 
/********************************************************************************/
/*Function sendMP3Command: seek for a 'c' command and send it to MP3  */
/*Parameter: c. Code for the MP3 Command, 'h' for help.                                                                                                         */
/*Return:  void                                                                */

void sendMP3Command(char c){
    switch (c) {
    case '?':
    case 'h':
          Serial.println("HELP  ");
          Serial.println(" p > Play / Pause ");
          Serial.println(" n > Next");          
          Serial.println(" b > Previous");
          Serial.println(" u > Volume UP");
          Serial.println(" d > Volume DOWN");
      break;
                 
     
      case 'p':
          if(!playing){
            Serial.println("Play ");
            sendCommand(CMD_PLAY_W_VOL, 0X0F01);//play the first song with volume 15 class
            sendCommand(CMD_SNG_CYCL_PLAY, 0);
            //sendCommand(CMD_PLAY, 0);
            playing = true;
          }else{
            Serial.println("Pause");
            sendCommand(CMD_PAUSE, 0);
             playing = false;           
          }
      break;

      
      case 'n':
          Serial.println("Next");
          sendCommand(CMD_NEXT_SONG, 0);
          sendCommand(CMD_PLAYING_N, 0x0000); // ask for the number of file is playing
      break;
      
      
      case 'b':
          Serial.println("Previous");
          sendCommand(CMD_PREV_SONG, 0);
          sendCommand(CMD_PLAYING_N, 0x0000); // ask for the number of file is playing
      break;
     
      case 'u':
          Serial.println("Volume Up");
          sendCommand(CMD_VOLUME_UP, 0);
      break;

      case 'd':
          Serial.println("Volume Down");
          sendCommand(CMD_VOLUME_DOWN, 0);
      break;
      case 'k':
          Serial.println("single");
          sendCommand(CMD_SNG_CYCL_PLAY, 0);
      break;
    }
}


 
/********************************************************************************/
/*Function decodeMP3Answer: Decode MP3 answer.                                  */
/*Parameter:-void                                                               */
/*Return: The                                                  */

String decodeMP3Answer(){
  String decodedMP3Answer="";
  
      decodedMP3Answer+=sanswer(); 
      
    //  if (ansbuf[3] == 0x4C) // currently planying
    //  {
    //    decodedMP3Answer+=" -> Playing: "+String(ansbuf[6],DEC);
    //  }
      
     switch (ansbuf[3]) {
      case 0x3A:
         decodedMP3Answer+=" -> Memory card inserted.";
         break; 
         
      case 0x3D:
         decodedMP3Answer+=" -> Completed play num "+String(ansbuf[6],DEC);
         break; 
         
      case 0x4C:
         decodedMP3Answer+=" -> Playing: "+String(ansbuf[6],DEC);
         break;
      
      case 0x41:
         decodedMP3Answer+=" -> Data recived correctly. ";
         break;     
     } 
      
   return decodedMP3Answer;
 }  


 
 


/********************************************************************************/
/*Function: Send command to the MP3                                         */
/*Parameter:-int8_t command                                                     */
/*Parameter:-int16_ dat  parameter for the command                              */

void sendCommand(int8_t command, int16_t dat)
{
  delay(20);
  Send_buf[0] = 0x7e;   //
  Send_buf[1] = 0xff;   //
  Send_buf[2] = 0x06;   // Len 
  Send_buf[3] = command;//
  Send_buf[4] = 0x01;   // 0x00 NO, 0x01 feedback
  Send_buf[5] = (int8_t)(dat >> 8);  //datah
  Send_buf[6] = (int8_t)(dat);       //datal
  Send_buf[7] = 0xef;   //
  for(uint8_t i=0; i<8; i++)
  {
    mp3.write(Send_buf[i]) ;
  }
  
}



/********************************************************************************/
/*Function: sbyte2hex. Returns a byte data in HEX format.                 */
/*Parameter:- uint8_t b. Byte to convert to HEX.                                */
/*Return: String                                                                */


String sbyte2hex(uint8_t b)
{
  String shex;
  
  //Serial.print("0x");
  shex="0X";
  
  //if (b < 16) Serial.print("0");
  if (b < 16) shex+="0";
  //Serial.print(b, HEX);
  shex+=String(b,HEX);
  //Serial.print(" ");
  shex+=" ";
  return shex;
}




/********************************************************************************/
/*Function: sanswer. Returns a String answer from mp3 UART module.          */
/*Parameter:- uint8_t b. void.                                                  */
/*Return: String. If the answer is well formated answer.                        */

 String sanswer(void)
{
  uint8_t i = 0;
  String mp3answer="";
  
 // Get only 10 Bytes
 while(mp3.available() && (i < 10))
  {
    uint8_t b = mp3.read();
    ansbuf[i] = b;
    i++;
   
    //Serial.print(sbyte2hex(b));
    mp3answer+=sbyte2hex(b);
  }
 
  //Serial.println();
 
  // if the answer format is correct.
  if ((ansbuf[0] == 0x7E) && (ansbuf[9] == 0xEF))
  {
    //return true;
    return mp3answer;
  }
 
  //return false;
  return "???: "+mp3answer;
}

trying to Play Audiofiles in Random Order (ShuffflePlay).

Trying this command lines:

case 's':
          Serial.println("Shuffle");
          sendCommand(CMD_SHUFFLE_PLAY, 0);
          sendCommand(CMD_PLAYING_N, 0x0000); // ask for the number of file is playing
      break;

but nothing happend.

Please Help to get my YX5300 to Play mp3 in random Order.

Thanks alot.....

To use each command you send the appropriate bits to the command, for example:

Serial.println("Increasing Volume");
sendCommand(0x04,0x00);

Serial.println("Previous track");
sendCommand(0x02,0x00);

The commands are listed in the manual: http://geekmatic.in.ua/pdf/Catalex_MP3_board.pdf

To play a specific track you the final command sent should be 7E FF 06 03 00 00 01 EF where the final 01 is the track number, you could therefore randomise the final number to get a shuffle effect. The command for playing the track would look like:

Serial.println("Playing track 2");
sendCommand(0x04,0x02);

To make it random change the 0x02 to a variable, and use a randomiser within limits to set that variable.

int randTrackNo;
randTrackNo = random(0, 13);
sendCommand(0x03,randTrackNo);
Serial.print("Playing track:");
Serial.println(randTrackNo);

Obviously this all requires the sendCommand function to work:

void sendCommand(int8_t command, int16_t dat)
{
  delay(20);
  Send_buf[0] = 0x7e; //starting byte
  Send_buf[1] = 0xff; //version
  Send_buf[2] = 0x06; //the number of bytes of the command without starting byte and ending byte
  Send_buf[3] = command; //
  Send_buf[4] = 0x00;//0x00 = no feedback, 0x01 = feedback
  Send_buf[5] = (int8_t)(dat >> 8);//datah
  Send_buf[6] = (int8_t)(dat); //datal
  Send_buf[7] = 0xef; //ending byte
  for(uint8_t i=0; i<8; i++)//
  {
    mySerial.write(Send_buf[i]) ;
  }
}

This looks really helpful for what I am trying to do, which is play a random MP3 from the Catalex board when a distance sensor is set off. I am using the code and circuit listed here - Arduino Project Hub - and it is working perfectly. As a newbie, I can't work out hos tyo adapt your random code above to work with my current code - any suggestions?

ee0u30eb:
To make it random change the 0x02 to a variable, and use a randomiser within limits to set that variable.

int randTrackNo;

randTrackNo = random(0, 13);
sendCommand(0x03,randTrackNo);
Serial.print("Playing track:");
Serial.println(randTrackNo);




Obviously this all requires the sendCommand function to work:



void sendCommand(int8_t command, int16_t dat)
{
  delay(20);
  Send_buf[0] = 0x7e; //starting byte
  Send_buf[1] = 0xff; //version
  Send_buf[2] = 0x06; //the number of bytes of the command without starting byte and ending byte
  Send_buf[3] = command; //
  Send_buf[4] = 0x00;//0x00 = no feedback, 0x01 = feedback
  Send_buf[5] = (int8_t)(dat >> 8);//datah
  Send_buf[6] = (int8_t)(dat); //datal
  Send_buf[7] = 0xef; //ending byte
  for(uint8_t i=0; i<8; i++)//
  {
    mySerial.write(Send_buf[i]) ;
  }
}