Arduino筆記(88):DF Player mini製作MP3播放器

一位好友幫忙代購淘寶的電子零件,建議我買DFPlayer mini這個模組,可以用來播放mp3音樂。一看價格覺得還可以,就加到購物清單中。利用一點點空檔時間,實作一下如何使用這個模組。我找了程式範本只有控制音樂前進一首、暫停及後退一首三個按鍵,要調整音量,要在一開始時設定,再上傳程式,覺得很麻煩。我增加控制聲音按鍵並修改程式在播放音樂時可以調整音量。
除此,我想到使用Web的方式來調整音量、控制歌曲往前或往後一首歌,方法是使用 NodeMCU 連接DFPlayer Mini,建立一個網頁在ESP8266,透過網頁控制前後一首歌及音量,有空時再來動手做看看是否能成功。


DFPlayer mini產品規格:
  • 支持取樣速率(KHz):8/11.025/12/16/22.05/24/32/44.1/48
  • 24位元DAC輸出,動態範圍支援:90dB,信噪比支持:85dB
  • 完全支持FAT16、FAT32檔案系統,最大支持32G的TF卡,支持32G的U盤、64M位元組的NORFLASH
  • 多種控制模式可選:IO控制模式、串口模式、AD按鍵控制模式
  • 廣播語插播功能,可以暫停正在播放的背景音樂。廣告播放完畢回到背景音繼續播放
  • 音訊資料按資料夾排序,最多支援100個資料夾,每隔資料夾可以分配255首曲目
  • 模組可播放MP3、WAV、WMA三種格式硬體解碼
  • 30級音量可調,6級EQ可調
DFPlayer mini的接腳圖,來源:dfrobot.com

DFPlayer  mini 接腳說明:
接腳編號接腳名稱功能描述備註
1VCC模組電源輸入3.3V~5V,建議5V,不要超過5.2V
2RX UART串列資料接收
3TX UART串列資料輸出
4 DAC_R 音訊輸出右聲道驅動耳機、功率放大機
5 DAC_L 音訊輸出左聲道驅動耳機、功率放大機
6SPK2接小喇叭驅動小於3W喇叭
7 GND 接地
8SPK1接小喇叭驅動小於3W喇叭
9IO1觸發口預設上一曲(長按音量減)
10 GND 接地
11IO2觸發口預設下一曲(長按音量加)
12 ADKEY1 AD口1當觸發時是第一首(長按迴圈第一首)
13 ADKEY2 AD口2當觸發時是第五首(長按迴圈第五首)
14 USB+ USB+ DP 接USB拇指碟或插電腦的USB口
15 USB- USB- DM 接USB拇指碟或插電腦的USB口
16 Busy 播放狀態有音訊,輸出低;無音訊,輸出高

DFPlayer Mini串列埠指令格式,這是要透過串列埠傳送給DFPlayer mini的指令,總共有10個(checksum分成高及低兩個位元),可參考以程式 execute_CMD()這段函式的內容,透過陣列方式,經由串列埠傳送10個參數給DFPlayer mini。
指令名稱對應功能功能描述
$S起始位0x7E 每則命令回饋均以$開頭,即0x7E
VER版本版本資訊[目前預設為0xFF]
Len len後位元組個數checksum不計算在內
CMD命令字表示特定的操作,如播放/暫停等
Feedback命令回饋是否需要回饋資訊,1回饋,0不回饋
para1參數1查詢的資料高位元組(比如歌曲序號)
para2參數2查詢的資料低位元組
checksum校驗和[占兩個位元組]累加和校驗[不計起始位$]
$0結束位結束位0xEF

上述指令的第四個參數是CMD,可代入以下控制指令值來執行其功能,如0x01會讓DFPlayer mini跳到下一首歌。
CMD命令(指令)对应的功能參數(16位)
0x01下一曲
0x02上一曲
0x03指定曲目(NUM)1-2999
0x04音量+
0x05音量-
0x06指定音量0-30
0x07指定EQ 0/1/2/3/4/5 Normal/Pop/Rock/Jazz/Classic/Bass
0x08單曲迴圈指定曲目播放1-2999
0x09指定播放設備 1/2/3/4/5 U盤/SD/AUX/SLEEP/FLASH
0x0A進入休眠——低功耗
0x0B保留
0x0C模組重定
0x0D播放
0x0E暫停
0x0F指定資料夾播放1-10(需要自己設定)
0x10擴音設置(無)[DH=1:開擴音][DL:設置增益0-31]
0x11全部迴圈播放[1:迴圈播放][0:停止迴圈播放]
0x12指定MP3資料夾曲目1-9999
0x13插播廣告1-9999
0x14支持15個資料夾見下面的詳細說明
0x15停止播放,播放背景
0x16停止播放

如果要查詢DFPlayer mini的狀態,可以將上述CMD參數,代入以下控制指令值來執行其功能,如0x43會回應目前的音量值。
CMD指令詳解功能說明對應參數(16位元)
0x3C STAY-
0x3DSTAY-
0x3ESTAY-
0x3F發送初始化參數0-0x0F(低四位元每位元代表一種設備)
0x40返回錯誤,請求重發-
0x41應答-
0x42查詢當前狀態-
0x43查詢當前音量-
0x44詢當前EQ-
0x45查詢當前播放模式該版本保留此功能
0x46查詢當前軟體版本該版本保留此功能
0x47查詢UDISK的總文件數-
0x48查詢TF卡的總文件數-
0x49查詢FLASH卡的總文件數-
0x4A保留-
0x4B查詢UDISK的當前曲目-
0x4C查詢TF的當前曲目-
0x4D查詢FLASH的當前曲目-

