Using Keypad with Music Maker Shield

Adafruit Ethernet, Motor, Proto, Wave, Datalogger, GPS Shields - etc!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
noopara
 
Posts: 45
Joined: Tue Oct 14, 2014 2:44 pm

Using Keypad with Music Maker Shield

Post by noopara »

I want to use a 3x4 keypad with the Adafruit Music Maker Shield to select tracks to play.
I have a few questions.
Do I have to connect the keypad to the Music Maker Shield or can I connect it direct to the Arduino UNO or does it matter?

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Using Keypad with Music Maker Shield

Post by adafruit_support_rick »

You'll have to connect the keypad to the Arduino and write a sketch to play the file you select with the keypad.

User avatar
noopara
 
Posts: 45
Joined: Tue Oct 14, 2014 2:44 pm

Re: Using Keypad with Music Maker Shield

Post by noopara »

OK, thanks. That is what I thought.

User avatar
noopara
 
Posts: 45
Joined: Tue Oct 14, 2014 2:44 pm

Re: Using Keypad with Music Maker Shield

Post by noopara »

Well, it looks like using the pins on the Uno for the keypad with the Music Maker shield is a bit of a problem. The shield uses pins 3,4,6,7,11,12,13. I tried using a keypad connected to Uno pins 2 through 8 and although it is possible to get key presses from the keyboard it is not reliable because of the dual use. There are not enough unused pins on the Uno to make this work reliably. Is there some reason I can't use the GPIO pins on the shield? Maybe I will need to use the Arduino Mega which has more pins?

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Using Keypad with Music Maker Shield

Post by adafruit_support_rick »

You can use 5, 8, 9, 10, and A0 through A5.
A0 is D14, A1 is D15, etc.

User avatar
noopara
 
Posts: 45
Joined: Tue Oct 14, 2014 2:44 pm

Re: Using Keypad with Music Maker Shield

Post by noopara »

Do I just define the analog pin numbers in the keypad matrix and add a pull up resistor to each pin and then treat it like a digital pin (high and low)?

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Using Keypad with Music Maker Shield

Post by adafruit_support_rick »

Use the digital numbers of the analog pins: 14, 15, 16, 17, 18, 19. They have internal pullups, just like the regular digital pins. In fact, they are regular digital pins, they just have an optional analog function. Use them the same way you'd use any other digital pin.

User avatar
noopara
 
Posts: 45
Joined: Tue Oct 14, 2014 2:44 pm

Re: Using Keypad with Music Maker Shield

Post by noopara »

OK, great. I've got that working now.

My goal is to have an mp3 playing over and over within the loop() function and then use an interrupt that detects a key press on a keypad and then process an ISR to get the key value which is then used to play a particular mp3 assigned that value.

I have the musicPlayer.playFullFile("track001.mp3"); statement within the ISR and when I press a key on the keypad the program stops. Is it not working because this statement issues an interrupt - which is known to cause an ISR to hang?

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Using Keypad with Music Maker Shield

Post by adafruit_support_rick »

Yes, you can't call playFullFile from within an interrupt. You will have to set a flag in the interrupt, and check for that flag in your loop.

User avatar
noopara
 
Posts: 45
Joined: Tue Oct 14, 2014 2:44 pm

Re: Using Keypad with Music Maker Shield

Post by noopara »

OK, that makes sense.

So what I think will work is:
1. in the loop to call playFullFile to play a very short sleeping.mp3 (5 secs or so) and to test for the wakeUp flag set to 1 which is set by the ISR from an external interrupt.
2. with the external interrupt the wakeUp flag would be set to 1 which would then start a timer interrupt and the getKey() function would start scanning for keypad presses and then play any selected mp3 files. the playing of an mp3 would restart the timer
3. after the mp3 completes playing, scanning would continue until either another keypad press or the completion of the timer
4. if the timer times out, a timer interrupt would be used to call another ISR which would set the wakeUp flag to 0 which would then start playing the sleeping.mp3 again.

