Catalex MP3 Player QUestions

I am new to Arduino, and I am trying to use the Catalex mp3 player module (Manual) to play through a folder of mp3s while at the same time allowing me to interrupt the playback of files in folder 01 with a button that plays a file in folder 02 and then resuming playback of the track that was being played in folder 01.

I can get the module to play, pause, skip, go back, and I can get it to play the sound file in the second folder when I push the button, and I can get it to resume playback of files in folder 01. But I can’t get it to resume playback of the track it was playing prior to pushing the horn button. I would also like to have the module display the actual song name rather than just what file it is on, but I am not sure how to do it.

My code is a combination of code from here, here, and here.

I’m sure there is a better/easier way to do what I already have done, and if so please show me where!

Here is my code: I tried to comment on what I had done/copied. I am also including pictures of the SD card folder structure and file names in each folder. Any tips/help/improvement of my current code will be greatly appreciated.

#include <SoftwareSerial.h>
#include <SD.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);
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
# define Start_Byte 0x7E
# define Version_Byte 0xFF
# define Command_Length 0x06
# define End_Byte 0xEF
# define Acknowledge 0x00 //Returns info with command 0x41 [0x01: info, 0x00: no info]

# define ACTIVATED HIGH

int buttonHorn = 2;
int buttonPause = 3;
int buttonPrevious = 7;
int buttonNext = 8;
boolean isPlaying = false;


/************Command byte**************************/
#define CMD_NEXT_SONG 0X01
#define CMD_PREV_SONG 0X02
#define CMD_PLAY_W_INDEX 0X03
#define CMD_VOLUME_UP 0X04
#define CMD_VOLUME_DOWN 0X05
#define CMD_SET_VOLUME 0X06
#define CMD_SINGLE_CYCLE_PLAY 0X08
#define CMD_SEL_DEV 0X09
#define DEV_TF 0X02
#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_SINGLE_CYCLE 0X19
#define SINGLE_CYCLE_ON 0X00
#define SINGLE_CYCLE_OFF 0X01
#define CMD_SET_DAC 0X1A
#define DAC_ON  0X00
#define DAC_OFF 0X01
#define CMD_PLAY_W_VOL 0X22
#define CMD_FOUND_NUM_FILES 0x48
#define CMD_CURRENT_TRACK 0X4C
#define CMD_FOUND_FOLDER 0X4F

int potPin = A0;
int potVal;
float last;
int track;

void setup() {
  Serial.begin(9600);
  mp3.begin (9600);

  pinMode(buttonPause, INPUT);

  pinMode(buttonNext, INPUT);

  pinMode(buttonPrevious, INPUT);

  pinMode(buttonHorn, INPUT);

  delay(500);


  sendCommand(CMD_SEL_DEV, DEV_TF); //Selects SD card
  delay(200);
  sendCommand(DAC_ON, 0X00); // I turned DAC on, but I have no idea what it does
  delay(200);
  sendCommand(CMD_FOUND_NUM_FILES, 0X48); // Detects number of files on card
  delay(200);
  playFirst();

  isPlaying = true;

  last = millis();
}
static int8_t pre_vol = 0x0f;

void loop() {
  potVal = analogRead(potPin);
  int8_t volume;

  volume = map(potVal, 0, 1023, 0, 30); // Potentiometer controls volume
  if (volume != pre_vol)
  {
    sendCommand(CMD_SET_VOLUME, volume);
    pre_vol = volume;
  }
  delay(100);

  if (mp3.available()) //Returns commands, and determines what file is being played
  {
    if ( answer ( ) )
    {
      if ( ansbuf [ 3 ] == 0x4c ) // currently playing
      {
        Serial. print ( "currently playing file " ) ;
        Serial.println(ansbuf[6] - 1); // had to add -1 to get it to display a 1 for file 1 in folder 01. It reads a 0 for file001 in folder 02. Any idea why?
        track = (ansbuf[6] - 1); //I tried storing the value of ansbuf[6] thinking i could use it to return to the file I was playing, but it changes when I play the horn file.

      }
    }
  }
  if ( ( millis ( ) - last ) > 5000 ) // We ask every 5 sec
  {
    last = millis();
    sendCommand ( 0x4c , 0X0000 ) ; // Ask for the number of the file being played
  }


  if (digitalRead(buttonPause) == ACTIVATED)
  {
    Serial.println("Button is pressed");
    if (isPlaying)
    {
      pause();
      isPlaying = false;
    }
    else
    {
      isPlaying = true;
      play();
    }
  }


  if (digitalRead(buttonNext) == ACTIVATED)
  {
    Serial.print("Next");
    if (isPlaying)
    {
      playNext();
    }
  }

  if (digitalRead(buttonPrevious) == ACTIVATED)
  {
    Serial.print("Prev");
    if (isPlaying)
    {
      playPrevious();
    }
  }
  if (digitalRead(buttonHorn) == ACTIVATED)
  {
    Serial.print("horn");
    horn();
  }


}

void playFirst()
{

  sendCommand(CMD_FOLDER_CYCLE, 0X0100);
  delay(200);
}

void pause()
{
  sendCommand(CMD_PAUSE, 0X0E);
  delay(200);
}

void play()
{ sendCommand(CMD_PLAY, 0X0D);
  delay(200);
}

void playNext()
{
  sendCommand(CMD_NEXT_SONG, 0X01);
  delay(200);

}

void playPrevious()
{
  sendCommand(CMD_PREV_SONG, 0X02);
  delay(200);
}