[材料]

  • Arduino Uno   x 1
  • DFPlayer Mini 模組   x1
  • 麵包板 x1
  • 按鍵 x5
  • 電阻 1K x1
  • 喇叭 x1
  • 連接線 n 條

[接線圖]

Arduino UnoDFPlayer Mini其他
VCCVCC-
GNDGND-
D10TX-
D11接一個1K歐姆的電阻後再接RX-
D2-接按鍵1,按鍵另一端接地(前一首按鍵)
D3-接按鍵2,按鍵另一端接地(暫停/開始按鍵)
D4-接按鍵3,按鍵另一端接地(下一首按鍵)
D5-接按鍵4,按鍵另一端接地(升高音量按鍵)
D6-接按鍵5,按鍵另一端接地(降低音量按鍵)
-SPK1接喇叭一端
-SPK2接喇叭另一端

[程式]

#include "SoftwareSerial.h"
SoftwareSerial mySerial(10, 11);

# define Start_Byte 0x7E
# define Version_Byte 0xFF
# define Command_Length 0x06
# define End_Byte 0xEF
# define Acknowledge 0x00  //Returns info with command 0x41 [0x01: info, 0x00: no info]

# define ACTIVATED LOW

int buttonNext = 2;
int buttonPause = 3;
int buttonPrevious = 4;
int buttonVolumeUp = 5;
int buttonVolumeDown = 6;
boolean isPlaying = false;

void setup () {
  pinMode(buttonPause, INPUT);
  digitalWrite(buttonPause,HIGH);
  pinMode(buttonNext, INPUT);
  digitalWrite(buttonNext,HIGH);
  pinMode(buttonPrevious, INPUT);
  digitalWrite(buttonPrevious,HIGH);

  pinMode(buttonVolumeUp, INPUT);
  digitalWrite(buttonVolumeUp,HIGH);  
  pinMode(buttonVolumeDown, INPUT);
  digitalWrite(buttonVolumeDown,HIGH);    

  mySerial.begin (9600);
  delay(1000);
  playFirst();
  isPlaying = true;
}

void loop () { 
 if (digitalRead(buttonPause) == ACTIVATED)  //暫停按鍵
  {
    if(isPlaying)
    {
      pause();
      isPlaying = false;
    }else
    {
      isPlaying = true;
      play();
    }
  }

 if (digitalRead(buttonNext) == ACTIVATED) //下一首按鍵
  {
    if(isPlaying)
    {
      playNext();
    }
  }

   if (digitalRead(buttonPrevious) == ACTIVATED)  //前一首按鍵
  {
    if(isPlaying)
    {
      playPrevious();
    }
  }
 if (digitalRead(buttonVolumeUp) == ACTIVATED)  //升高聲音鍵
  {
    if(isPlaying)
    {
      voiceup();
    }
  }
  
 if (digitalRead(buttonVolumeDown) == ACTIVATED) //降低聲音鍵
  {
    if(isPlaying)
    {
      voicedown();
    }
  }  
}

void playFirst()
{
  execute_CMD(0x3F, 0, 0);
  delay(500);
  setVolume(20);   // 初次播放的預設的音量
  delay(500);
  execute_CMD(0x11,0,1); 
  delay(500);
}

void pause()
{
  execute_CMD(0x0E,0,0);  //暫停播放
  delay(500);
}

void play()
{
  execute_CMD(0x0D,0,1);  //播放音樂
  delay(500);
}

void playNext()
{
  execute_CMD(0x01,0,1);  //播放下一首
  delay(500);
}

void playPrevious()
{
  execute_CMD(0x02,0,1);  //播放前一首
  delay(500);
}

void voiceup()
{
  execute_CMD(0x04,0,1);  //增加音量
  delay(500);
}

void voicedown()
{
  execute_CMD(0x05,0,1);  //降低音量
  delay(500);
}

void setVolume(int volume)
{
  execute_CMD(0x06, 0, volume); // Set the volume (0x00~0x30)
  delay(2000);
}

// 執行命令及傳入參數
void execute_CMD(byte CMD, byte Par1, byte Par2) {
  // 計算checksum (2 bytes)
  word checksum = -(Version_Byte + Command_Length + CMD + Acknowledge + Par1 + Par2);

  // 建立命令列
  byte Command_line[10] = { Start_Byte, Version_Byte, Command_Length, CMD, Acknowledge,
  Par1, Par2, highByte(checksum), lowByte(checksum), End_Byte};

  //送出命令列給模組
  for (byte k=0; k<10; k++){
    mySerial.write( Command_line[k]);
  }
}

[結果]

實作中的麵包板,最左方的按鍵是「前一首」,其次是「暫停」及「下一首」,最右邊兩個分別是「升高音量」及「降低音量」。

4 留言

  1. https://www.webteach.tw/?p=1204
    這塊我也有玩,可以單獨使用很方便 多塊18650的 充放電板就可以當播放機。

    回覆刪除
    回覆
    1. 我還以為要搭配控制板才可以用,原來只要電池供電就可以播放歌曲,學到經驗了,謝謝分享!

      刪除
  2. 你好
    我想指定歌曲跟單曲迴圈指定曲目播放的功能,請問如何寫程式?

    回覆刪除
  3. 你好, 請問D11為什麼要先接電組再接到RX ??

    回覆刪除

張貼留言

較新的 較舊