Since a call of playFullFile executes an interrupt would this cause a problem with the timer interrupt?

Do you see any possible problems with this approach?

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Using Keypad with Music Maker Shield

Post by adafruit_support_rick »

I'm not sure why you need the external interrupt. Can't you just call getKey inside loop, something like this:

Code: Select all

void loop()
{
  if (musicPlayer.stopped())
  {
    <play background loop file>
  }
  char key = keypad.getKey();
  if (NO_KEY != key)
  {
    musicPlayer.stop();
    <play selected sound file>
  }
}

User avatar
noopara
 
Posts: 45
Joined: Tue Oct 14, 2014 2:44 pm

Re: Using Keypad with Music Maker Shield

Post by noopara »

Sorry, I didn't include all the requirements such as an option to also wake it up from an external trigger such as a motion detector or some other switch closure.

In some cases instead of a background mp3 playing there will be a flashing LED or maybe both while it waits for the interrupt.

Your example does work but you have to be pressing a key on the key pad when the background mp3 stops before it starts again with the next loop through.

Does the Music Maker shield use one of the 3 timers when it plays a file?

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Using Keypad with Music Maker Shield

Post by adafruit_support_rick »

You can do the external trigger to actually wake the Arduino from sleep. The flashing LED also does not require an interrupt - it can be integrated into the loop as I proposed it.
noopara wrote:Your example does work but you have to be pressing a key on the key pad when the background mp3 stops before it starts again with the next loop through.
I don't think so. It will start the background whenever there is nothing playing. So, when the file selected by the keypad stops, it will automatically restart the background.
noopara wrote:Does the Music Maker shield use one of the 3 timers when it plays a file?
No - it uses one of the external interrupts

User avatar
noopara
 
Posts: 45
Joined: Tue Oct 14, 2014 2:44 pm

Re: Using Keypad with Music Maker Shield

Post by noopara »

I'm actually not wanting to put the arduino to sleep. I understand the confusion as there is a sleep mode. I want the arduino to be running 24-7 and playing an mp3 continuously and optionally blinking an led until someone approaches or hits a button, or some other TBD sensor triggers. At that point it will play another mp3 giving instructions for the user to key in a number on the keypad to hear one of several mp3s. Then after some period (ie 10 minutes) of no activity, return to playing the continuous mp3 and blinking the led again.

I have not been using the interrupt function in the Music Maker library which is probably why I'm seeing what I am seeing. I will give that a try.
here is what I have now: (which works just fine)
// attach external Interrupt to Arduino pin 2
pinMode(wakePin, INPUT);
digitalWrite(wakePin,HIGH);
attachInterrupt(0, wakeUpNow, LOW);

void wakeUpNow() // ISR called from external interrupt
{
wakeUp = 1;
}

I am making good progress with a 1 sec timer1 interrupt but am having problems getting an mp3 to play now. I will try and implement the Music Maker Library Interrupt function as you suggest.

Here is a sketch using Music Maker interrupt functions. It causes a lock up when I press a key on the keypad.
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>


volatile int wakeUp = 0; // wakeUp flag
const int wakeTime = 1; // minutes awake
int seconds = 0; // awake counter
int wakePin = 2; // interrupt pin
int count = 0; // troubleshooting counter

const int numRows = 4; // number of rows in the keypad
const int numCols = 3; // number of columns
const int debounceTime = 20; // number of milliseconds for switch to be stable

// keymap defines the character returned when the corresponding key is pressed
const char keymap[numRows][numCols] = {
{ '1', '2', '3' } ,
{ '4', '5', '6' } ,
{ '7', '8', '9' } ,
{ '*', '0', '#' }
};

// this array determines the pins used for rows and columns
const int rowPins[numRows] = { 10, 14, 15, 16 }; // Rows 0 through 3
const int colPins[numCols] = { 5, 8, 9 }; // Columns 0 through 2

// Grayhill series 88 keypad pin out
// D=Col 2 E=Col 1 F=Col 0 G=Row 3 H=Row 2 J=Row 1 K=Row 0

