Bluetooth Music Box (4180 Final Project)
Overview
Final ECE 4180 project made by Scout Schultz and Neeta Thawani for Spring 2017. The music box is made to add to a mechanical process. Added functionality includes the ability to switch songs, pause/play/stop songs, reset to the first song, stop/start a figurine rotating, and change volume on command of a Bluetooth app.
Parts Required
Mbed (Photo from pololu)
SD Card (Photo from Sparkfun)
Audio Amplifier (Photo from Mbed)
Speaker (Photo from Mbed)
External Power (Photo from Sparkfun)
Bluetooth (Photo from Adafruit)
On/off switch (Photo from AllExpress)
Pint Outs
mbed | Audio Amplifier | Speaker | External Power |
gnd | pwr-, in- | ||
pwr+ | 5V | ||
p18 | in+ | ||
out+ | + | ||
out- | - | ||
S |
mbed | SD Card | External Power |
14 | CS | |
11 | DI | |
VCC | 5V | |
13 | SCK | |
GND | GND | |
12 | DO | |
CD |
mbed | MOSFET Connector | motor | External power |
GND | JP2-2 GND | ||
JP2-1 RAW | 5V | ||
P23 | JP2-3 Control | ||
JP1-1 | Device(neg) | ||
JP1-2 | Device(pos) |
mbed | Bluetooth | External Power |
GND | CST | |
p10 | TXO | |
p9 | RXI | |
VIN | 5V | |
GND | GND |
mbed | On/Off Switch | External Power |
- | GND | |
p22 | + |
How It Works
When you open the box, the switch is released and the microcontroller starts playing music and spinning the dancer. The box will play the first song on the SD card and this song can be changed or paused using the Bluetooth LE control pad. If the song runs out, the box will begin playing the same song from the beginning. All of the songs are stored on the SD card, because there is ample space to put as many songs as you would like on the card. Songs should be in a .wav format and be sampled down in Audacity.
Bluetooth Module
(Photo from Adafruit)
We make use of the control pad on the Bluefruit LE app that can be downloaded to any smart phone. The control has eight buttons, a set of arrows and numbers 1 to 4.
Up arrow: Go up in volume.
Down arrow: Go down in volume.
Left arrow: Go back one song in vector.
Right arrow: Go to next song in vector.
'1': Play/pause song.
'2': Play/pause dancer while song is on.
'3': Stop song.
'4': Reset box song to first song.
How to Start Using Bluetooth
Turn on smart phone
Download the app from the app store (App is called Bluefruit LE)
Open the app and allow it to turn on your Bluetooth on your phone
Find your Bluetooth module. It should be called Adafruit Bluefruit LE
Click connect and choose the controller mode
Choose the control pad mode near the bottom of the list
You can now click button and control the music box
Code
Music Box Code
// Scout Schultz and Neeta Thawani // ECE 4180 Final Project - BlueTooth Music Box // Spring 2017 #include "mbed.h" #include "rtos.h" #include "SDFileSystem.h" #include "wave_player.h" //#include "uLCD_4DGL.h" #include "PinDetect.h" #include <vector> #include <string> #include "Motor.h" //uLCD_4DGL uLCD(p28, p27, p29); // create a global lcd object SDFileSystem sd(p11, p12, p13, p14, "sd"); //SD card PwmOut Ctrl(p23); AnalogOut DACout(p18); wave_player waver(&DACout); DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); DigitalOut led4(LED4); PinDetect lid(p22); Serial pc(USBTX, USBRX); // tx, rx Serial blue(p9,p10); volatile short paused = 0; volatile short songnum = 0; volatile short openLid = 0; volatile short dancerEnable = 1; string songname; vector<string> songs; float motorSpeed = 0.15f; float volumeIncrement = 0.2; //This function is for a thread that handles playing a song. //Once the song ends, it will automatically play the song stored in songname //(if songname is unchanged, it will just play the same song again and again) void songThread(void const *argument) { while(1) { FILE *wave_file; wave_file=fopen(songname.c_str(),"r"); waver.play(wave_file); fclose(wave_file); } } void pauseSong() { paused=1; Ctrl.write(0); waver.pause(); } void resumeSong() { paused=0; if(dancerEnable) Ctrl.write(motorSpeed); waver.resume(); } void lidClosed() { short tmp = paused; // preserve whether box was paused or not when opening pauseSong(); openLid=0; paused = tmp; } void lidOpen() { if(paused==0) resumeSong(); openLid=1; } int main() { //basic setup lid.mode(PullUp); wait(0.01); lid.attach_deasserted(&lidClosed); lid.attach_asserted(&lidOpen); lid.setSampleFrequency(50000); // 50 ms sample rate //Scan the directory for .wav files and build a vector of file names DIR *d; struct dirent *p; d = opendir("/sd"); if (d != NULL) { while ((p = readdir(d)) != NULL) { //printf(" - %s\n", p->d_name); string fname = p->d_name; if(fname.find(".wav")!=string::npos) { // if it contains ".wav" //printf("%s\n\r",fname); songs.push_back("/sd/" + fname); } } } else { printf("Could not open directory!\n\r"); } closedir(d); // Initialize a thread to handle playing the appropriate song songname = songs[0]; Thread t1(songThread); // Check whether song should be playing or not at program start Thread::wait(50); if(lid==0) lidClosed(); else //lid==0 lidOpen(); //Start the main loop, reading serial data from Bluetooth char bnum=0; while(1) { Thread::wait(100); led1= !led1; if(openLid==1) { //only perform actions if lid is open if (blue.getc()=='!' && openLid==1) { //Received a serial input if (blue.getc()=='B' && openLid==1) { //Received a button press bnum = blue.getc(); //Save which button was pressed if(blue.getc()=='1' && openLid==1) { //only execute on button press (not release) switch(bnum) { case '1': //pause/play functionality if(paused) resumeSong(); else //not paused pauseSong(); break; case '2': //enable/disable dancer if(dancerEnable) { //disable the dancer dancerEnable=0; Ctrl.write(0); } else { //enable the dancer dancerEnable = 1; if(paused==0) Ctrl.write(motorSpeed); } break; case '3': //stop functionality waver.stop(); Thread::wait(50); pauseSong(); break; case '4': //reset functionality songnum=0; songname = songs[0]; waver.stop(); Thread::wait(50); resumeSong(); break; case '5': //increase volume if(waver.getVolume()+volumeIncrement>1.0) waver.setVolume(1.0); else waver.setVolume(waver.getVolume()+volumeIncrement); break; case '6': //decrease volume if(waver.getVolume()-volumeIncrement<0.0) waver.setVolume(0.0); else waver.setVolume(waver.getVolume()-volumeIncrement); break; case '7': //previous song in list songnum--; if(songnum<0) { songnum=songs.size()-1; } songname = songs[songnum]; waver.stop(); if(paused) waver.pause(); break; case '8': //next song in list songnum++; if(songnum>=songs.size()) { songnum=0; } songname = songs[songnum]; waver.stop(); if(paused) waver.pause(); break; } } } } } else { //if lid is closed //flush the buffer while(blue.readable()) { blue.getc(); } //otherwise it will execute commands immediately once you open box } } }
How to Debug Issues
Song Playback Issues
-Be sure to change the SD card rate from 1 MB to 10 MB.
-Be sure you have the correct versions of the SD Card player and Waveplayer
-Be sure the project sample rate is correct in Audacity.
The process to correctly change a song:
1) Open song in Audacity.
2) Change the song to mono.
3) Resample the song to 16,000 Hz.
4) Change the project rate to 16,000 Hz.
5) Export song as a .wav file.
Bluetooth Issues
-Be sure your device is connected to correct Bluetooth module
-To stop the song, you must delay the pause for long enough that the song does not begin to play again. Be sure your wait is long enough.
-The code is written so that the buttons need to be pressed and released for functions to work. The control pad generally works when you simply press and do not release, so this led to a lot of double pressing and possibly restarting the song when you did not want to, which we mitigated by making sure functions only work when you press down on a button. We found the codes that are sent via bluetooth to the controller and choose those with a '1' in the 4th character to be the press of the buttons. The codes that are sent across bluetooth are as follows for when they are pressed and then released.
Up: !B516, !B507
Left: !B714, !B705
Right: !B813, !B804
Down: !B615, !B606
1: !B11:, !B10;
2: !B219, !B20:
3: !B318, !B309
4: !B417, !B408
Please log in to post comments.