ボタンで音楽を操作してみよう

前回は、DFPlayerを使って音楽を再生しました。

今回はボタンを追加して、 「再生・停止」「曲送り」などの操作ができるようにしてみましょう。

DFPlayerには、色々なコマンドが用意されているので
リピート再生やランダム再生など、コマンドを使って色々なことができるようになります。

ボタンとリピート再生のサンプル

OLEDでボリュームや再生モードなどを表示するバージョン


mp3player2

ボタンを追加しよう

次の3つのボタンを用意します。

  • 再生 / 停止ボタン
  • 次の曲ボタン
  • 前の曲ボタン

それぞれのボタンを、マイコンのピンに接続します。
今回は、2・5・11・7のピンをボタンにつなぎました。(7番は予備)
sc8_612

プルアップ接続

ボタンはINPUT_PULLUPを使って接続します。

・押していないとき → HIGH
・押したとき → LOW

となるので、プログラムではLOWのときを「押された」として扱います。

プログラムを書こう

ボタンの状態を読み取って、DFPlayerに命令を送ります。

■ サンプルコード


// DFPlayerにコマンドを送る関数
void sendCommand(uint8_t cmd, uint8_t p1, uint8_t p2) {
  uint8_t packet[10] = {
    0x7E, 0xFF, 0x06, cmd, 0x00,
    p1, p2,
    0x00, 0x00, 0xEF
  };

  uint16_t sum = 0;
  for (int i = 1; i < 7; i++) {
    sum += packet[i];
  }
  sum = -sum;

  packet[7] = (sum >> 8) & 0xFF;
  packet[8] = sum & 0xFF;

  Serial1.write(packet, 10);
  delay(200);
}

#define BTN_PREV 2
#define BTN_PLAY 5
#define BTN_NEXT 11
#define BTN_SUB 7

bool isPlaying = true;

void setup() {

  pinMode(BTN_PREV, INPUT_PULLUP);
  pinMode(BTN_PLAY, INPUT_PULLUP);
  pinMode(BTN_NEXT, INPUT_PULLUP);
  pinMode(BTN_SUB, INPUT_PULLUP);

  Serial1.begin(9600);
  delay(2000);

  sendCommand(0x0D, 0, 0); // 再生スタート
}

void loop() {

  // 再生 / 停止ボタン
  if (digitalRead(BTN_PLAY) == LOW) {
    if (isPlaying) {
      sendCommand(0x0E, 0, 0); // 一時停止
      isPlaying = false;
    } else {
      sendCommand(0x0D, 0, 0); // 再生
      isPlaying = true;
    }
    delay(300);
  }

  // 次の曲
  if (digitalRead(BTN_NEXT) == LOW) {
    sendCommand(0x01, 0, 0);
    isPlaying = true;
    delay(300);
  }

  // 前の曲
  if (digitalRead(BTN_PREV) == LOW) {
    sendCommand(0x02, 0, 0);
    isPlaying = true;
    delay(300);
  }
}


DFPlayerは、「コマンド」という命令を送ることで動きます。

たとえば…

  • 0x0D → 再生
  • 0x0E → 一時停止
  • 0x01 → 次の曲
  • 0x02 → 前の曲

sendCommand()は、このコマンドをDFPlayerに送るための関数です。

動かしてみよう

プログラムを書き込んだら、 それぞれのボタンを押してみましょう。

  • 再生 / 停止が切り替わる
  • 次の曲に進む
  • 前の曲に戻る

思い通りに動けば成功です。(1曲目を再生中に前の曲に戻ることはできません)


いまは、1曲終わるごとに停止するようになっていますね。

次は、ループ再生やランダム再生などを試してみましょう。


ループ再生できるようにしてみよう

DFPlayerは、曲が終わったあとに自動で次の曲を再生したり、同じ曲をくり返し再生したりすることができます。
BGMプレイヤーやゲームの音楽にもぴったりですね。

今回は「全曲リピート」と「1曲だけリピート」の2種類を試してみましょう。

DFPlayerのコマンド一覧を見てみよう

DFPlayerは、決められたコマンドをシリアル通信で送ることで操作できます。
どんな命令があるかは、仕様書(データシート)に書かれています。

仕様書はこちら:
[DFPlayer Mini Datasheet]

DFPlayerの説明書はいろんなバージョンがあって、コマンドが全部のっていないものもありました
また、DFPlayer本体のバージョンによっても動かないことがあるかもしれません。

全曲をループ再生してみよう

まずは、SDカードに入っている曲を順番にくり返し再生してみます。
setup()でリピートのコマンドを送ってみましょう。

■ サンプルコード

void setup() {

  pinMode(BTN_PREV, INPUT_PULLUP);
  pinMode(BTN_PLAY, INPUT_PULLUP);
  pinMode(BTN_NEXT, INPUT_PULLUP);
  pinMode(BTN_SUB, INPUT_PULLUP);

  Serial1.begin(9600);
  delay(2000);
  sendCommand(0x11, 0, 1); // リピートオン
  sendCommand(0x0D, 0, 0); // 再生スタート
}

この「0x11」という命令が、全曲リピート再生です。
曲が最後まで再生されると、自動で次の曲へ進みます。

コマンドの読み方

「0x11」のような数字は、16進数という特別な数の表し方です。
マイコンではよく使われます。

DFPlayerは、この数字を見て
「次の曲へ進むモード」
「音量変更」
などを判断しています。