// These are the pins used for the music maker shield .3
#define SHIELD_CS 7 // VS1053 chip select pin (output)
#define SHIELD_DCS 6 // VS1053 Data/command select pin (output)

// These are common pins between breakout and shield .4
#define CARDCS 4 // Card chip select pin
// DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
#define DREQ 3 // VS1053 Data request, ideally an Interrupt pin
Adafruit_VS1053_FilePlayer musicPlayer =
// create shield-example object!
Adafruit_VS1053_FilePlayer(SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);


void setup() {
Serial.begin(9600);
Serial.println(" Audio Player - Arduino Uno with Adafruit Music Maker");

if (! musicPlayer.begin()) { // initialise the music player
Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
while (1);
}
Serial.println(F("VS1053 found"));


// initialise the SD card
if (!SD.begin(CARDCS)) {
Serial.println(F("SD failed, or not present"));
while (1); // don't do anything more
}

Serial.println("SD OK!");


// Set volume for left, right channels. lower numbers == louder volume!
musicPlayer.setVolume(10,10);

// assign keypad pinModes and set pins High
for (int row = 0; row < numRows; row++)
{
pinMode(rowPins[row],INPUT); // Set row pins as input
digitalWrite(rowPins[row],HIGH); // turn on Pull-ups
}
for (int column = 0; column < numCols; column++)
{
pinMode(colPins[column],OUTPUT); // Set column pins as outputs
// for writing
digitalWrite(colPins[column],HIGH); // Make all columns inactive
}


// from player_interrupts sample sketch
if (! musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT))
Serial.println(F("DREQ pin is not an interrupt pin"));

} // end setup()

void loop()
{

musicPlayer.playFullFile("breath02.mp3");


if (! musicPlayer.startPlayingFile("breath02.mp3")) {
Serial.println("Could not open file breath02.mp3");
while (1);
}
Serial.println(F("Started playing"));

while (musicPlayer.playingMusic) {
// file is now playing in the 'background' so now's a good time
// to do something else like handling LEDs or buttons :)
//Serial.print(".");
//delay(1000);

char key = getKey();

if( key == '1') {
musicPlayer.stopPlaying();
delay(500);
musicPlayer.playFullFile("track001.mp3");
}

Serial.println("Got Key");
Serial.print(key);
Serial.println("Done playing music");
}

} // end of loop

// returns with the key pressed, or 0 if no key is pressed
char getKey()
{

char key = 0; // 0 indicates no key pressed

for(int column = 0; column < numCols; column++)
{
digitalWrite(colPins[column],LOW); // Activate the current column.
for(int row = 0; row < numRows; row++) // Scan all rows for
// a key press.
{
if(digitalRead(rowPins[row]) == LOW) // Is a key pressed?
{

delayMicroseconds(15000); // debounce

while(digitalRead(rowPins[row]) == LOW)
; // wait for key to be released
key = keymap[row][column]; // Remember which key
// was pressed.
}
}
digitalWrite(colPins[column],HIGH); // De-activate the current column.
}
return key; // returns the key pressed or 0 if none


} // end of getKey()

User avatar
noopara
 
Posts: 45
Joined: Tue Oct 14, 2014 2:44 pm

Re: Using Keypad with Music Maker Shield

Post by noopara »

I've had to take a few steps back

I tried using the Music Maker Library Interrupt function. I was not able to get an mp3 to play after getKey() returns a value for key. So, I took a few steps back to make sure that it works without using an interrupt and it doesn't. So, I have to solve that first.

The getKey() function seems to be working perfectly as the value of key which represents a key on the keypad leads all the way to this statement: musicPlayer.playFullFile("track001.mp3"); but it doesn't play it. The program hangs at this point.

I ran some tests and discovered that if the playFullFile statement is within the if( key != 0) it will not play. It will play if it is outside of it. I know that the the value of key is not 0, but for some reason the file won't play inside the if constructor.

