Audio player - LCD and buttons

Hello

I'm working on an audio project using this audio board :
rMP3 Playback Module - Rogue Robotics which is very nice.

I'm trying to command 2 of this board with an Arduino Duemilanove, 4 buttons and a LCD.
Everything is nearly working, but I faced a problem using the two boards and the buttons.

This is the code, "rmp1" is the first audio board, "rmp2" the second.

#define play1       3  // Button
#define next1       18  // Button
#define play2       2  // Button
#define next2       19 // Button
#define DELAY            80  // Delay per loop in ms

#include <RogueSD.h>
#include <RogueMP3.h>
#include <SoftwareSerial.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(8, 9, 10, 11, 12, 13);

SoftwareSerial rmp1_serial(6, 7);//*************  player 1
RogueMP3 rmp1(rmp1_serial);
RogueSD filecommands1(rmp1_serial);
char path1[96];
const char *directory1;

SoftwareSerial rmp2_serial(4, 5);//************** player 2
RogueMP3 rmp2(rmp2_serial);
RogueSD filecommands2(rmp2_serial);
char path2[96];
const char *directory2;

boolean next1_was_pressed;
boolean play1_was_pressed;
boolean next2_was_pressed;
boolean play2_was_pressed;

//************************************************* SETUP

void setup()
{

  char filename1[80];
  char filename2[80];

  Serial.begin(9600);
  Serial.println("Minison Player");
  Serial.println(' ');
  lcd.begin(16, 2);

  pinMode(next1, INPUT);
  pinMode(play1, INPUT);
  pinMode(next2, INPUT);
  pinMode(play1, INPUT);
  next1_was_pressed = false;
  play1_was_pressed = false;
  next2_was_pressed = false;
  play2_was_pressed = false;


  //*********************************************************
 //**************** Init PLayer 1 ************************** 

  rmp1_serial.begin(9600);
  rmp1.sync();
  rmp1.stop();
  filecommands1.sync();

  //****************************  List Files Player 1 

  // char filename1[64];
  Serial.print("Player 1 Version: ");
  Serial.println(rmp1.version());

  if (filecommands1.status() == 0)
  {
    Serial.print("File count: ");// list all files
    // filecount() takes 2 arguments:
    // 1. source path
    // 2. file mask (e.g. list only MP3 files: "*.mp3")
    // (note: the "/""*" is there because of a problem with the Arduino IDE
    // thinking that /* is the start of a comment
    Serial.println(filecommands1.filecount("/""*"), DEC);
    Serial.println("--- Files ---");
    // opendir() opens the directory for reading.
    // argument is the path
    filecommands1.opendir("/");
    // readdir() gets the next directory entry that matches the mask. 2 arguments:
    // 1. char buffer to store the name - make sure that it's big enough to store the
    //    largest name in the directory.
    // 2. file mask (same as in filecount()) 
    int type; 
    while((type = filecommands1.readdir(filename1, "*")) >= 0)
    {
      if (type == 1)  // if it's a folder/directory
        Serial.print("*DIR* ");
      Serial.println(filename1);
    }
    Serial.println("-------------");
  }
  else
  {
    Serial.print("rmp2 sync failed. Error code: ");
    Serial.println(filecommands1.LastErrorCode, HEX);
  }

  //************************** End List Files Player 1 

  filecommands1.opendir(directory1);
  filecommands1.readdir(filename1, "*.mp3");
  strcpy(path1, directory1);
  strcat(path1, filename1);
  rmp1.playfile(path1);
  lcd.setCursor(0,0);
  lcd.println(filename1);
  Serial.println("Player 1 playing");
  Serial.println(' ');

  delay(50);
  
  //************************************************
 //************ Init PLayer 2 **********************

  rmp2_serial.begin(9600);
  rmp2.sync();
  rmp2.stop();
  filecommands2.sync();

  //***************************** List Files Player 2 

  //   char filename2[64];
  Serial.print("Player 2 Version: ");
  Serial.println(rmp2.version());

  if (filecommands2.status() == 0)
  {
    Serial.print("File count: ");// list all files
    // filecount() takes 2 arguments:
    // 1. source path
    // 2. file mask (e.g. list only MP3 files: "*.mp3")
    // (note: the "/""*" is there because of a problem with the Arduino IDE
    // thinking that /* is the start of a comment
    Serial.println(filecommands2.filecount("/""*"), DEC);
    Serial.println("--- Files ---");
    // opendir() opens the directory for reading.
    // argument is the path
    filecommands2.opendir("/");
    // readdir() gets the next directory entry that matches the mask. 2 arguments:
    // 1. char buffer to store the name - make sure that it's big enough to store the
    //    largest name in the directory.
    // 2. file mask (same as in filecount()) 
    int type; 
    while((type = filecommands2.readdir(filename2, "*")) >= 0)
    {
      if (type == 1)  // if it's a folder/directory
        Serial.print("*DIR* ");
      Serial.println(filename2);
    }
    Serial.println("-------------");
  }
  else
  {
    Serial.print("rmp2 sync failed. Error code: ");
    Serial.println(filecommands2.LastErrorCode, HEX);
  }

  //****************************** End List Files Player 2

  filecommands2.opendir(directory2);
  filecommands2.readdir(filename2, "*.mp3");
  strcpy(path2, directory2);
  strcat(path2, filename2);
  rmp2.playfile(path2);
  lcd.setCursor(0,1);
  lcd.println(filename2);
  Serial.println("Player 2 playing");
  Serial.println(' ');
  Serial.print("Error : ");
  Serial.println(filecommands2.LastErrorCode, HEX);
  delay(500);

}

