Although this works, I am not confident that I've coded this optimally.
I have:
- MOVI rev 1.1
- Adafruit "Music Maker" MP3 Shield for Arduino w/3W Stereo Amp (
https://www.adafruit.com/product/1788)
- Adafruit PN532 NFC/RFID Controller Shield (
https://www.adafruit.com/product/789)
- Elegoo Mega 2560 R3 (
https://www.amazon.com/Elegoo-ATmega2560-ATMEGA16U2-Compatible-Arduino/dp/B01H4ZLZLQ)
Goal is to integrate these components.
I had to briefly pause music playing so that I could run the MOIV poll() method. I also had to place the NFC card read within a pause. Otherwise, weirdness occurred. I'm thinking that either there are pin conflicts or memory conflicts. Need to dig some more, but for now this works:
if (musicPlayer.playingMusic) { recognizerPause=true; musicPlayer.pausePlaying(true); }
// do this while briefly paused music
res=recognizer.poll();
// do this while briefly paused music
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
if (recognizerPause) { recognizerPause=false; musicPlayer.pausePlaying(false); }
Note:
- I jumped the MOVI TX and RX pins to pins A13 and A12 on the mega.
- On the Music Maker shield, I closed the three solder jumpers next to the ISP header. This configures the shield to use the ISP header for SPI communication (needed for the Mega). I also cut the mini wire between the other three jumpers to 'release' the digital #11, 12 and 13 pins from being tied to the SPI pins - so that I could use them for something else. (
https://learn.adafruit.com/adafruit-music-maker-shield-vs1053-mp3-wav-wave-ogg-vorbis-player/assembly).
Full code is below:
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>
#include "MOVIShield.h" // Include MOVI library, needs to be *before* the next #include
#include <Wire.h>
#include <Adafruit_NFCShield_I2C.h>
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_PIC32)
#include <SoftwareSerial.h> // This is nice and flexible but only supported on AVR and PIC32 architecture, other boards need to use Serial1
#endif
// These are the pins used for the music maker shield
#define SHIELD_RESET -1 // VS1053 reset pin (unused!)
#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
#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
#define NFC_IRQ 2
#define NFC_RESET 100 // Not connected by default on the NFC Shield
// Set volume for Music Maker left, right channels. lower numbers == louder volume!
#define MUSIC_LOUD 20
#define MUSIC_SOFT 40
Adafruit_VS1053_FilePlayer musicPlayer =
Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);
/*
* MOVI TX (J2) -> Arduino A13 (Arduino Mega RX)
* MOVI RX (J3) -> Arduino A12 (Arduino Mega TX)
*/
const int led = 13;
MOVI recognizer(true, A13, A12); // Get a MOVI object, true enables serial monitor interface, rx and tx can be passed as parameters for alternate communication pins on AVR architecture
char *Tracks[] = {"TRACK001.MP3", "TRACK002.MP3", "TRACK003.MP3", "TRACK004.MP3"};
int track=0;
Adafruit_NFCShield_I2C nfc(NFC_IRQ, NFC_RESET);
void setup()
{
recognizer.init(); // Initialize MOVI (waits for it to boot)
recognizer.setVoiceGender(true);
recognizer.callSign("Arduino"); // Train callsign Arduino (may take 20 seconds)
recognizer.addSentence("Let there be light"); // Add sentence 1
recognizer.addSentence("Go dark"); // Add sentence 2
recognizer.addSentence("pause"); // Add sentence 3
recognizer.addSentence("next"); // Add sentence 4
recognizer.addSentence("resume"); // Add sentence 5
recognizer.addSentence("stop"); // Add sentence 6
recognizer.addSentence("soft"); // Add sentence 7
recognizer.addSentence("loud"); // Add sentence 8
recognizer.addSentence("play"); // Add sentence 9
recognizer.train(); // Train (may take 20seconds)
// Serial.begin(9600); // because we constructed with debug true
nfc.begin();
uint32_t versiondata = nfc.getFirmwareVersion();
if (! versiondata) {
Serial.print("Didn't find PN53x board");
while (1); // halt
}
// Got ok data, print it out!
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
// Set the max number of retry attempts to read from a card
// This prevents us from waiting forever for a card, which is
// the default behaviour of the PN532. 0x01 will retry once. 0xFF will retry forever
nfc.setPassiveActivationRetries(0x01);
// configure board to read RFID tags
nfc.SAMConfig();
// initialise the music player
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"));
musicPlayer.sineTest(0x44, 500); // Make a tone to indicate VS1053 is working
if (!SD.begin(CARDCS)) {
Serial.println(F("SD failed, or not present"));
while (1); // don't do anything more
}
Serial.println("SD OK!");
// list files
printDirectory(SD.open("/"), 0);
// Set volume for left, right channels. lower numbers == louder volume!
musicPlayer.setVolume(MUSIC_SOFT,MUSIC_SOFT);
if (! musicPlayer.useInterrupt(VS1053_FILEPLAYER_TIMER0_INT))
Serial.println(F("DREQ pin is not an interrupt pin"));
// Start playing a file, then we can do stuff while waiting for it to finish
if (! musicPlayer.startPlayingFile(Tracks[track])) {
Serial.print("Could not open file ");
Serial.println(Tracks[track]);
while (1);
}
Serial.println(F("Started playing"));
delay(250); // Give the music maker a moment to get going
}
void loop() // run over and over
{
signed int res;
bool recognizerPause=false;
uint8_t success;
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
if (musicPlayer.playingMusic) { recognizerPause=true; musicPlayer.pausePlaying(true); }
// do this while briefly paused music
res=recognizer.poll(); // Get result from MOVI, 0 denotes nothing happened, negative values denote events (see docs)
// do this while briefly paused music
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
if (recognizerPause) { recognizerPause=false; musicPlayer.pausePlaying(false); }
if (success) {
// Display some basic information about the card
Serial.println("Found an ISO14443A card");
Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
Serial.print(" UID Value: ");
nfc.PrintHex(uid, uidLength);
Serial.println("");
}
switch (res) {
case 1: //"Let there be light"
Serial.println("and there was light!");
recognizer.say("and there was light!"); // Speak a sentence
break;
case 2: //"Go dark"
Serial.println(F("and there was darkness!"));
recognizer.say("and there was darkness!");
break;
case 3: //"pause"
Serial.println("pause");
recognizer.say("Pausing music.");
musicPlayer.pausePlaying(true);
break;
case 4: //"next"
Serial.println("next");
recognizer.say("I will play the next song.");
musicPlayer.stopPlaying();
if (track<3) track++; else track=0;
if (! musicPlayer.startPlayingFile(Tracks[track])) {
Serial.print("Could not open file ");
Serial.println(Tracks[track]);
while (1);
}
Serial.print("Started playing ");
Serial.println(Tracks[track]);
break;
case 5: //"continue"
Serial.println("resume");
recognizer.say("I will resume playing the music.");
musicPlayer.pausePlaying(false);
break;
case 6: //"stop"
Serial.println("stop");
recognizer.say("I will stop playing music.");
musicPlayer.stopPlaying();
break;
case 7: //"soft"
Serial.println("I will play softly.");
recognizer.say("I will play softly.");
musicPlayer.setVolume(MUSIC_SOFT,MUSIC_SOFT);
break;
case 8: //"loud"
Serial.println("I will play loudly.");
recognizer.say("I will play loudly.");
musicPlayer.setVolume(MUSIC_LOUD,MUSIC_LOUD);
break;
case 9: //"play"
Serial.println("I will play music.");
recognizer.say("I will begin playing music.");
musicPlayer.stopPlaying();
musicPlayer.startPlayingFile(Tracks[track]);
break;
}
}
/// File listing helper
void printDirectory(File dir, int numTabs) {
while(true) {
File entry = dir.openNextFile();
if (! entry) {
// no more files
//Serial.println("**nomorefiles**");
break;
}
for (uint8_t i=0; i<numTabs; i++) {
Serial.print('\t');
}
Serial.print(entry.name());
if (entry.isDirectory()) {
Serial.println("/");
printDirectory(entry, numTabs+1);
} else {
// files have sizes, directories do not
Serial.print("\t\t");
Serial.println(entry.size(), DEC);
}
entry.close();
}
}