New Project (3).png

上一篇介紹了基本的DFPlayer Mini的操作,接下來我們就要更進一步,加上一些操作的控制,像是上一首/下一首,暫停/播放,還有音量的控制。如此一來,整個專題看起來就更完整,更專業囉!

golink

購買Arduino材料最佳選擇:https://www.jmaker.com.tw/

如果你尚未使用過DFPlayer,強烈建議先看上一篇DFPlayer入門教學:
https://blog.jmaker.com.tw/arduino-dfplayer-mp3/

傑森創工獨家提供完整套件,歡迎選購!

https://www.jmaker.com.tw/products/dfplayer-mp3

再次提醒,這個範例是用DFPlayer Mini Mp3 by Makuna函式庫,一定要先行安裝才行哦!
mp3-1.png

接著我們就要接線了,這次多了3個按鈕和1個可變電阻,接線上自然複雜一些,但其實並不難的。

接線方式:
VCC => 5V (接到麵包板上方的紅線處,這樣可以方便所有零件都能使用這個5V)
GND => GND (接到麵包板上方的藍線處,這樣可以方便所有零件都能使用這個GND)
RX => Pin 10 (加1K電阻)
TX => Pin 11
SPK1,SPK2 => 分別接喇叭單體的兩條線,沒有序順限制
下一首按鈕 => Pin 5
播放/暫停按鈕 => Pin 6
上一首按鈕 => Pin 7
以上三個按鈕的另一腳 => GND (接到麵包板上方的藍線插孔即可)
可變電阻中間腳位 => A5

mp3-2-layout.png

程式部份,基本上是由上一篇基本範例進行改寫,重複的部份請參考上一篇說明。
https://blog.jmaker.com.tw/arduino-dfplayer-mp3/

這次主要是新增音量鍵和三個按鈕。我們先看音量旋鈕,這是一個常見的可變電阻,我們透過旋轉的量,用map函式進行換算成0-30的音量質。

另外,我們還加了一個判斷,如果目前音量,不等於可變電阻設定的音量,才將音量設為新的值,不然就不用理會。

再來就是3個按鍵,主要是播放/暫停鍵比較麻煩,我們必須先判斷目前的播放狀態,是不是正在播放中,如果是,就進行暫停的動作;如果不是,就進行播放。

而這裡用的播放是start(),這個函式會自行判斷目前是不是有曲子播到一半被暫停,如果有,就會播著播,如果沒有,就把之前播完的那首,重頭播起。

另兩個按鈕,下一首,上一首就很簡單了,分別用prevTrack()和nextTrack()就搞定了。

這個專題雖然接的線不少,但其實並不難,大家試看看吧!

/*
 * 本範程式為Arduino結合DFPlayer MP3範例程式,加上播放控制,由傑森創工提供
 * 
 * 
 * 請先安裝DFPlayer Mini Mp3 by Makuna函式庫,可由Arduino IDE裡的「程式管理員」進行安裝
 * 建議先看上一篇DFPlayer入門教學:
 * https://blog.jmaker.com.tw/arduino-dfplayer-mp3/
 * 
 * 粉絲團:https://www.facebook.com/jasonshow
 * 傑森創工購物網:https://www.jmaker.com.tw/
 * 傑森創工部落格:https://blog.jmaker.com.tw/
 */
// SD卡上的MP3檔案,必須放在mp3這個目錄,並取名0開頭的4個數字,如:0001.mp3、0002.mp3
// sd:/mp3/0001.mp3
// sd:/mp3/0002.mp3

const int Next_BUTTON_PIN = 5;  // 下一首按鍵的接腳
const int PlayPause_BUTTON_PIN = 6;  // 播放/暫停 按鍵的接腳
const int Prev_BUTTON_PIN = 7;  // 上一首按鍵的接腳


int sensorPin = A5;    //音量控制類比輸入的PIN腳
int sensorValue = 0;  // 類比輸入得到的數值
int volume = 0;       //目前音量


#include <DFMiniMp3.h>  
//使用軟體Serial
#include <SoftwareSerial.h>  
SoftwareSerial mySerial(11, 10); // RX, TX

// 宣告 notify class
//
class Mp3Notify; 

// 定義類型,其中第一個參數為決定用硬體Serial或軟體Serail
//
typedef DFMiniMp3<SoftwareSerial, Mp3Notify> DfMp3;  //如果用UNO板就用軟體Serail
//typedef DFMiniMp3<HardwareSerial, Mp3Notify> DfMp3;  //如果用Mega板就用硬體Serail