//************************************************* LOOP

void loop()
{
  char filename1[80];
  char filename2[80];

  //************************************************  Handle buttons


  int play1_now_pressed = !digitalRead(play1); // pin low -> pressed
  boolean play1_event = play1_now_pressed && !play1_was_pressed;
  play1_was_pressed = play1_now_pressed;

  int next1_now_pressed = !digitalRead(next1); // pin low -> pressed
  boolean next1_event = next1_now_pressed && !next1_was_pressed;
  next1_was_pressed = next1_now_pressed;

  int play2_now_pressed = !digitalRead(play2); // pin low -> pressed
  boolean play2_event = play2_now_pressed && !play2_was_pressed;
  play2_was_pressed = play2_now_pressed;

  int next2_now_pressed = !digitalRead(next2); // pin low -> pressed
  boolean next2_event = next2_now_pressed && !next2_was_pressed;
  next2_was_pressed = next2_now_pressed;

  //***************************************************** Events

  if (next1_event == true)
  {
    Serial.println("next1");
    filecommands1.readdir(filename1, "*.mp3");
    strcpy(path1, directory1);
    strcat(path1, filename1);
    lcd.setCursor(0,0);
    lcd.println(path1);
    Serial.println(path1);
  }

  if (next2_event == true)
  {
    Serial.println("next2");
    filecommands2.readdir(filename2, "*.mp3");
    strcpy(path2, directory2);
    strcat(path2, filename2);
    lcd.setCursor(0,1);
    lcd.println(path2);
    Serial.println(path2);

  }

  if (play1_event == true)
  {
    Serial.println("play1");
        Serial.println(play1_event);
        rmp1.playfile(path1);
       Serial.println(path1);
        Serial.println(filecommands2.LastErrorCode, HEX);
  }

  if (play2_event == true)
  {
    Serial.println("play2");
       rmp2.playfile(path2);
     
  }


  delay(DELAY);
}

I apologize because I think this code is ugly, but I'm learning :slight_smile:

When I run this sketch I could read on the serial monitor

Minison Player

Player 1 Version: 10001
File count: 5
--- Files ---
RAP 01.mp3
RAP 02.mp3
RAP 03.mp3
RAP 04.mp3
DIR .Trash-1000

Player 1 playing

Player 2 Version: 10001
File count: 5
--- Files ---
CB - Chills.mp3
CB - Malaguena.mp3
DIR .Trash-1000
CB - Kiki.mp3
CB - Don't.mp3

Player 2 playing

Error : 7

And the two boards start to play first songs on memory !

But I can command only the board named "rmp2" on my sketch.
The buttons "play2" and "next2" works perfectly, but buttons "next1" and "play1" seems to crash the sketch.
After a press on button "next1" or"play1", serial monitor freeze and nothing happens.

I found where the sketch is bugging
this is at rmp2_serial.begin(9600);

