MP3 Playerの製作(00)

最近、車で遠出をしラジオが入らない事が有りました。音無しで運転するのは以外に辛くなにかBGMが欲しいと思ってしまいました。CDをかければ良いのですが運転中にCDセットは出来ません。スマホを聞けば良いじゃんってスマホも圏外だったりします。

そこでMP3 Playerでも買って音楽を聞こうかと探していると、Aideepen 5個 Mini MP3プレーヤーを見つけました。HPには、

  • 端子の説明。
  • Arduinoに接続した例。
  • 単品動作様の配線図。
  • サンプルプログラム(これは絵だけでした)

が有りました。HPの写真に DFPlayer Mini と有るのでGoogleで検索するとかなりのヒットが有りました。おもしろそうなのでこれを買って見ることにしました。

資料集め

多分ここが製品のHP、DFPlayer_Mini_SKU_DFR0299-DFRobot。AmazonのHPより更に詳しく製品の説明が載っています。Sample Code欄に有る、DFRobotDFPlayerMiniをダウンロードして解凍するとArduinoのサンプルコードと詳しい製品マニュアルが入っていました。

先ずは単品で

先ずは単品で動作するか確かめて見ます。使った回路はマニュアルに載っていた回路そのままです。これでSDカードに曲データを入れてボタンを押せば曲が再生されるはずです。

何と確かに曲を再生します。SDカードに数曲コピーしたのでPreとNextボタンで曲が前後して再生されます。 またボタンを長押しすれば音量の調整が出来ます。かなり嬉しい気持ちになったのですが、ボタンを押すと1曲しか再生してくれません。曲が終わるともう一度ボタンを押さないと次の曲を再生してくれません。ボタンを1回押すとコピーした曲を全部再生して欲しい所です。

マニュアルに有る下記の回路図に、多分これだろうと思われる所を見つけました。

ADKEY1に51Kの抵抗を通してグランドとショートとさせるボタンが有り(上図赤枠のボタン)、Loop Allと注釈が有ります。このボタンを押すとループ再生すると思われます。実際に配線すると上図右の様になります。実際に配線して確かめたい所ですが、この機能はArduinoを繋げば出来るので配線はしていません。

Arduinoと言ってもESP32

ArduinoとしてESP32を使用します。30ピンのESP32でDFPlayerと下記の様に配線しました。前回の回路にTX/RXを接続したのみです。

ソフトはサンプルコードを使う

先ずは、DFRobotDFPlayerMiniに有ったGetStarted.inoを使用する事にしました。

GetStarted.ino

/***************************************************
DFPlayer - A Mini MP3 Player For Arduino
 <https://www.dfrobot.com/product-1121.html>
 
 ***************************************************
 This example shows the basic function of library for DFPlayer.
 
 Created 2016-12-07
 By [Angelo qiao](Angelo.qiao@dfrobot.com)
 
 GNU Lesser General Public License.
 See <http://www.gnu.org/licenses/> for details.
 All above must be included in any redistribution
 ****************************************************/

/***********Notice and Trouble shooting***************
 1.Connection and Diagram can be found here
 <https://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299#Connection_Diagram>
 2.This code is tested on Arduino Uno, Leonardo, Mega boards.
 ****************************************************/

#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int value);

void setup()
{
  mySoftwareSerial.begin(9600);
  Serial.begin(115200);
  
  Serial.println();
  Serial.println(F("DFRobot DFPlayer Mini Demo"));
  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));
  
  if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while(true){
      delay(0); // Code to compatible with ESP8266 watch dog.
    }
  }
  Serial.println(F("DFPlayer Mini online."));
  
  myDFPlayer.volume(10);  //Set volume value. From 0 to 30
  myDFPlayer.play(1);  //Play the first mp3
}

