Need help connecting serial input from keypad to play MP3 output from MP3 shield

Hi all,

Disclaimer that I am not a coder but have been trying my best to figure this out on my own. I have all the hardware figured out thanks to a friend, but the software has been harder to figure out. Now I’m down to the wire on a project and I need to figure this out, today…

The goal is to re-build a regular, touch tone phone so that when you pick up the handset and press a button on the keypad, you’ll hear an mp3 play. 9 mp3s total, one for each key (press 1 to hear track001.mp3, 2 to hear track002.mp3, etc.). Hang up the handset and it will stop.

I have this arduino and this MP3 shield, and my friend is handling all of the hardware - connecting the keypad from the original phone to the arduino itself. At this point we’ve got it so that pushing the keys prints the key numbers on the screen, as in the CustomKeypad sketch mentioned here which is an example in Arduino IDE.

I have two pieces of borrowed code that compile and do what I want them to do.

The code that runs the Keypad and gives a number output when I press a key (e.g. press 1 on the keypad, 1 shows up in the Serial Monitor):

/* @file CustomKeypad.pde
|| @version 1.0
|| @author Alexander Brevig
||s @contact alexanderbrevig@gmail.com
||
|| @description
|| | Demonstrates changing the keypad size and key values.
|| #
*/
#include <Keypad.h>
#include <SPI.h>           // SPI library
#include <SdFat.h>         // SDFat Library
//#include <SdFatUtil.h>     // SDFat Util Library
#include <SFEMP3Shield.h>  // Mp3 Shield Library

SdFat sd; // Create object to handle SD functions

SFEMP3Shield MP3player; // Create Mp3 library object
// These variables are used in the MP3 initialization to set up
// some stereo options:
const uint8_t volume = 0; // MP3 Player volume 0=max, 255=lowest (off)
const uint16_t monoMode = 1;  // Mono setting 0=off, 3=max

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
//define the cymbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
  {'1','2','3','.'},
  {'4','5','6','.'}, 
  {'7','8','.','9'},
  {'*','0','.','#'}
};
byte rowPins[ROWS] = {0, 10, 5, A0/*, A5*/}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {A4, A1, A2, A3/*, 12*/}; //connect to the column pinouts of the keypad

int stopPin = A5; // This pin triggers a track stop. I added from Mp3 shield trigger
int lastTrigger = 0; // This variable keeps track of which tune is playing. I added from Mp3 shield trigger. not needed?

//initialize an instance of class NewKeypad
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 

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


  initSD();  // Initialize the SD card
  initMP3Player(); // Initialize the MP3 Shield - I added from void setup of Mp3 trigger code
}
  
void loop(){
  char customKey = customKeypad.getKey();
  
  if (customKey){
    Serial.println(customKey);
  }



  // After looping through and checking trigger pins, check to
  //  see if the stopPin (A5) is triggered.
  if (digitalRead(stopPin) == LOW)
  {
    lastTrigger = 0; // Reset lastTrigger
    // If another track is playing, stop it.
    if (MP3player.isPlaying())
      MP3player.stopTrack();
  }
  
}


// initSD() initializes the SD card and checks for an error.
void initSD()
{
  //Initialize the SdCard.
  if(!sd.begin(SD_SEL, SPI_HALF_SPEED)) 
    sd.initErrorHalt();
  if(!sd.chdir("/")) 
    sd.errorHalt("sd.chdir");
}

// initMP3Player() sets up all of the initialization for the
// MP3 Player Shield. It runs the begin() function, checks
// for errors, applies a patch if found, and sets the volume/
// stero mode.
void initMP3Player()
{
  uint8_t result = MP3player.begin(); // init the mp3 player shield
  if(result != 0) // check result, see readme for error codes.
  {
    // Error checking can go here!
  }
  MP3player.setVolume(volume, volume);
  MP3player.setMonoMode(monoMode);
}

And the code that will play an mp3 (e.g. track001.mp3) loaded on an SD card in the MP3 shield if I type in a number (e.g. 1) from my computer keyboard into the Serial Monitor. I’ve attached this as a separate file (Player.ino).

I’ve attached a separate file (CombinedKeypadPlayer.ino) with my attempt at combining these two, which compiles with no errors.

What I’m finding with this combined code:

  • The MP3s play when I input 1, 2, 3, etc from my computer keyboard into the Serial Monitor, but they only play for half a second. I have changed #define USE_MP3_REFILL_MEANS USE_MP3_INTx to #define USE_MP3_REFILL_MEANS USE_MP3_Polled in the SFEMP3ShieldConfig.h file, as mentioned here.
    This only happens in the combined code- the full MP3s do play if I just use the FilePlayer code above.

  • If I press the keypad numbers, they will show up in the Serial Monitor (yay).

I want to take customKey as an output from the keypad, and turn that into an input for the file player. Somehow relate/connect customKey to key_command in the file player code, if that makes sense. I hope that will solve my problem.

I also want to somehow connect the A5 pin as a stop trigger. The pin is connected to the hang-up switch on the phone right now, and I think I can take some of the TRIGGER code from this MP3 Shield Sketch and use that as another input that will stop a currently playing track.

Can anyone help me with this?

Thank you to Alexander Brevig, Bill Porter, Michael P. Flaga, and everyone else whose code I have been using, and thanks in advance for any advice. I’m kind of at my wit’s end as a non-coder and I really appreciate it.

Player.ino (20.4 KB)

CombinedKeypadPlayer.ino (20.3 KB)

The values in the keypad table don't have to be characters. They can be any non-zero number. You could assign numbers in any order and use to directly select a file from a list of files. Use 0 for any keys you don't need.

char hexaKeys[ROWS][COLS] = {
  {1,2,3,0},
  {4,5,6,0}, 
  {7,8,0,9},
  {0,0,0,0}
};
byte rowPins[ROWS] = {0, 10, 5, A0}; //connect to the row pinouts of the keypad

  Serial.begin(9600);

  Serial.print(F("Free RAM = ")); // available in Version 1.0 F() bases the string to into Flash, to use less SRAM.
  Serial.print(FreeRam(), DEC);  // FreeRam() is provided by SdFatUtil.h
  Serial.println(F(" Should be a base line of 1029, on ATmega328 when using INTx"));

Pin 0 is NOT available for your keypad, when you actually use Serial.

All the commented out code in your combined attempt, and all the useless

white space do NOT make for easy reading.

Your
piss-poor
indenting
doesn't
help, either.

    } else if (buffer_pos > 5) {
      // dump if entered command is greater then uint16_t
      Serial.println(F("Ignored, Number is Too Big!"));

You should check BEFORE you write more than 5 characters to the array, that there IS room in the array. This test should NEVER be true.

We can't see your serial output, so we have no idea what your code is actually doing.
We can't see your schematic, even though we KNOW that it is wrong, so we can't tell if you have floating pins, etc.