Any ideas?

Also, can you tell me where I can find the documentation on statements such as musicPlayer.pausePlaying(true); and musicPlayer.stopPlaying(); These are not in the Music Maker Library Reference.

Here is the code:

Code: Select all

#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>

const int numRows = 4;       // number of rows in the keypad
const int numCols = 3;       // number of columns
const int debounceTime = 20; // number of milliseconds for switch to be stable

// keymap defines the character returned when the corresponding key is pressed
const char keymap[numRows][numCols] = {
  { '1', '2', '3'  } ,
  { '4', '5', '6'  } ,
  { '7', '8', '9'  } ,
  { '*', '0', '#'  }
};

// this array determines the pins used for rows and columns
const int rowPins[numRows] = { 10, 14, 15, 16 }; // Rows 0 through 3
const int colPins[numCols] = { 5, 8, 9 };    // Columns 0 through 2
	
// These are the pins used for the music maker shield .3
#define SHIELD_CS     7      // VS1053 chip select pin (output)
#define SHIELD_DCS    6      // VS1053 Data/command select pin (output)

// These are common pins between breakout and shield .4
#define CARDCS 4     // Card chip select pin
// DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
#define DREQ 3       // VS1053 Data request, ideally an Interrupt pin
Adafruit_VS1053_FilePlayer musicPlayer =
// create shield-example object!
Adafruit_VS1053_FilePlayer(SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);


void setup() {
  Serial.begin(9600);
  Serial.println("TJ Audio Player - Arduino Uno with  Adafruit Music Maker");

  if (! musicPlayer.begin()) { // initialise the music player
	  Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
	  while (1);
  }
  Serial.println(F("VS1053 found"));
  
  SD.begin(CARDCS);    // initialise the SD card
  
  // Set volume for left, right channels. lower numbers == louder volume!
  musicPlayer.setVolume(20,20);
  
  
  for (int row = 0; row < numRows; row++)
  {
    pinMode(rowPins[row],INPUT);       // Set row pins as input
    digitalWrite(rowPins[row],HIGH);   // turn on Pull-ups
  }
  for (int column = 0; column < numCols; column++)
  {
    pinMode(colPins[column],OUTPUT);     // Set column pins as outputs 
                                         // for writing
    digitalWrite(colPins[column],HIGH);  // Make all columns inactive
  }
} // end of setup

void loop()
{
  char key = getKey();
  if( key != 0) {       // if the character is not 0 then 
                        // it's a valid key press
    Serial.print("Got key - loop ");  // this shows in monitor with key 1 when the 1 key is pressed
    Serial.println(key);  // this shows in monitor when key 1 is pressed
    
  }
  if( key == '1'){
    Serial.print("key = 1");  // this shows in monitor
    //delay(2000); // no delay value here helps
  musicPlayer.playFullFile("track001.mp3");  // wont' play
  
  }
  
  
  
} // end of loop

// returns with the key pressed, or 0 if no key is pressed
char getKey()
{    
  char key = 0;                                  // 0 indicates no key pressed

  for(int column = 0; column < numCols; column++)
  {
    digitalWrite(colPins[column],LOW);         // Activate the current column.
    for(int row = 0; row < numRows; row++)     // Scan all rows for 
                                               // a key press.
    {
      if(digitalRead(rowPins[row]) == LOW)     // Is a key pressed?
      {
        delay(debounceTime);                   // debounce
        while(digitalRead(rowPins[row]) == LOW)
            ;                                  // wait for key to be released
        key = keymap[row][column];             // Remember which key 
                                               // was pressed.
      }
    }
    digitalWrite(colPins[column],HIGH);     // De-activate the current column.
  }
  //key = 1;
  Serial.print(".6 Got key - getKey ");
    Serial.println(key);
  
  return key;  // returns the key pressed or 0 if none
} // end of getKey
Last edited by noopara on Sat Oct 25, 2014 3:25 pm, edited 5 times in total.

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino Shields from Adafruit”