When I remove everything relative "to rmp2" underneath this instruction and decomment this instruction
I can use buttons "next1" and "play1"
(It may be not clear, sorry for that, I'm french :slight_smile: "

So I think the problem come from a conflict between the buttons and the initialisation of the RMP3.
I tried to look in the libraries in RogueMP3.cpp
but it too complicated for a newbie like me.
Any ideas ?

One potential issue is that only one instance of SoftwareSerial can be active at one one. You have two instances. I don't see any calls to listen() for those two instances.

I'd recommend a Mega with 4 hardware serial ports that can all listen at once.

You are also creating two instances of a class that can access an SD card. Each instance is probably creating a 512 byte buffer to be used to talk to the SD card. Those two buffers represent half the memory on a 328-based Arduino.

I'd guess that you are running out of memory.

thanks

you say

I'd guess that you are running out of memory.

I tested with this library “memoryFree”

a Serial.println(freeMemory()); give me a result of 937.

Thanks !!!

I just add a listen instruction after each if events and it works !
Here is the code

//#include "MemoryFree.h"
#define play1       3  // Button
#define next1       18  // Button
#define play2       2  // Button
#define next2       19 // Button
#define DELAY            80  // Delay per loop in ms

#include <RogueSD.h>
#include <RogueMP3.h>
#include <SoftwareSerial.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 10, 11, 12, 13);

SoftwareSerial rmp1_serial(6, 7);//*************  player 1
RogueMP3 rmp1(rmp1_serial);
RogueSD filecommands1(rmp1_serial);
char path1[96];
const char *directory1;

SoftwareSerial rmp2_serial(4, 5);//************** player 2
RogueMP3 rmp2(rmp2_serial);
RogueSD filecommands2(rmp2_serial);
char path2[96];
const char *directory2;

boolean next1_was_pressed;
boolean play1_was_pressed;
boolean next2_was_pressed;
boolean play2_was_pressed;


void setup()//********************************** SETUP
{

  char filename1[80];
  char filename2[80];

  Serial.begin(9600);
  lcd.begin(16, 2);

  pinMode(next1, INPUT);
  pinMode(play1, INPUT);
  pinMode(next2, INPUT);
  pinMode(play1, INPUT);
  next1_was_pressed = false;
  play1_was_pressed = false;
  next2_was_pressed = false;
  play2_was_pressed = false;

  //*********************************************************
  //**************** Init PLayer 1 ************************** 

  rmp1_serial.begin(9600);
  rmp1.sync();
  rmp1.stop();
  filecommands1.sync();

  //****************************  List Files Player 1 

  // char filename1[64];
  Serial.print("Player 1 Version: ");
  Serial.println(rmp1.version());

  if (filecommands1.status() == 0)
  {
    Serial.print("File count: ");// list all files
    Serial.println(filecommands1.filecount("/""*"), DEC);
    Serial.println("--- Files ---");
    filecommands1.opendir("/");
    int type; 
    while((type = filecommands1.readdir(filename1, "*")) >= 0)
    {
      if (type == 1)  // if it's a folder/directory
        Serial.print("*DIR* ");
      Serial.println(filename1);
    }
    Serial.println("-------------");
  }
  else
  {
    Serial.print("rmp2 sync failed. Error code: ");
    Serial.println(filecommands1.LastErrorCode, HEX);
  }

  //************************** End List Files Player 1 

  filecommands1.opendir(directory1);
  filecommands1.readdir(filename1, "*.mp3");
  strcpy(path1, directory1);
  strcat(path1, filename1);
  rmp1.playfile(path1);
  lcd.setCursor(0,0);
  lcd.println(filename1);

  delay(50);

  //************************************************
  //************ Init PLayer 2 **********************

  rmp2_serial.begin(9600);
  rmp2.sync();
  rmp2.stop();
  filecommands2.sync();

  //***************************** List Files Player 2 


  Serial.print("Player 2 Version: ");
  Serial.println(rmp2.version());

  if (filecommands2.status() == 0)
  {
    Serial.print("File count: ");// list all files
    Serial.println(filecommands2.filecount("/""*"), DEC);
    Serial.println("--- Files ---");
    filecommands2.opendir("/");
    int type; 
    while((type = filecommands2.readdir(filename2, "*")) >= 0)
    {
      if (type == 1)  // if it's a folder/directory
        Serial.print("*DIR* ");
      Serial.println(filename2);
    }
    Serial.println("-------------");
  }
  else
  {
    Serial.print("rmp2 sync failed. Error code: ");
    Serial.println(filecommands2.LastErrorCode, HEX);
  }

  //****************************** End List Files Player 2

  filecommands2.opendir(directory2);
  filecommands2.readdir(filename2, "*.mp3");
  strcpy(path2, directory2);
  strcat(path2, filename2);
  rmp2.playfile(path2);
  lcd.setCursor(0,1);
  lcd.println(filename2);
  delay(500);
}

//************************************************************ LOOP

void loop()
{
  char filename1[80];
  char filename2[80];
  char status1;
  char status2;
  //Serial.println(freeMemory());

  //************************************************  Handle buttons

  int play1_now_pressed = !digitalRead(play1); // pin low -> pressed
  boolean play1_event = play1_now_pressed && !play1_was_pressed;
  play1_was_pressed = play1_now_pressed;

  int next1_now_pressed = !digitalRead(next1); // pin low -> pressed
  boolean next1_event = next1_now_pressed && !next1_was_pressed;
  next1_was_pressed = next1_now_pressed;

  int play2_now_pressed = !digitalRead(play2); // pin low -> pressed
  boolean play2_event = play2_now_pressed && !play2_was_pressed;
  play2_was_pressed = play2_now_pressed;

  int next2_now_pressed = !digitalRead(next2); // pin low -> pressed
  boolean next2_event = next2_now_pressed && !next2_was_pressed;
  next2_was_pressed = next2_now_pressed;

  //*************************************************************
  //****************** Events ************************************


  if (next1_event == true)//******************************** NEXT 1
  {
    rmp1_serial.listen();
    filecommands1.readdir(filename1, "*.mp3");
    strcpy(path1, directory1);
    strcat(path1, filename1);
    lcd.setCursor(0,0);
    lcd.println(path1);
  }

  //*************************************************** REINIT PLAYER 1
  if (play1_was_pressed == 1 && next1_was_pressed == 1)
  {
    rmp1_serial.listen();
    filecommands1.opendir(directory1);
    filecommands1.readdir(filename1, "*.mp3");
    strcpy(path1, directory1);
    strcat(path1, filename1);
    lcd.setCursor(0,0);
    lcd.println(filename1);
  }

  if (play1_event == true)//********************************* PLAY 1
  {
    rmp1_serial.listen();
    rmp1.playfile(path1);
  }

  if (next2_event == true)//********************************* NEXT 2
  {
    rmp2_serial.listen();
    filecommands2.readdir(filename2, "*.mp3");
    strcpy(path2, directory2);
    strcat(path2, filename2);
    lcd.setCursor(0,1);
    lcd.println(path2);
  }

  //************************************************** REINIT PLAYER 2
  if (play2_was_pressed == 1 && next2_was_pressed == 1)
  {
    rmp2_serial.listen();
    filecommands2.opendir(directory2);
    filecommands2.readdir(filename2, "*.mp3");
    strcpy(path2, directory2);
    strcat(path2, filename2);
    lcd.setCursor(0,1);
    lcd.println(filename2);
  }

  if (play2_event == true)//********************************** PLAY 2
  {
    rmp2_serial.listen();
    rmp2.playfile(path2);
  }

  rmp1_serial.listen();
  status1 = rmp1.getplaybackstatus();
  if (status1 == 'S')
  {
    rmp1_serial.listen();
    filecommands1.readdir(filename1, "*.mp3");
    strcpy(path1, directory1);
    strcat(path1, filename1);
    rmp1.playfile(path1);
    lcd.setCursor(0,0);
    lcd.println(path1);
    return;
  }

  rmp2_serial.listen();
  status2 = rmp2.getplaybackstatus();
  if (status2 == 'S')
  {
    rmp2_serial.listen();
    filecommands2.readdir(filename2, "*.mp3");
    strcpy(path2, directory2);
    strcat(path2, filename2);
    rmp2.playfile(path2);
    lcd.setCursor(0,1);
    lcd.println(path2);
    return;
  }
}

My next question is for the LCD.

I use a standard 16 x 2 LCD with the Liquid crystal library.

With this code, I see the terminating null character.
How can I shorten the array that it don't display this character ?

I tried to define an array for the lcd and copy the filename on it, like this

char lcd_path[16];
strcpy(lcd_path, filename1);

but it dont' works.

With this code, I see the terminating null character.

You mean this code?

  lcd.println(filename1);

Your LCD doesn't know what to do with the carriage return and line feed you are sending it. That isn't the "terminating NULL character" you are seeing.

Use print() to send data the to LCD, not println().

but it dont' works.

Well, that's certainly enough to go on. We know exactly what it did, what you expected, and how those two differ. Not!