學習目標 : 認識faya MP3模組的功能及使用方式
學習時間 : 60~90 mins
示範模組 : (1) faya brickNano
(2) faya MP3模組
(3) faya SD卡模組
(4) faya雙聲道喇叭模組 (或自備耳機)
工具 : 積木底板、音源線、SD卡
====================功能介紹====================
faya MP3模組使用MP3解碼晶片(代號VS1053B),透過簡單的接線後,只要對第三方所提供的函式下指令,就能從SD卡讀取MP3檔案並播放,函示庫可以到這裡下載,解壓縮後放在Arduino資料夾裡的library裡面。
介紹指令前,先看一下faya MP3模組的外觀,它的左邊有七個埠,分別是RST、DREQ、MISO、MOSI、SCK、XDCS、XCS,其中MISO、MOSI、SCK屬於SPI通訊協定,用來和Arduion互相溝通。
Arduino 的SPI通訊有固定的腳位,對於 faya brickNano而言,我們要把SCK接在D13位置、MISO接在D12位置、MOSI接在D11的位置。
- #include <SFEMP3Shield.h>
使用MP3模組函示庫,還需要引入SD與SPI的函示庫。
- #include <SdFat.h>
- #include <SdFatUtil.h>
使用SD卡模組函示庫。
- #include <SPI.h>
引入SPI介面。
- SdFat 物件名稱;
此指令建構了SD卡模組的物件,物件名稱 : 可自行命名。
- SFEMP3Shield 物件名稱;
此指令建構了MP3模組的物件,物件名稱 : 可自行命名。
其他函式功能,大家可以透過Libraries裡的.h檔案,查看呼叫方式
====================原理知識====================
模組電路圖如下所示:
====================範例實作(一)====================
了解模組功能(原理)後,我們用以下範例來展示模組的功能,我們直接利用官方所提供的程式,加了些註解,讓使用者可以看到MP3的函式的全部功能,未來要使用此模組時,直接複製裡面的函示來用即可。
目標:
目標:
(1) 利用MP3模組撥放SD卡裡面的音樂
(2) 使用Serial Monitor,控制MP3模組的撥放與各種功能
(3) 利用faya雙聲道喇叭模組撥放MP3的音樂
(2) 使用Serial Monitor,控制MP3模組的撥放與各種功能
(3) 利用faya雙聲道喇叭模組撥放MP3的音樂
接線:
Arduino_D11 ===> SD卡模組_MOSI
Arduino_D13 ===> SD卡模組_SCLK
Arduino_D12 ===> SD卡模組_MISO
需要連接的訊號線比往常都還要多,如果要連的整齊一點,可以參考以下連接方式
首先將MP3和SD卡模組的SPI介面MOSI, SCLK, MISO對連,注意到MP3模組的SCLK標示為SCK,如下圖中紫色的單芯線。
接著將MP3模組的RST, DREQ, XDCS, XS分別連到Arduino的D8, D2, D7, D6腳位,如下圖中紅色單芯線
然後將MP3模組的MISO和MOSI分別連到Arduino的D12和D11腳位,如下圖中的黃色單芯線
(3) 音源線連接 - 將音源線插入MP3模組和雙聲道喇叭模組的音源座
安裝SD卡:
將MP3檔案透過讀卡機或筆電的SD卡插槽複製到SD卡裡面,MP3的檔名必須符合程式的格式,從TRACK000.MP3開始編起,第一首歌TRACK000.mp3,第二首歌TRACK001.MP3,依此類推,複製完成後,再將SD卡插到SD卡模組。
範例程式:Arduino_D13 ===> SD卡模組_SCLK
Arduino_D12 ===> SD卡模組_MISO
MP3模組接法如下 :
Arduino_D8 ===> MP3模組_RST
Arduino_D2 ===> MP3模組_DREQ
Arduino_D12 ===> MP3模組_MISO
Arduino_D11 ===> MP3模組_MOSI
Arduino_D13 ===> MP3模組_SCK
Arduino_D7 ===> MP3模組_XDCS
Arduino_D6 ===> MP3模組_XCS
Arduino_D12 ===> MP3模組_MISO
Arduino_D11 ===> MP3模組_MOSI
Arduino_D13 ===> MP3模組_SCK
Arduino_D7 ===> MP3模組_XDCS
Arduino_D6 ===> MP3模組_XCS
需要連接的訊號線比往常都還要多,如果要連的整齊一點,可以參考以下連接方式
首先將MP3和SD卡模組的SPI介面MOSI, SCLK, MISO對連,注意到MP3模組的SCLK標示為SCK,如下圖中紫色的單芯線。
接著將MP3模組的RST, DREQ, XDCS, XS分別連到Arduino的D8, D2, D7, D6腳位,如下圖中紅色單芯線
然後將MP3模組的MISO和MOSI分別連到Arduino的D12和D11腳位,如下圖中的黃色單芯線
最後將SD卡模組的CS和SCLK分別連接到Arduino的D9和D13腳位,如下圖中的綠色單芯線
(3) 音源線連接 - 將音源線插入MP3模組和雙聲道喇叭模組的音源座
將MP3檔案透過讀卡機或筆電的SD卡插槽複製到SD卡裡面,MP3的檔名必須符合程式的格式,從TRACK000.MP3開始編起,第一首歌TRACK000.mp3,第二首歌TRACK001.MP3,依此類推,複製完成後,再將SD卡插到SD卡模組。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 2018/02/08 | |
// Faya-Nugget 範例程式 (mp3_1.ino) | |
// 單元: 模組介紹-faya MP3模組 | |
// 網址: https://fayalab.blogspot.com/2019/03/mp3.html | |
// 目標: (1) 利用MP3模組撥放SD卡裡面的音樂 | |
// (2) 使用Serial Monitor,控制MP3模組的撥放與各種功能 | |
// (3) 利用faya雙聲道喇叭模組撥放MP3的音樂 | |
// 接線: Arduino ==> faya模組 | |
// D9 ==> SD卡模組_CS | |
// D11 ==> SD卡模組_MOSI | |
// D13 ==> SD卡模組_SCLK | |
// D12 ==> SD卡模組_MISO | |
// D8 ==> MP3模組_RST | |
// D2 ==> MP3模組_DREQ | |
// D12 ==> MP3模組_MISO | |
// D11 ==> MP3模組_MOSI | |
// D13 ==> MP3模組_SCK | |
// D7 ==> MP3模組_XDCS | |
// D6 ==> MP3模組_XCS | |
#include <SPI.h> //匯入SPI的library | |
#include <SdFat.h> //匯入SD卡模組的library | |
#include <SdFatUtil.h> | |
#include <SFEMP3Shield.h> //匯入MP3模組的library | |
// Below is not needed if interrupt driven. Safe to remove if not using. | |
#if defined(USE_MP3_REFILL_MEANS) && USE_MP3_REFILL_MEANS == USE_MP3_Timer1 | |
#include <TimerOne.h> | |
#elif defined(USE_MP3_REFILL_MEANS) && USE_MP3_REFILL_MEANS == USE_MP3_SimpleTimer | |
#include <SimpleTimer.h> | |
#endif | |
/** | |
* \brief Object instancing the SdFat library. | |
* | |
* principal object for handling all SdCard functions. | |
*/ | |
SdFat sd; //建構SdFat物件並定義 | |
/** | |
* \brief Object instancing the SFEMP3Shield library. | |
* | |
* principal object for handling all the attributes, members and functions for the library. | |
*/ | |
SFEMP3Shield MP3player; //建構SFEMP3Shield物件並定義 | |
int16_t last_ms_char; // milliseconds of last recieved character from Serial port. Serial port最後收到的字符的毫秒數 | |
int8_t buffer_pos; // next position to recieve character from Serial port. 下一個從Serial port接收字符的位置。 | |
//------------------------------------------------------------------------------ | |
/** | |
* \brief Setup the Arduino Chip's feature for our use. | |
* | |
* After Arduino's kernel has booted initialize basic features for this | |
* application, such as Serial port and MP3player objects with .begin. | |
* Along with displaying the Help Menu. | |
* | |
* \note returned Error codes are typically passed up from MP3player. | |
* Whicn in turns creates and initializes the SdCard objects. | |
* | |
* \see | |
* \ref Error_Codes | |
*/ | |
char buffer[6]; // 0-35K+null 建立字元BUFFER存放 | |
void setup() { | |
uint8_t result; //result code from some function as to be tested at later time. | |
Serial.begin(115200); | |
Serial.print(F("F_CPU = ")); | |
Serial.println(F_CPU); | |
Serial.print(F("Free RAM = ")); // available in Version 1.0 F() bases the string to into Flash, to use less SRAM. | |
Serial.print(FreeRam(), DEC); // FreeRam() is provided by SdFatUtil.h | |
Serial.println(F(" Should be a base line of 1017, on ATmega328 when using INTx")); | |
//Initialize the SdCard. 初始化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"); | |
//Initialize the MP3 Player Shield 初始化MP3模組 | |
result = MP3player.begin(); | |
//check result, see readme for error codes. | |
if(result != 0) { | |
Serial.print(F("Error code: ")); | |
Serial.print(result); | |
Serial.println(F(" when trying to start MP3 player")); | |
if( result == 6 ) { | |
Serial.println(F("Warning: patch file not found, skipping.")); // can be removed for space, if needed. | |
Serial.println(F("Use the \"d\" command to verify SdCard can be read")); // can be removed for space, if needed. | |
} | |
} | |
#if (0) | |
// 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(); // 呼叫help指令 | |
last_ms_char = millis(); // stroke the inter character timeout. | |
buffer_pos = 0; // start the command string at zero length. | |
parse_menu('l'); // display the list of files to play | |
} | |
//------------------------------------------------------------------------------ | |
/** | |
* \brief Main Loop the Arduino Chip | |
* | |
* This is called at the end of Arduino kernel's main loop before recycling. | |
* And is where the user's serial input of bytes are read and analyzed by | |
* parsed_menu. | |
* | |
* Additionally, if the means of refilling is not interrupt based then the | |
* MP3player object is serviced with the availaible function. | |
* | |
* \note Actual examples of the libraries public functions are implemented in | |
* the parse_menu() function. | |
*/ | |
void loop() { | |
// Below is only needed if not interrupt driven. Safe to remove if not using. | |
#if defined(USE_MP3_REFILL_MEANS) \ | |
&& ( (USE_MP3_REFILL_MEANS == USE_MP3_SimpleTimer) \ | |
|| (USE_MP3_REFILL_MEANS == USE_MP3_Polled) ) | |
MP3player.available(); | |
#endif | |
char inByte; | |
if (Serial.available() > 0) { | |
inByte = Serial.read(); | |
if ((0x20 <= inByte) && (inByte <= 0x126)) { // strip off non-ASCII, such as CR or LF | |
if (isDigit(inByte)) { // macro for ((inByte >= '0') && (inByte <= '9')) | |
// else if it is a number, add it to the string | |
buffer[buffer_pos++] = inByte; | |
} else { | |
// input char is a letter command | |
buffer_pos = 0; | |
parse_menu(inByte); | |
} | |
buffer[buffer_pos] = 0; // update end of line | |
last_ms_char = millis(); // stroke the inter character timeout. | |
} | |
} else if ((millis() - last_ms_char) > 500 && ( buffer_pos > 0 )) { | |
// ICT expired and have something | |
if (buffer_pos == 1) { | |
// look for single byte (non-number) menu commands | |
parse_menu(buffer[buffer_pos - 1]); | |
} else if (buffer_pos > 5) { | |
// dump if entered command is greater then uint16_t | |
Serial.println(F("Ignored, Number is Too Big!")); | |
} else { | |
// otherwise its a number, scan through files looking for matching index. | |
int16_t fn_index = atoi(buffer); | |
SdFile file; | |
char filename[13]; | |
sd.chdir("/",true); | |
uint16_t count = 1; | |
while (file.openNext(sd.vwd(),O_READ)) | |
{ | |
file.getFilename(filename); | |
if ( isFnMusic(filename) ) { | |
if (count == fn_index) { | |
Serial.print(F("Index ")); | |
SerialPrintPaddedNumber(count, 5 ); | |
Serial.print(F(": ")); | |
Serial.println(filename); | |
Serial.print(F("Playing filename: ")); | |
Serial.println(filename); | |
int8_t result = MP3player.playMP3(filename); | |
//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")); | |
} | |
char title[30]; // buffer to contain the extract the Title from the current filehandles | |
char artist[30]; // buffer to contain the extract the artist name from the current filehandles | |
char album[30]; // buffer to contain the extract the album name from the current filehandles | |
MP3player.trackTitle((char*)&title); | |
MP3player.trackArtist((char*)&artist); | |
MP3player.trackAlbum((char*)&album); | |
//print out the arrays of track information | |
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(); | |
break; | |
} | |
count++; | |
} | |
file.close(); | |
} | |
} | |
//reset buffer to start over | |
buffer_pos = 0; | |
buffer[buffer_pos] = 0; // delimit | |
} | |
delay(100); | |
} | |
uint32_t millis_prv; | |
//------------------------------------------------------------------------------ | |
/** | |
* \brief Decode the Menu. | |
* | |
* Parses through the characters of the users input, executing corresponding | |
* MP3player library functions and features then displaying a brief menu and | |
* prompting for next input command. | |
*/ | |
void parse_menu(byte key_command) { | |
uint8_t result; // result code from some function as to be tested at later time. | |
// Note these buffer may be desired to exist globably. | |
// but do take much space if only needed temporarily, hence they are here. | |
char title[30]; // buffer to contain the extract the Title from the current filehandles | |
char artist[30]; // buffer to contain the extract the artist name from the current filehandles | |
char album[30]; // buffer to contain the extract the album name from the current filehandles | |
Serial.print(F("Received command: ")); | |
Serial.write(key_command); | |
Serial.println(F(" ")); | |
//if s, stop the current track | |
if(key_command == 's') { | |
Serial.println(F("Stopping")); | |
MP3player.stopTrack(); | |
//if 1-9, play corresponding track | |
} 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 | |
//tell the MP3 Shield to play a track | |
result = MP3player.playTrack(key_command); | |
//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")); | |
} else { | |
Serial.println(F("Playing:")); | |
//we can get track info by using the following functions and arguments | |
//the functions will extract the requested information, and put it in the array we pass in | |
MP3player.trackTitle((char*)&title); | |
MP3player.trackArtist((char*)&artist); | |
MP3player.trackAlbum((char*)&album); | |
//print out the arrays of track information | |
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(); | |
} | |
//if +/- to change volume | |
} else if((key_command == '-') || (key_command == '+')) { | |
union twobyte mp3_vol; // create key_command existing variable that can be both word and double byte of left and right. | |
mp3_vol.word = MP3player.getVolume(); // returns a double uint8_t of Left and Right packed into int16_t | |
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]")); | |
//if < or > to change Play Speed | |
} else if((key_command == '>') || (key_command == '<')) { | |
uint16_t playspeed = MP3player.getPlaySpeed(); // create key_command existing variable | |
// 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 | |
/* List out music files on the SdCard */ | |
} else if(key_command == 'l') { | |
if(!MP3player.isPlaying()) { | |
Serial.println(F("Music Files found :")); | |
SdFile file; | |
char filename[13]; | |
sd.chdir("/",true); | |
uint16_t count = 1; | |
while (file.openNext(sd.vwd(),O_READ)) | |
{ | |
file.getFilename(filename); | |
if ( isFnMusic(filename) ) { | |
SerialPrintPaddedNumber(count, 5 ); | |
Serial.print(F(": ")); | |
Serial.println(filename); | |
count++; | |
} | |
file.close(); | |
} | |
Serial.println(F("Enter Index of File to play")); | |
} else { | |
Serial.println(F("Busy Playing Files, try again later.")); | |
} | |
} 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(",l,h :")); | |
} | |
//------------------------------------------------------------------------------ | |
/** | |
* \brief Print Help Menu. | |
* | |
* Prints a full menu of the commands available along with descriptions. | |
*/ | |
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(" [l] Display list of music files")); | |
Serial.println(F(" [0####] Enter index of file to play, zero pad! e.g. 01-65534")); | |
Serial.println(F(" [h] this help")); | |
} | |
void SerialPrintPaddedNumber(int16_t value, int8_t digits ) { | |
int currentMax = 10; | |
for (byte i=1; i<digits; i++){ | |
if (value < currentMax) { | |
Serial.print("0"); | |
} | |
currentMax *= 10; | |
} | |
Serial.print(value); | |
} |
備註:
完成燒錄後,打開串列埠傳輸介面,傳輸速率選擇115200,畫面會顯示歡迎畫面、功能介紹和列出SD卡內的MP3清單
[l]:小寫L,顯示MP3歌曲清單,左邊是編號,右邊是檔案名稱
[1-9] : 輸入數字撥放清單上的編號歌曲
[p] : 暫停/回復撥放
[s]: 停止撥放
[+ or -] : 改變聲音大小
[> or <] : 改變撥放速度
[l] Display list of music files
[h] : 顯示所有指令
範例結果:
- 你可以試著加入硬體按鈕直接控制MP3晶片,這樣就可以不用依賴Serial Monitor介面,脫離電腦變成一台獨立的MP3撥放器,只要一顆行動電源就可以選歌聽歌,這樣是不是方便多了呢。
也歡迎大家在底下留言或到我們的粉絲團留言喔!
沒有留言:
張貼留言