1曲だけループ再生してみよう

DFPlayerは、「何番の曲を再生するか?」を数字で指定できます。
ですが、ファイル名の付け方や、SDカードへのコピー順に少しクセがあります。


ルートフォルダに入れる場合

SDカードの一番上(フォルダの外)に曲を入れるときは、
ファイル名を「4ケタの数字」にする必要があります。

  • 0001.mp3 → 1番の曲
  • 0002.mp3 → 2番の曲
  • 0003.mp3 → 3番の曲

として再生されます。

コピーする順番にも注意

実はDFPlayerは、ファイル名だけでなく
SDカードに書き込まれた順番も見ています。

たとえば…

  • 最初に「0007.mp3」をコピー
  • あとから「0001.mp3」をコピー

という順番にすると、

  • 0007.mp3 → 1番目の曲
  • 0001.mp3 → 2番目の曲

のように認識されてしまうことがあります。

おすすめの方法 
  • 先にパソコン上で「0001.mp3」などに名前をそろえる
  • あとから全部まとめてコピーする
こうすると、曲番号がズレにくくなります。

フォルダに入れる場合

フォルダを使う場合は、少しルールが変わります。

■ フォルダ構成の例
01/
 ├─001.mp3
 ├─002.mp3

02/
 ├─001.mp3
  • フォルダ名 → 01〜99
  • ファイル名 → 001.mp3〜255.mp3

この場合は、「フォルダ番号」と「曲番号」を指定して再生できます。

1曲だけリピートするプログラム

たとえば「0002.mp3」をずっとループしたい場合は、 次のようなコマンドを送ります。

■ サンプルコード
void setup() {

  pinMode(BTN_PREV, INPUT_PULLUP);
  pinMode(BTN_PLAY, INPUT_PULLUP);
  pinMode(BTN_NEXT, INPUT_PULLUP);
  pinMode(BTN_SUB, INPUT_PULLUP);

  Serial1.begin(9600);
  delay(2000);
  sendCommand(0x08, 0, 2); // 2番目のトラックをリピート再生
  sendCommand(0x0D, 0, 0); // 再生スタート
}

最後の「2」が曲番号です。
つまり「2番目の曲をループ再生してね!」という意味になります。

よく使うDFPlayerコマンド一覧

DFPlayerは、「sendCommand()」で命令を送ることで操作できます。
たとえば、

■ 基本の書き方
sendCommand(コマンド番号, 引数1, 引数2);

という形で使います。

  • コマンド番号 → 「何をしたいか」
  • 引数1・引数2 → 追加の設定

を表しています。

ワンポイント 💡

使わない引数は「0」を入れておけばOKです。
コマンド 内容 sendCommand() の例
0x01 次の曲 sendCommand(0x01, 0, 0);
0x02 前の曲 sendCommand(0x02, 0, 0);
0x03 曲番号を指定して再生 sendCommand(0x03, 0, 5);
→ 0005.mp3 を再生
0x04 音量アップ sendCommand(0x04, 0, 0);
0x05 音量ダウン sendCommand(0x05, 0, 0);
0x06 音量指定(0〜30) sendCommand(0x06, 0, 20);
→音量を20にする
0x07 EQ設定 sendCommand(0x07, 0, 2);
→ Rockモード
0x08 1曲リピート sendCommand(0x08, 0, 2);
→ 0002.mp3 をループ
0x09 再生デバイス指定 sendCommand(0x09, 0, 2);
→ SDカード
0x0C リセット sendCommand(0x0C, 0, 0);
0x0D 再生 sendCommand(0x0D, 0, 0);
0x0E 一時停止 sendCommand(0x0E, 0, 0);
0x0F フォルダ内トラック再生 sendCommand(0x0F, 1, 3);
→ 01/003.mp3
0x11 全曲リピート sendCommand(0x11, 0, 1);
0x16 停止 sendCommand(0x16, 0, 0);
0x17 フォルダリピート sendCommand(0x17, 0, 1);
→ 01フォルダをループ
0x18 ランダム再生 sendCommand(0x18, 0, 0);
0x19 現在の曲をリピート sendCommand(0x19, 0, 0);
0x1A DAC ON/OFF sendCommand(0x1A, 0, 1);

仕様書には細かいコマンドの使い方説明も載ってるので、チェックしてみて下さい

Busyピンで曲が再生中かどうかがわかる

DFPlayerには「いま音楽を再生しているか?」を教えてくれる Busyピンがあります。
  • 再生中 → LOW(0)
  • 停止中 → HIGH(1)
という状態になります。 配線の例では、UIAPduinoの10番ピンにつないでいます。
#define BUSY_PIN 10

bool nowPlaying = (digitalRead(BUSY_PIN) == LOW);
digitalRead() でBUSYピンを読むことで、
  • 曲が終わったかチェックする
  • 次の曲を自動再生する
  • 再生中だけアニメーションする
  • LEDを点滅させる
など、いろいろな機能を作れるようになります


OLEDディスプレイと組み合わせ

さいごに
これまでに作った ・ボタン入力 ・OLED表示 ・DFPlayer制御 を全部組み合わせて
音楽プレイヤーっぽくしてみました。(ボタンのピン配置が違うので、自分のピンに合わせて下さい)

さいごにサンプルだけあげておきます。
なんか途中で自動再生が止まっちゃったりしたので、ちょいゴリ押しぎみです。

sc8_613