// 建立mp3物件
//
DfMp3 dfmp3(mySerial);

DfMp3_Status playOrPause;   // 建立播放狀態物件

// 實作notification的類別,可以在不同的事件中,寫入想要進行的動作
// 若沒有特別要進行的處理,這裡不用修改
class Mp3Notify
{
public:
  static void PrintlnSourceAction(DfMp3_PlaySources source, const char* action)
  {
    if (source & DfMp3_PlaySources_Sd) 
    {
        Serial.print("SD Card, ");
    }
    if (source & DfMp3_PlaySources_Usb) 
    {
        Serial.print("USB Disk, ");
    }
    if (source & DfMp3_PlaySources_Flash) 
    {
        Serial.print("Flash, ");
    }
    Serial.println(action);
  }
  static void OnError([[maybe_unused]] DfMp3& mp3, uint16_t errorCode)
  {
    // 錯誤訊息
    Serial.println();
    Serial.print("Com Error ");
    Serial.println(errorCode);
  }
  static void OnPlayFinished([[maybe_unused]] DfMp3& mp3, [[maybe_unused]] DfMp3_PlaySources source, uint16_t track)
  {
    Serial.print("Play finished for #");
    Serial.println(track);  
  }
  static void OnPlaySourceOnline([[maybe_unused]] DfMp3& mp3, DfMp3_PlaySources source)
  {
    PrintlnSourceAction(source, "online");
  }
  static void OnPlaySourceInserted([[maybe_unused]] DfMp3& mp3, DfMp3_PlaySources source)
  {
    PrintlnSourceAction(source, "inserted");
  }
  static void OnPlaySourceRemoved([[maybe_unused]] DfMp3& mp3, DfMp3_PlaySources source)
  {
    PrintlnSourceAction(source, "removed");
  }
};

void setup() 
{
  Serial.begin(9600); //啟用監控視窗
  Serial.println("initializing...");

  pinMode(Next_BUTTON_PIN, INPUT_PULLUP); //設定按鈕的接腳為輸入
  pinMode(PlayPause_BUTTON_PIN, INPUT_PULLUP); 
  pinMode(Prev_BUTTON_PIN, INPUT_PULLUP); 
  
  dfmp3.begin();  //開始使用DFPlayer模組

  //重置DFPlayer模組,會聽到"波"一聲
  dfmp3.reset();

  //音量控制,0~30
  uint16_t volume = dfmp3.getVolume();
  Serial.print("volume ");
  Serial.println(volume);
  dfmp3.setVolume(24);
  
  //取得所有MP3檔的總數
  uint16_t count = dfmp3.getTotalTrackCount(DfMp3_PlaySource_Sd);
  Serial.print("files ");
  Serial.println(count);

  Serial.println("Play Mp3...");

  // 播放MP3,參數就是第N首。如要播第一首MP3,參數就是1
  dfmp3.playMp3FolderTrack(1);  
}

void loop() 
{
  //音量控制,旋轉可變電阻,讀取類比值後,換算成音量,然後進行設定
  sensorValue = analogRead(sensorPin);   //讀取類比輸入的值會得到0~1023
  sensorValue = map(sensorValue,0,1023,0,30);  //將0~1023轉化成0~30音量
  if(volume != sensorValue){   //如果目前音量,不等於可變電阻設定的音量,就將音量設為新的值
    dfmp3.setVolume(sensorValue);
    volume = sensorValue;
    Serial.println(volume); //從監控視窗看到音量值
  }


  //判斷 播放/暫停 的狀態,如果正在播放,按了鈕就表示要暫停,除此之外,就接著播放
  if(digitalRead(PlayPause_BUTTON_PIN) == LOW){  // 如果按了鍵
    Serial.println("click Play/Pause..."); 
    playOrPause = dfmp3.getStatus();  //取得播放狀態
    if(playOrPause.state == DfMp3_StatusState_Playing ){   //判斷目前是不是播放中
      dfmp3.pause();  //暫停
      delay(500);     //delay半秒,以免操作者按住不放會一直重複操作
    }else{
      dfmp3.start();  //接著播放
      delay(500);
    }
  }

  //按下上一首按鍵的處理
  if(digitalRead(Prev_BUTTON_PIN) == LOW){          //如果按鍵按了
    dfmp3.prevTrack();
    delay(500);
  }

  //按下下一首按鍵的處理
  if(digitalRead(Next_BUTTON_PIN) == LOW){          //如果按鍵按了
    dfmp3.nextTrack();
    delay(500);
  }
  
}