void loop()
{
  static unsigned long timer = millis();
  
  if (millis() - timer > 3000) {
    timer = millis();
    myDFPlayer.next();  //Play next mp3 every 3 second.
  }
  
  if (myDFPlayer.available()) {
    printDetail(myDFPlayer.readType(), myDFPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states.
  }
}

void printDetail(uint8_t type, int value){
  switch (type) {
    case TimeOut:
      Serial.println(F("Time Out!"));
      break;
    case WrongStack:
      Serial.println(F("Stack Wrong!"));
      break;
    case DFPlayerCardInserted:
      Serial.println(F("Card Inserted!"));
      break;
    case DFPlayerCardRemoved:
      Serial.println(F("Card Removed!"));
      break;
    case DFPlayerCardOnline:
      Serial.println(F("Card Online!"));
      break;
    case DFPlayerUSBInserted:
      Serial.println("USB Inserted!");
      break;
    case DFPlayerUSBRemoved:
      Serial.println("USB Removed!");
      break;
    case DFPlayerPlayFinished:
      Serial.print(F("Number:"));
      Serial.print(value);
      Serial.println(F(" Play Finished!"));
      break;
    case DFPlayerError:
      Serial.print(F("DFPlayerError:"));
      switch (value) {
        case Busy:
          Serial.println(F("Card not found"));
          break;
        case Sleeping:
          Serial.println(F("Sleeping"));
          break;
        case SerialWrongStack:
          Serial.println(F("Get Wrong Stack"));
          break;
        case CheckSumNotMatch:
          Serial.println(F("Check Sum Not Match"));
          break;
        case FileIndexOut:
          Serial.println(F("File Index Out of Bound"));
          break;
        case FileMismatch:
          Serial.println(F("Cannot Find File"));
          break;
        case Advertise:
          Serial.println(F("In Advertise"));
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }
  
}

プログラムの内容は簡単で、SDの中のファイルを3秒毎再生したら次のファイルを再生するものです。コードの26行でシリアル通信のピンを設定しているので、ここを今回の回路に合わせて

SoftwareSerial mySoftwareSerial(17, 16); // RX, TX

と変更するのみでOKの様に見えます。早速書き換えて実行したのですがDFPlayerと接続が出来ません。コンパイルはエラー無く完了するのですが、実行するとシリアルモニタに下記のメッセージが表示されプログラムが進みません。

DFRobot DFPlayer Mini Demo
Initializing DFPlayer … (May take 3~5 seconds)
Unable to begin:
1.Please recheck the connection!
2.Please insert the SD card!

コードの最初の段階でエラーを出している様です。

Googleで同じ様な事例は無いか検索して見ました。ESP32を使ってこのDFPlayerを動かしている例はネットに幾つか有り、その例を見る限り同じ様な回路とコードで問題無く動いているようです。

また、ネットにESP32は、”SoftwareSerialは使えない” と有ったのでコードのその部分を、”HardwareSerial” (実は最初からこれを使う予定で配線していた)に変えたのですが同じメッセージが表示され繋がりませんでした。

始めから書くか

マニュアルを見る限り一連のデータをDFPlayerに送信すれば操作出来るようなので最初からコードを書いて見ることにしました。

getstart_00.ino

#include "Arduino.h"

HardwareSerial _serial(2); 

uint8_t send_buf[8]= {0x7E, 0xFF, 0x06, 0x01, 0x00, 0x00, 0x00, 0xEF};

void setup() 
{
    
    Serial.begin(115200);
    Serial.println(" ");
  
    Serial.println("Initialize UART");
    _serial.begin(9600);
    
    Serial.println("Waite 3secT");
    delay(3000);
    
    Serial.println("Set Volume 20");
    send_buf[3] = 0x06;
    send_buf[5] = 0;
    send_buf[6] = 20;
    _serial.write(send_buf,8);
    delay(200);
}

void loop() 
{
    Serial.println("Play next");
    send_buf[3] = 0x01;
    send_buf[5] = 0;
    send_buf[6] = 0;
    _serial.write(send_buf,8);
    
    Serial.println("Waite 30sec");
    delay(30000);

}

コードの流れは以下の通り

  • 3行:当初の予定通り、UARTの2番を使用
  • 5行:DFPlayerに送るデータの配列を宣言。送信データのフォーマットは
    • 最初の3バイトは固定
    • 4バイト目がコマンド
    • 5バイト目は0に固定
    • 6,7バイト目にデータ
    • 8バイトは、0xEF
  • setup()で転送レートと音量を20に設定
    • 14行:転送レートは9600
    • 17行:マニュアルにDFPlayerの初期化に約1.5秒かかると有るので3秒待つ
    • 20〜22行:音量を20に調整
    • 23行:ここでDFPlayerにデータを送信
  • loop()で再生を行う
    • 30〜32行:Next Playコマンドの設定
    • 33行:DFPlayerにコマンドを送信
    • 36行:再生を30秒行う
    • これを繰り返す

SDカードに再生用のデータをコピーしてこのコードを実行すると問題無く曲が再生されました。通信エラーは起きません。”エラーは起きているがコードがそれを見ていない”が正しいのかもしれませんが、でも想定した通りに曲が再生されています。

次回は

意外と簡単にDFPlayerを制御出来そうなので、操作に必要なコマンドを実行する関数を定義しながらMP3Playerを製作して行こうと思います。