Step 6: Integration with Electronics

Step 7: Final Product and Future Plans

Below is a video of the final product. The sound is being output through some desktop computer speakers. You may notice in the video that one o...

Step 3: Behavioral Code Overview

In the main loop, we read continuously from the light sensor
If the light sensor input goes above a certain value, then the MP3 starts to play
If the light sensor input goes below a certain value, then the MP3 is stopped

While the MP3 is playing, the light sensor input is converted into a decibel level for the MP3, where more light equals louder sound
In addition, the light sensor input controls the LED values inside the main loop and the MP3 loop
As the light sensor input increases, the red LED increases and the blue LED decreases

//This is the name of the file on the microSD card you would like to play
//Stick with normal 8.3 nomeclature. All lower-case works well.
//Note: you must name the tracks on the SD card with 001, 002, 003, etc.
//For example, the code is expecting to play 'track002.mp3', not track2.mp3.
char trackName[] = "sound.mp3";
int trackNumber = 1;
int previousTrigger = 1; //This indicates that we've already triggered on 1

char errorMsg[100]; //This is a generic array used for sprintf of error messages

while(1) {
while(!digitalRead(MP3_DREQ)) {
//DREQ is low while the receive buffer is full
//You can do something else here, the buffer of the MP3 is full and happy.
//Maybe set the volume or test to see how much we can delay before we hear audible glitches

//If the MP3 IC is happy, but we need to read new data from the SD, now is a great time to do so
if(need_data == TRUE) {
if(!track.read(mp3DataBuffer, sizeof(mp3DataBuffer))) { //Try reading 32 new bytes of the song
//Oh no! There is no data left to read!
//Time to exit
break;
}
need_data = FALSE;
}

//Check to see if we need to bail on this track
if(checkTriggers() != 255) {
Serial.println("Exiting MP3!");
track.close(); //Close this track!
previousTrigger = 255; //Trick the next check into thinking we haven't seen a previous trigger
return;
}
}

if(need_data == TRUE){ //This is here in case we haven't had any free time to load new data
if(!track.read(mp3DataBuffer, sizeof(mp3DataBuffer))) { //Go out to SD card and try reading 32 new bytes of the song
//Oh no! There is no data left to read!
//Time to exit
break;
}
need_data = FALSE;
}

pinMode(inputPin, INPUT); // declare the LDR as an INPUT
pinMode(redOutputLED, OUTPUT); // declare the ledPin as an OUTPUT
pinMode(blueOutputLED, OUTPUT);

Serial.begin(57600); //Use serial for debugging
Serial.println("MP3 Player Example using Control");

//Setup SD card interface
pinMode(10, OUTPUT); //Pin 10 must be set as an output for the SD communication to work.
if (!card.init(SPI_FULL_SPEED)) Serial.println("Error: Card init"); //Initialize the SD card and configure the I/O pins.
if (!volume.init(&card)) Serial.println("Error: Volume ini"); //Initialize a volume on the SD card.
if (!root.openRoot(&volume)) Serial.println("Error: Opening root"); //Open the root directory in the volume.

//We have no need to setup SPI for VS1053 because this has already been done by the SDfatlib

//Write to VS10xx register - from SparkFun example
//SCI: Data transfers are always 16bit. When a new SCI operation comes in
//DREQ goes low. We then have to wait for DREQ to go high again.
//XCS should be low for the full duration of operation.
void Mp3WriteRegister(unsigned char addressbyte, unsigned char highbyte, unsigned char lowbyte){
while(!digitalRead(MP3_DREQ)) ; //Wait for DREQ to go high indicating IC is available
digitalWrite(MP3_XCS, LOW); //Select control