void setVolume(int volume)
{
  sendCommand(CMD_SET_VOLUME, volume); // Set the volume (0x00~0x30)
  delay(200);
}
void horn() //This is my attempt at the horn interrupt. It will pause and play the horn sound, but wont return to the previous track from folder 01
{
  sendCommand(CMD_PAUSE, 0X0E);
  delay(200);

  sendCommand(CMD_PLAY_FOLDER_FILE, 0X0201);
  delay(100);

  sendCommand(0X01, track);

}
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]) ;
  }
}
void byte2hex(uint8_t b)
{
  Serial.print("0x");
  if (b < 16) Serial.print("0");
  Serial.print(b, HEX);
  Serial.print(" ");
}

// Function to retrieve answers
boolean answer(void)
{
  uint8_t i = 0;

  // Get only 10 bytes
  while (mp3.available() && (i < 10))
  {
    uint8_t b = mp3.read();
    ansbuf[i] = b;
    i++;
    byte2hex(b);
  }

  Serial.println();

  // If the correct response format
  if ((ansbuf[0] == 0x7E) && (ansbuf[9] == 0xEF))
  {
    return true;
  }

  return false;
}

SD Card Folders.JPG

  pinMode(buttonPause, INPUT);

  pinMode(buttonNext, INPUT);

  pinMode(buttonPrevious, INPUT);

  pinMode(buttonHorn, INPUT);

You need to tell us how the switches are actually wired (unless you really sewed buttons on, in which case don't bother).

  if (mp3.available()) //Returns commands, and determines what file is being played

How can that one function REALLY do all that?

  sendCommand(CMD_FOUND_NUM_FILES, 0X48); // Detects number of files on card

Why do you bother to do that, if you don't care what the answer is?

How do you know which commands return an answer? Why don't you read all the answers?

You seem to think that the answer will contain one value that says which file is playing. I do NOT agree. There will be TWO values - the folder and the track. If you want to resume playing the correct file, you need to specify the folder AND the track.

PaulS:

  pinMode(buttonPause, INPUT);

pinMode(buttonNext, INPUT);

pinMode(buttonPrevious, INPUT);

pinMode(buttonHorn, INPUT);



You need to tell us how the switches are actually wired (unless you really sewed buttons on, in which case don't bother).

**The buttons are wired with a 10k resistor to ground.** 



if (mp3.available()) //Returns commands, and determines what file is being played



How can that one function REALLY do all that?

**That one line doesn't do that, but the code that follows, along with the function at the bottom, does.** 



sendCommand(CMD_FOUND_NUM_FILES, 0X48); // Detects number of files on card



Why do you bother to do that, if you don't care what the answer is?

**This gets read on the serial monitor. However, it's not stored in an integer.** 

How do you know which commands return an answer? Why don't you read all the answers?

**The best I can tell this code is the function that is read by the if (mp3.available()) statement and returns the answers in a HEX format that is then read on the serial monitor. I am also attaching an image of the serial monitor so you can see how it is displaying the answers.** 



// Function to retrieve answers
boolean answer(void)
{
  uint8_t i = 0;

// Get only 10 bytes
  while (mp3.available() && (i < 10))
  {
    uint8_t b = mp3.read();
    ansbuf[i] = b;
    i++;
    byte2hex(b);
  }

Serial.println();

// If the correct response format
  if ((ansbuf[0] == 0x7E) && (ansbuf[9] == 0xEF))
  {
    return true;
  }

return false;
}




You seem to think that the answer will contain one value that says which file is playing. I do NOT agree. There will be TWO values - the folder and the track. If you want to resume playing the correct file, you need to specify the folder AND the track.

**I agree with that assertion that I will need both the folder and the track; however, when I activate the other song via the button both of those values change. How can I store the value for the song/folder that was playing without it changing when I activate the button to play the new song?**

The mp3.available() method tells you that there is data to read. It does NOT tell you which command that was sent to the device the data is an answer to.

The buttons are wired with a 10k resistor to ground.

Useless information. You might has well have responded with what color insulation the wires have.

A schematic WOULD be useful information.

This gets read on the serial monitor. However, it's not stored in an integer.

YOU read data on the Serial Monitor. The Arduino does not. The Arduino can WRITE data on the serial port that the Serial Monitor app is listening to.

  sendCommand(0X01, track);

Isn't 0x01 the Play Next Song command? 0x0D appears to be the Resume command that goes with the Pause command.

PaulS:
The mp3.available() method tells you that there is data to read. It does NOT tell you which command that was sent to the device the data is an answer to.

The data that is printed on the serial monitor tells you what commands have been sent as shown in the image of the serial monitor I attached earlier.

Useless information. You might has well have responded with what color insulation the wires have.

A schematic WOULD be useful information.

I am attaching an image of the schematic. The Catalex board is not shown because it is not listed in fritzing. It’s TX is connected to pin D5 and it’s RX is D6 with V+ and ground connected appropriately. From the description I gave the switches are wired as pull down switches, and in the code they are plugged in the following ports:
** **int buttonHorn = 2; int buttonPause = 3; int buttonPrevious = 7; int buttonNext = 8;** **
With the following designations:
```
**pinMode(buttonPause, INPUT);

pinMode(buttonNext, INPUT);

pinMode(buttonPrevious, INPUT);

pinMode(buttonHorn, INPUT);**

```
The insulation is white BTW

YOU read data on the Serial Monitor. The Arduino does not. The Arduino can WRITE data on the serial port that the Serial Monitor app is listening to.

Ok, Arduino WRITES it to the serial monitor, then I READ it myself. That still doesn’t help me be able to store the value written by the arduino and use it later in my code. As I said, the value printed for the file number changes when I press the horn button.

  sendCommand(0X01, track);

Isn’t 0x01 the Play Next Song command? 0x0D appears to be the Resume command that goes with the Pause command.

Yes, the 0X0D command is the play command, but changing that still doesn’t solve the issue of it being able to resume playing the track that it left when the horn button was pressed.