Que tal aposentar seu celular e ouvir suas músicas em MP3 direto no Arduino? OK, substituir o celular pode ser um pouco exagerado, mas você pode utilizar as funcionalidades do Shield MP3 Player Sparkfun e incrementar os seus projetos. Quer exemplos?
- Sistemas de identificação com avisos sonoros: Ao invés de enviar os dados para uma tela ou acender alguma lâmpada, o seu sistema de identificação pode “falar” o nome do usuário, recebê-lo com um “Bom dia”, “Bem vindo”, “Acesso liberado”, etc.
- Utilização em brinquedos: Interação ao apertar botões ou em conjunto com acelerômetro quando há movimentação do brinquedo
- Projetos de auxílio à pessoas com deficiência visual: um despertador que “fala” as horas, uma caixa de correio que avisa quando há correspondência, um sistema que emite um sinal sonoro quando alguém se aproxima. As possibilidades são infinitas.
O Shield MP3 Player Sparkfun
Com esse Shield MP3 Player Sparkfun você pode fazer tudo isso. Ele aceita arquivos nos formatos Ogg Vorbis, MP3, AAC, WMA e MIDI, possui uma saída para fone de ouvido padrão P2 (conector 3.5mm stéreo) e permite também a conexão de um alto-falante. Um conector para cartões microSD é o responsável pelo armazenamento dos arquivos de áudio.
Essa placa não vem com a barra de pinos soldada, assim você pode montar a configuração de sua preferência. Uma opção é soldar barras de pinos como essa abaixo, numa configuração “empilhável”:
Ou você pode soldar uma barra de pinos comum, utilizando apenas os pinos necessários para comunicação com o Arduino e funcionamento do shield MP3, que são os pinos mostrados na figura abaixo:
Os pinos marcados em azul (2, 3, 4, 6, 7 e 8) são os pinos utilizados pelo CI VS1053, “cérebro” da placa e responsável pelo tratamento do som. O pino em vermelho (9), é utilizado para comunicação com o cartão microSD, e os pinos em roxo (11, 12, 13), são utilizados pelos dois, que se comunicam com o Arduino via interface SPI.
E o que sobra? Pinos 0 e 1 (RX e TX – Comunicação serial), pinos digitais 5 e 10 (PWM) e os pinos analógicos de A0 a A5.
Legal! E como eu testo tudo isso?
Bom, a primeira coisa é você soldar a barra de pinos na configuração de sua preferência. Depois, você deve baixar o arquivo Sparkfun-MP3-Player-Shield-Arduino-Library-master.zip neste link.
Dentro desse arquivo, você tem as pastas SdFAT e SFEMP3Shield, que são as bibliotecas que devem ser extraídas e colocadas na pasta LIBRARIES dentro da IDE do seu Arduino.
Ligação MP3 Player Shield no Arduino
Se você vai usar a placa como “shield”, basta encaixá-la no Arduino e seguir o próximo passo. Se você for utilizar apenas os pinos básicos, sua ligação ficará assim:
O próximo passo é você gravar alguns arquivos MP3 no cartão SD, que deve ter sido formatado previamente no formato FAT ou FAT32. Lembre-se que por ser formato FAT, os arquivos devem seguir o formato 8.3, ou seja. O nome do arquivo deve conter 8 caracteres, mais 3 caracteres para a extensão.
Assim, no exemplo que vamos utilizar, os nomes dos arquivos devem ser track001.MP3, track002.MP3, e assim sucessivamente.
Programa controle de músicas com Arduino
Carregue o programa abaixo, baseado no arquivo de exemplo que já vem na biblioteca SFEMP3Shield:
//Programa : Teste MP3 Player Sparkfun //Autor : Arduino e Cia //Baseador no programa original de //author Bill Porter //author Michael P. Flaga #include <SPI.h> //Bibliotecas para cartao SD #include <SdFat.h> #include <SdFatUtil.h> //Biblioteca do MP3 Shield #include <SFEMP3Shield.h> SdFat sd; SFEMP3Shield MP3player; void setup() { uint8_t result; Serial.begin(115200); Serial.print(F("F_CPU = ")); Serial.println(F_CPU); Serial.print(F("Free RAM = ")); Serial.print(FreeRam(), DEC); Serial.println(F(" Should be a base line of 1028, on ATmega328 when using INTx")); //Inicializa o cartao SD if(!sd.begin(SD_SEL, SPI_FULL_SPEED)) sd.initErrorHalt(); // depending upon your SdCard environment, SPI_HAVE_SPEED may work better. if(!sd.chdir("/")) sd.errorHalt("sd.chdir"); //Inicializa o MP3 Player Shield result = MP3player.begin(); //Verifica se ha erros na conexao if(result != 0) { Serial.print(F("Error code: ")); Serial.print(result); Serial.println(F(" when trying to start MP3 player")); } #if defined(__BIOFEEDBACK_MEGA__) // or other reasons, of your choosing. // Typically not used by most shields, hence commented out. Serial.println(F("Applying ADMixer patch.")); if(MP3player.ADMixerLoad("admxster.053") == 0) { Serial.println(F("Setting ADMixer Volume.")); MP3player.ADMixerVol(-3); } #endif help(); } void loop() { MP3player.available(); if(Serial.available()) { parse_menu(Serial.read()); // get command from serial input } delay(100); } uint32_t millis_prv; void parse_menu(byte key_command) { uint8_t result; //Armazena o titulo da musica char title[30]; //Armazena o nome do artista char artist[30]; //Armazena o nome do album char album[30]; Serial.print(F("Received command: ")); Serial.write(key_command); Serial.println(F(" ")); //Caso s seja recebido, para a reproducao if(key_command == 's') { Serial.println(F("Stopping")); MP3player.stopTrack(); //Caso um numero de 1 a 9 seja recebido, //reproduz o arquivo MP3 correspondente } else if(key_command >= '1' && key_command <= '9') { //convert ascii numbers to real numbers key_command = key_command - 48; #if USE_MULTIPLE_CARDS sd.chvol(); // assign desired sdcard's volume. #endif //Comando para o shield reproduzir a musica result = MP3player.playTrack(key_command); //Checa por erros na reproducao if(result != 0) { Serial.print(F("Error code: ")); Serial.print(result); Serial.println(F(" when trying to play track")); } else { Serial.println(F("Playing:")); MP3player.trackTitle((char*)&title); MP3player.trackArtist((char*)&artist); MP3player.trackAlbum((char*)&album); //Imprime as informacoes sobre a musica reproduzida Serial.write((byte*)&title, 30); Serial.println(); Serial.print(F("by: ")); Serial.write((byte*)&artist, 30); Serial.println(); Serial.print(F("Album: ")); Serial.write((byte*)&album, 30); Serial.println(); } //+/- altera volume da musica } else if((key_command == '-') || (key_command == '+')) { union twobyte mp3_vol; mp3_vol.word = MP3player.getVolume(); if(key_command == '-') { // note dB is negative // assume equal balance and use byte[1] for math if(mp3_vol.byte[1] >= 254) { // range check mp3_vol.byte[1] = 254; } else { mp3_vol.byte[1] += 2; // keep it simpler with whole dB's } } else { if(mp3_vol.byte[1] <= 2) { // range check mp3_vol.byte[1] = 2; } else { mp3_vol.byte[1] -= 2; } } // push byte[1] into both left and right assuming equal balance. MP3player.setVolume(mp3_vol.byte[1], mp3_vol.byte[1]); // commit new volume Serial.print(F("Volume changed to -")); Serial.print(mp3_vol.byte[1]>>1, 1); Serial.println(F("[dB]")); //< ou > altera a velocidade de reproducao } else if((key_command == '>') || (key_command == '<')) { uint16_t playspeed = MP3player.getPlaySpeed(); // note playspeed of Zero is equal to ONE, normal speed. if(key_command == '>') { // note dB is negative // assume equal balance and use byte[1] for math if(playspeed >= 254) { // range check playspeed = 5; } else { playspeed += 1; // keep it simpler with whole dB's } } else { if(playspeed == 0) { // range check playspeed = 0; } else { playspeed -= 1; } } MP3player.setPlaySpeed(playspeed); // commit new playspeed Serial.print(F("playspeed to ")); Serial.println(playspeed, DEC); /* Alterativly, you could call a track by it's file name by using playMP3(filename); But you must stick to 8.1 filenames, only 8 characters long, and 3 for the extension */ } else if(key_command == 'f' || key_command == 'F') { uint32_t offset = 0; if (key_command == 'F') { offset = 2000; } //create a string with the filename char trackName[] = "track001.mp3"; #if USE_MULTIPLE_CARDS sd.chvol(); // assign desired sdcard's volume. #endif //tell the MP3 Shield to play that file result = MP3player.playMP3(trackName, offset); //check result, see readme for error codes. if(result != 0) { Serial.print(F("Error code: ")); Serial.print(result); Serial.println(F(" when trying to play track")); } /* Display the file on the SdCard */ } else if(key_command == 'd') { if(!MP3player.isPlaying()) { // prevent root.ls when playing, something locks the dump. but keeps playing. // yes, I have tried another unique instance with same results. // something about SdFat and its 500byte cache. Serial.println(F("Files found (name date time size):")); sd.ls(LS_R | LS_DATE | LS_SIZE); } else { Serial.println(F("Busy Playing Files, try again later.")); } /* Get and Display the Audio Information */ } else if(key_command == 'i') { MP3player.getAudioInfo(); } else if(key_command == 'p') { if( MP3player.getState() == playback) { MP3player.pauseMusic(); Serial.println(F("Pausing")); } else if( MP3player.getState() == paused_playback) { MP3player.resumeMusic(); Serial.println(F("Resuming")); } else { Serial.println(F("Not Playing!")); } } else if(key_command == 't') { int8_t teststate = MP3player.enableTestSineWave(126); if(teststate == -1) { Serial.println(F("Un-Available while playing music or chip in reset.")); } else if(teststate == 1) { Serial.println(F("Enabling Test Sine Wave")); } else if(teststate == 2) { MP3player.disableTestSineWave(); Serial.println(F("Disabling Test Sine Wave")); } } else if(key_command == 'S') { Serial.println(F("Current State of VS10xx is.")); Serial.print(F("isPlaying() = ")); Serial.println(MP3player.isPlaying()); Serial.print(F("getState() = ")); switch (MP3player.getState()) { case uninitialized: Serial.print(F("uninitialized")); break; case initialized: Serial.print(F("initialized")); break; case deactivated: Serial.print(F("deactivated")); break; case loading: Serial.print(F("loading")); break; case ready: Serial.print(F("ready")); break; case playback: Serial.print(F("playback")); break; case paused_playback: Serial.print(F("paused_playback")); break; case testing_memory: Serial.print(F("testing_memory")); break; case testing_sinewave: Serial.print(F("testing_sinewave")); break; } Serial.println(); } else if(key_command == 'b') { Serial.println(F("Playing Static MIDI file.")); MP3player.SendSingleMIDInote(); Serial.println(F("Ended Static MIDI file.")); #if !defined(__AVR_ATmega32U4__) } else if(key_command == 'm') { uint16_t teststate = MP3player.memoryTest(); if(teststate == -1) { Serial.println(F("Un-Available while playing music or chip in reset.")); } else if(teststate == 2) { teststate = MP3player.disableTestSineWave(); Serial.println(F("Un-Available while Sine Wave Test")); } else { Serial.print(F("Memory Test Results = ")); Serial.println(teststate, HEX); Serial.println(F("Result should be 0x83FF.")); Serial.println(F("Reset is needed to recover to normal operation")); } } else if(key_command == 'e') { uint8_t earspeaker = MP3player.getEarSpeaker(); if(earspeaker >= 3){ earspeaker = 0; } else { earspeaker++; } MP3player.setEarSpeaker(earspeaker); // commit new earspeaker Serial.print(F("earspeaker to ")); Serial.println(earspeaker, DEC); } else if(key_command == 'r') { MP3player.resumeMusic(2000); } else if(key_command == 'R') { MP3player.stopTrack(); MP3player.vs_init(); Serial.println(F("Reseting VS10xx chip")); } else if(key_command == 'g') { int32_t offset_ms = 20000; // Note this is just an example, try your own number. Serial.print(F("jumping to ")); Serial.print(offset_ms, DEC); Serial.println(F("[milliseconds]")); result = MP3player.skipTo(offset_ms); if(result != 0) { Serial.print(F("Error code: ")); Serial.print(result); Serial.println(F(" when trying to skip track")); } } else if(key_command == 'k') { int32_t offset_ms = -1000; // Note this is just an example, try your own number. Serial.print(F("moving = ")); Serial.print(offset_ms, DEC); Serial.println(F("[milliseconds]")); result = MP3player.skip(offset_ms); if(result != 0) { Serial.print(F("Error code: ")); Serial.print(result); Serial.println(F(" when trying to skip track")); } } else if(key_command == 'O') { MP3player.end(); Serial.println(F("VS10xx placed into low power reset mode.")); } else if(key_command == 'o') { MP3player.begin(); Serial.println(F("VS10xx restored from low power reset mode.")); } else if(key_command == 'D') { uint16_t diff_state = MP3player.getDifferentialOutput(); Serial.print(F("Differential Mode ")); if(diff_state == 0) { MP3player.setDifferentialOutput(1); Serial.println(F("Enabled.")); } else { MP3player.setDifferentialOutput(0); Serial.println(F("Disabled.")); } } else if(key_command == 'V') { MP3player.setVUmeter(1); Serial.println(F("Use \"No line ending\"")); Serial.print(F("VU meter = ")); Serial.println(MP3player.getVUmeter()); Serial.println(F("Hit Any key to stop.")); while(!Serial.available()) { union twobyte vu; vu.word = MP3player.getVUlevel(); Serial.print(F("VU: L = ")); Serial.print(vu.byte[1]); Serial.print(F(" / R = ")); Serial.print(vu.byte[0]); Serial.println(" dB"); delay(1000); } Serial.read(); MP3player.setVUmeter(0); Serial.print(F("VU meter = ")); Serial.println(MP3player.getVUmeter()); } else if(key_command == 'T') { uint16_t TrebleFrequency = MP3player.getTrebleFrequency(); Serial.print(F("Former TrebleFrequency = ")); Serial.println(TrebleFrequency, DEC); if (TrebleFrequency >= 15000) { // Range is from 0 - 1500Hz TrebleFrequency = 0; } else { TrebleFrequency += 1000; } MP3player.setTrebleFrequency(TrebleFrequency); Serial.print(F("New TrebleFrequency = ")); Serial.println(MP3player.getTrebleFrequency(), DEC); } else if(key_command == 'E') { int8_t TrebleAmplitude = MP3player.getTrebleAmplitude(); Serial.print(F("Former TrebleAmplitude = ")); Serial.println(TrebleAmplitude, DEC); if (TrebleAmplitude >= 7) { // Range is from -8 - 7dB TrebleAmplitude = -8; } else { TrebleAmplitude++; } MP3player.setTrebleAmplitude(TrebleAmplitude); Serial.print(F("New TrebleAmplitude = ")); Serial.println(MP3player.getTrebleAmplitude(), DEC); } else if(key_command == 'B') { uint16_t BassFrequency = MP3player.getBassFrequency(); Serial.print(F("Former BassFrequency = ")); Serial.println(BassFrequency, DEC); if (BassFrequency >= 150) { // Range is from 20hz - 150hz BassFrequency = 0; } else { BassFrequency += 10; } MP3player.setBassFrequency(BassFrequency); Serial.print(F("New BassFrequency = ")); Serial.println(MP3player.getBassFrequency(), DEC); } else if(key_command == 'C') { uint16_t BassAmplitude = MP3player.getBassAmplitude(); Serial.print(F("Former BassAmplitude = ")); Serial.println(BassAmplitude, DEC); if (BassAmplitude >= 15) { // Range is from 0 - 15dB BassAmplitude = 0; } else { BassAmplitude++; } MP3player.setBassAmplitude(BassAmplitude); Serial.print(F("New BassAmplitude = ")); Serial.println(MP3player.getBassAmplitude(), DEC); } else if(key_command == 'M') { uint16_t monostate = MP3player.getMonoMode(); Serial.print(F("Mono Mode ")); if(monostate == 0) { MP3player.setMonoMode(1); Serial.println(F("Enabled.")); } else { MP3player.setMonoMode(0); Serial.println(F("Disabled.")); } #endif } else if(key_command == 'h') { help(); } // print prompt after key stroke has been processed. Serial.print(F("Time since last command: ")); Serial.println((float) (millis() - millis_prv)/1000, 2); millis_prv = millis(); Serial.print(F("Enter s,1-9,+,-,>,<,f,F,d,i,p,t,S,b")); #if !defined(__AVR_ATmega32U4__) Serial.print(F(",m,e,r,R,g,k,O,o,D,V,B,C,T,E,M:")); #endif Serial.println(F(",h :")); } //Imprime o menu de opcoes void help() { Serial.println(F("Arduino SFEMP3Shield Library Example:")); Serial.println(F(" courtesy of Bill Porter & Michael P. Flaga")); Serial.println(F("COMMANDS:")); Serial.println(F(" [1-9] to play a track")); Serial.println(F(" [f] play track001.mp3 by filename example")); Serial.println(F(" [F] same as [f] but with initial skip of 2 second")); Serial.println(F(" [s] to stop playing")); Serial.println(F(" [d] display directory of SdCard")); Serial.println(F(" [+ or -] to change volume")); Serial.println(F(" [> or <] to increment or decrement play speed by 1 factor")); Serial.println(F(" [i] retrieve current audio information (partial list)")); Serial.println(F(" [p] to pause.")); Serial.println(F(" [t] to toggle sine wave test")); Serial.println(F(" [S] Show State of Device.")); Serial.println(F(" [b] Play a MIDI File Beep")); #if !defined(__AVR_ATmega32U4__) Serial.println(F(" [e] increment Spatial EarSpeaker, default is 0, wraps after 4")); Serial.println(F(" [m] perform memory test. reset is needed after to recover.")); Serial.println(F(" [M] Toggle between Mono and Stereo Output.")); Serial.println(F(" [g] Skip to a predetermined offset of ms in current track.")); Serial.println(F(" [k] Skip a predetermined number of ms in current track.")); Serial.println(F(" [r] resumes play from 2s from begin of file")); Serial.println(F(" [R] Resets and initializes VS10xx chip.")); Serial.println(F(" [O] turns OFF the VS10xx into low power reset.")); Serial.println(F(" [o] turns ON the VS10xx out of low power reset.")); Serial.println(F(" [D] to toggle SM_DIFF between inphase and differential output")); Serial.println(F(" [V] Enable VU meter Test.")); Serial.println(F(" [B] Increament bass frequency by 10Hz")); Serial.println(F(" [C] Increament bass amplitude by 1dB")); Serial.println(F(" [T] Increament treble frequency by 1000Hz")); Serial.println(F(" [E] Increament treble amplitude by 1dB")); #endif Serial.println(F(" [h] this help")); }
Carregue o programa no Arduino e abra o Serial Monitor. Antes de mais nada, selecione a velocidade de comunicação para 115200, conforme destacado. Um menu de opções será exibido, e você pode selecionar as músicas, alterar o volume e a velocidade de reprodução, tudo através do serial monitor, bastando enviar os caracteres correspondentes:
Assim, pressione 1 para reproduzir o arquivo track001.mp3, 2 para reproduzir o arquivo track002.mp3, e assim por diante.
Esse é apenas um exemplo de utilização. Informações completas e detalhadas sobre esse shield você pode obter acessando diretamente o site do produto na Sparkfun, nesse link.
Gostou? Confira outros posts usando módulos MP3 aqui mesmo no Arduino e Cia!