部品 · 読了まで18分

ArduinoでDFPlayer Miniを使う:MP3の再生、SDカード、スピーカー

ArduinoでDFPlayer Miniを使う方法。RXの1kΩ抵抗、SDカードと0001.mp3の命名、ライブラリのコード、ボタン、スピーカー、ESP32とPicoの例を解説します。

DFPlayer Miniは、ArduinoでMP3を再生する最も安く簡単な方法です。microSDカードの音声ファイルを自分でデコードし、内蔵の小さなアンプでスピーカーを直接鳴らし、2本線のシリアル通信でArduinoからコマンドを受け取ります。ブザーのビープ音と違い、歌、話し声、玄関チャイムのメロディー、「ドアが開いたままです」のような音声の警告も再生できます。初めてつないだ人の多くは同じ問題にぶつかります。音が出ない、スピーカーからサーッという雑音がする、ファイルが違う順番で再生される、シリアルモニタに「Unable to begin」と出る、などです。このガイドでは、そのすべてを解決し、なぜそうなるのかも説明します。

まず、モジュールのピンと、RXの線に1 kΩの抵抗を入れる理由を学びます。次に、SDカードをFAT32で準備し、ファイルを0001.mp3と01のフォルダの形式で名前を付け、DFRobotDFPlayerMiniライブラリで最初の音を鳴らし、音量とEQを設定し、ボタンで曲を変え、適切なスピーカーや外付けアンプを選ぶ方法を見ていきます。最後のセクションでは、「Unable to begin」エラーのステップごとの直し方、ESP32でWebページから操作するMP3プレーヤー、Raspberry Pi Pico用のライブラリを使わないMicroPythonの例を紹介します。ビープ音や簡単なメロディーだけでよければ、ブザーのほうが簡単です。

DFPlayer Mini MP3プレーヤーモジュール
DFPlayer Mini:わずか20 × 20 mmで、microSDカードのスロット、MP3デコーダーのチップ、最大3 Wのスピーカーを鳴らせる小さなアンプを備えています。

DFPlayer Miniとは?どう動くのか

DFPlayer Miniは、MP3デコーダーのチップ、24ビットのDAC、microSDカードのスロット、小さなモノラルアンプでできた、それだけで完結したMP3プレーヤーです。Arduinoは「3曲目を再生して」「音量を20にして」といった短いコマンドを送るだけです。カードからファイルを読み、圧縮された音声をデコードし、スピーカーを鳴らすのはモジュールの仕事です。そのため、RAMが2 KBしかないArduino Unoでも楽々と音楽を再生できます。コマンドは9600ボーで、1つ10バイトのパケットとして送られます。モジュールも、曲が終わったとき、カードが挿されたり抜かれたりしたとき、エラーが起きたときに同じ形式で知らせてきます。基板上のチップはメーカーによって違います(YX5200-24SS、MH2024K-24SS、GD3200Bなど)。どれも同じコマンドを理解しますが、応答にかかる時間が違うことがあり、これはあとで「Unable to begin」エラーのときに重要になります。モジュールは3つの方法で操作できます。シリアルポート(UART)、IOボタン、ADKEYの抵抗ラダーです。

項目値
対応ファイルMP3、WAV、WMA
サンプリング周波数8 / 11.025 / 12 / 16 / 22.05 / 24 / 32 / 44.1 / 48 kHz
DAC24ビット。ダイナミックレンジ90 dB、S/N比85 dB
記録メディア32 GBまでのmicroSD(TF)カード、FAT16またはFAT32。USBメモリにも対応
フォルダの容量最大100フォルダ、1フォルダあたり255ファイル
音量30段階(0〜30)
イコライザー(EQ)6モード:Normal、Pop、Rock、Jazz、Classic、Bass
スピーカー出力内蔵のモノラルアンプ、3 W未満のスピーカー
ライン出力DAC_LとDAC_R:ステレオ、ヘッドホンや外付けアンプ用
電源3.2〜5.0 V(標準4.2 V)
待機時の電流約20 mA
インターフェースUART、9600ボー、8N1
大きさ20 × 20 mm

DFPlayer Miniのピン配置

ピン名前機能
1VCC電源入力、3.2〜5.0 V
2RXシリアル入力:1 kΩの抵抗を通してボードのTXピンにつなぐ
3TXシリアル出力:ボードのRXピンへ
4DAC_R右チャンネルのライン出力(ヘッドホンかアンプ)
5DAC_L左チャンネルのライン出力(ヘッドホンかアンプ)
6と8SPK_1、SPK_2スピーカー出力:3 W未満のスピーカーの2本の線をここにつなぐ
7GNDグランド
9IO_1GNDに短く押す:前の曲、長押し:音量を下げる
10GNDグランド
11IO_2GNDに短く押す:次の曲、長押し:音量を上げる
12ADKEY1抵抗ラダーによる複数ボタンの入力
13ADKEY22つ目の抵抗ラダーの入力
14USB+USBメモリ用のD+
15USB−USBメモリ用のD−
16BUSY再生中はLOW、待機中はHIGH

シリアルポートを使う場合に必要なのは、VCC、GND、RX、TX、スピーカーのピンだけです。BUSYピンを使えば、シリアル通信なしで曲が終わったかがわかり、基板上の小さなLEDも再生中に点きます。IO_1とIO_2のピンを使えば、Arduinoなしでもモジュールを動かせます。各ピンとGNDの間にボタンを付ければ、短く押すと曲が変わり、長押しで音量が変わります。値の違う抵抗を通してADKEYのピンにつないだボタンで、特定の曲を再生することもできます。つまり、電池、スピーカー、ボタン2つがあれば、マイコンなしで玄関チャイムやしゃべるおもちゃを作れます。USB+とUSB−のピンはSDカードの代わりにUSBメモリから再生するためのもので、ほとんどのプロジェクトでは未接続のままです。

DFPlayer MiniとArduinoの配線、RXの1kΩ抵抗

DFPlayerのピンArduino UnoESP32Raspberry Pi Pico
VCC5V5V(VIN)VBUS(USBの5 V、40番ピン)
GNDGNDGNDGND
RX1 kΩの抵抗を通してD111 kΩの抵抗を通してGPIO 17(TX2)1 kΩの抵抗を通してGP0(UART0のTX)
TXD10GPIO 16(RX2)GP1(UART0のRX)
SPK_1とSPK_2スピーカーの2本の線スピーカーの2本の線スピーカーの2本の線
BUSY(任意)D5使わない使わない
Arduino Uno
Arduino Uno
ESP32
ESP32
Raspberry Pi Pico
Raspberry Pi Pico

データ線は交差させます。モジュールのTXはボードのRXへ、RXはボードのTXへつなぎます。UnoのD0とD1のハードウェアシリアルポートはUSBでの書き込みとシリアルモニタに使われているので、モジュールはSoftwareSerialでD10(RX)とD11(TX)につなぎます。モジュールのRX入力と直列に入れる1 kΩの抵抗は、ささいな部品ではありません。DFPlayerのチップは3.3 Vのロジックで動きますが、UnoのTXピンは5 Vを出します。抵抗がないと、その差によってチップの入力保護ダイオードに電流が流れます。その電流がチップに負担をかけ、シリアル通信中にスピーカーから聞こえるサーッという雑音やプチプチ音の原因になります。オームの法則で計算すると、1 kΩならこの電流が約1〜2 mAに抑えられ、9600ボーの信号には影響しないことがわかります。10 kΩのようなずっと大きな抵抗では信号が弱まり、通信が途切れることがあります。モジュールのTX出力はそのままUnoにつなぎます。Unoは3.3 VをHIGHとして読むからです(しきい値は約3.0 V)。

SPK_1やSPK_2を絶対にGNDにつながないでください。基板上のアンプはブリッジ(BTL)出力で、両方の線に音声信号が流れています。片方をグランドにつなぐとアンプがショートし、壊れることがあります。同じ理由で、SPKのピンを外付けアンプの入力につながないでください。そのためにはDAC_LとDAC_Rのライン出力を使います。インピーダンスが4 Ω未満のスピーカーもつながないでください。

SDカードの準備:FAT32、フォルダ、0001.mp3の命名

DFPlayer Miniが読めるのは、FAT16かFAT32でフォーマットした32 GBまでのmicroSDカードです。64 GB以上のカードはexFATでフォーマットされて出荷されていて、モジュールでは読めません。数百曲なら1〜16 GBのカードで十分です。MP3を128〜192 kbps・44.1 kHzでエンコードすると、互換性とカードの読み込み速度の両面で最も安全です。モジュールはファイルを名前ではなく番号で識別するので、どの関数で再生するかに応じて、フォルダとファイルの名前を決まった形式にする必要があります。

カード上の場所例ライブラリの関数ルール
ルートフォルダ/0001.mp3、/0002.mp3play(1)名前ではなく、カードにコピーした順に再生される
番号付きのフォルダ/01/001.mp3 … /99/255.mp3playFolder(1, 1)フォルダ名は2桁(01〜99)、ファイル名は3桁(001〜255)
mp3フォルダ/mp3/0001.mp3playMp3Folder(1)ファイル名は4桁。ファイルは名前の番号で見つけられる
advertフォルダ/advert/0001.mp3advertise(1)再生中の曲を中断し、案内が終わると再開する
大きなフォルダ/01/0001.mp3 … /15/3000.mp3playLargeFolder(1, 1)最大15フォルダ、1フォルダあたり3000ファイル、4桁の名前
  1. パソコンでカードをFAT32でフォーマットします(Windowsなら右クリック >「フォーマット」、macOSなら「ディスクユーティリティ」>「消去」>「MS-DOS (FAT)」)。
  2. ルートにmp3という名前のフォルダを作り、必要なら01や02のような番号付きのフォルダも作ります。
  3. ファイルの名前を0001.mp3、0002.mp3(番号付きのフォルダでは001.mp3)に変えます。0001_hello.mp3のように番号のあとに説明を加えても構いません。モジュールは先頭の数字だけを見ます。
  4. ルートのファイルをplay()で再生する場合は、1つずつ順番にコピーしてください。まとめてコピーすると順番がずれることがあります。
  5. カードを安全に取り出し、電源を切った状態でモジュールに挿します。動作中に抜き差しすると、ファイルが壊れることがあります。
macOSは、ファイルごとに._0001.mp3のような隠しコピーと、.Spotlight-V100や.fseventsdのような隠しフォルダを作ります。DFPlayerはこれらもファイルとして数えるので、違う曲が再生されたり、音が出なかったり、readFileCounts()が実際より多いファイル数を返したりします。Macでカードを準備した場合は、ターミナルでdot_clean -m /Volumes/CARD_NAMEを実行するか、隠しファイルを手で削除してください。Windowsが作るSystem Volume Informationフォルダは、通常は問題を起こしません。

DFRobotDFPlayerMiniライブラリと最初のテスト用スケッチ

  1. Arduino IDEでライブラリマネージャを開き、DFRobotDFPlayerMiniと入力してDFRobotのライブラリをインストールします。インストールの手順はArduinoにライブラリを追加する方法で詳しく説明しています。
  2. SDカードのルートにMP3を少なくとも1つコピーし、カードをモジュールに挿して、表のとおりに回路を組みます。
  3. 下のスケッチを書き込み、シリアルモニタを115200ボーで開きます。
  4. 数秒のうちに「DFPlayer Mini online.」とカード上のファイル数が表示され、続いて最初の曲が聞こえるはずです。
C++ (Arduino IDE)
1#include <SoftwareSerial.h>
2#include <DFRobotDFPlayerMini.h>
3
4SoftwareSerial dfSerial(10, 11);   // RX = D10 ← DFPlayer TX, TX = D11 → 1 kΩ → DFPlayer RX
5DFRobotDFPlayerMini player;
6
7void setup() {
8  Serial.begin(115200);
9  dfSerial.begin(9600);                       // DFPlayer her zaman 9600 baud / DFPlayer always uses 9600 baud
10  Serial.println(F("DFPlayer baslatiliyor / Starting DFPlayer..."));
11
12  if (!player.begin(dfSerial)) {              // reset gönderir, kartı bekler / sends a reset, waits for the card
13    Serial.println(F("Unable to begin: kablolari ve SD karti kontrol et / check wiring and SD card"));
14    while (true) {}                           // burada dur / stop here
15  }
16  Serial.println(F("DFPlayer Mini online."));
17  Serial.print(F("Karttaki dosya / Files on card: "));
18  Serial.println(player.readFileCounts());    // gizli dosyalar da sayılır / hidden files are counted too
19
20  player.volume(20);                          // ses seviyesi 0-30 / volume 0-30
21  player.EQ(DFPLAYER_EQ_NORMAL);              // ekolayzır: normal / equalizer: normal
22  player.play(1);                             // kökteki ilk dosya / first file in the root
23}
24
25void loop() {
26  if (player.available()) {                   // modülden bildirim geldi / a message arrived from the module
27    uint8_t type = player.readType();
28    int value = player.read();
29    if (type == DFPlayerPlayFinished) {
30      Serial.print(F("Parca bitti / Track finished: "));
31      Serial.println(value);
32    } else if (type == DFPlayerError) {
33      Serial.print(F("Hata kodu / Error code: "));
34      Serial.println(value);                  // kodların anlamı tabloda / meanings are in the table
35    } else if (type == DFPlayerCardRemoved) {
36      Serial.println(F("SD kart cikarildi / SD card removed"));
37    }
38  }
39}
40
関数役割
begin(serial, isACK, doReset)モジュールを起動する。初期設定ではリセットを送り、カードの準備ができたというメッセージを待つ
volume(0–30)音量を設定する。volumeUp()とvolumeDown()は1段階ずつ変える
EQ(DFPLAYER_EQ_POP)イコライザー:NORMAL、POP、ROCK、JAZZ、CLASSIC、BASS
play(n)ルートのn番目のファイルを再生する(コピーした順)
next() / previous()次の曲 / 前の曲
pause() / start()一時停止 / 止めたところから再開
stop()再生を止める
loop(n)n番目の曲を繰り返し再生する
enableLoopAll() / randomAll()すべての曲をループ / ランダムな順で再生する
readState() / readVolume() / readFileCounts()状態、音量、カード上のファイル数を問い合わせる
available() / readType() / read()モジュールからのメッセージ(曲の終了、エラー、カードの取り外し)を読む
begin()はモジュールにリセットを送り、カードの準備ができたというメッセージを最大2秒待つので、起動に数秒かかるのは正常です。初期設定では、ライブラリはコマンドのたびにモジュールの応答を待つので、コマンドがたまることはありません。それでも、loop()の毎回の周回でvolume()やplay()を送らないでください。コマンドを絶え間なく受け取るモジュールは固まることがあり、スピーカーからプチプチ音がします。何かが変わったときだけコマンドを送りましょう。

音量、EQ、BUSYピンを使った連続の案内

音量は0〜30の範囲です。小さなスピーカーなら、たいていの部屋では15〜20で十分です。25を超えると、特に電源が弱い場合、音が歪み始め(クリッピング)、モジュールがリセットされることがあります。EQの設定は低音と高音のバランスを変えます。小さなスピーカーではBASSモードだと音がこもることがあるので、NORMALから始めてください。番号付きのフォルダは、しゃべるプロジェクトにとても便利です。「温度は」と「度」という言葉をフォルダ01に、001.mp3〜100.mp3の数字をフォルダ02に入れれば、Arduinoが数字を文として話せます。ファイルが終わったことを知る最も確実な方法はBUSYピンです。モジュールが再生中はLOW、待機中はHIGHになります。下のスケッチはD5でBUSYを読み、ファイルを重ならないように1つずつ順番に再生します。

C++ (Arduino IDE)
1#include <SoftwareSerial.h>
2#include <DFRobotDFPlayerMini.h>
3
4SoftwareSerial dfSerial(10, 11);            // RX = D10 ← DFPlayer TX, TX = D11 → 1 kΩ → DFPlayer RX
5DFRobotDFPlayerMini player;
6const byte BUSY_PIN = 5;                    // DFPlayer BUSY: çalarken LOW / LOW while playing
7
8// Klasör 01: 001.mp3 "Sıcaklık", 002.mp3 "derece" / folder 01: 001.mp3 "Temperature", 002.mp3 "degrees"
9// Klasör 02: 001.mp3 ... 100.mp3 = 1 ... 100 sayıları / folder 02: 001.mp3 ... 100.mp3 = numbers 1 ... 100
10
11void playAndWait(uint8_t folder, uint8_t file) {
12  player.playFolder(folder, file);          // /01/001.mp3 gibi / e.g. /01/001.mp3
13  unsigned long start = millis();
14  while (digitalRead(BUSY_PIN) == HIGH && millis() - start < 1000) {}  // çalma başlasın / wait for playback to start
15  while (digitalRead(BUSY_PIN) == LOW) {}                              // parça bitsin / wait for the track to end
16  delay(50);
17}
18
19void sayTemperature(int degrees) {
20  playAndWait(1, 1);                        // "Sıcaklık" / "Temperature"
21  if (degrees >= 1 && degrees <= 100) {
22    playAndWait(2, degrees);                // sayıyı söyle / say the number
23  }
24  playAndWait(1, 2);                        // "derece" / "degrees"
25}
26
27void setup() {
28  pinMode(BUSY_PIN, INPUT);
29  Serial.begin(115200);
30  dfSerial.begin(9600);
31  if (!player.begin(dfSerial)) {
32    Serial.println(F("Unable to begin"));
33    while (true) {}
34  }
35  player.volume(22);
36  sayTemperature(23);                       // değer bir sensörden de gelebilir / the value can come from a sensor
37}
38
39void loop() {
40}
41

playAndWait()は、まずコマンドを送り、BUSYがLOWになるまで最大1秒待ち(モジュールが再生を始めるまで数百ミリ秒かかります)、そのあと曲が終わるまで待ちます。音声ファイルは自分の声で録音しても、音声合成(TTS)ツールで作っても構いません。各ファイルの最初と最後の無音を削ると、案内がより自然に流れます。短い警告のために音楽を中断したい場合はadvertise(n)を使います。モジュールは/advertフォルダの案内を再生し、そのあと音楽を止めたところから再開します。このコマンドは曲の再生中にしか使えません。モジュールが待機中に呼ぶとエラーが返ります。

ボタンで曲を変え、ポテンショメーターで音量を調整する

それでは自分のMP3プレーヤーを作りましょう。3つのボタンが前の曲、再生・一時停止、次の曲の役目をし、ポテンショメーターで音量を調整します。ボタンはD2、D3、D4とGNDの間につなぎます。内部プルアップ抵抗を使うので、外付けの抵抗は不要です(理由はArduinoに押しボタンをつなぐ方法で説明しています)。ポテンショメーターの両端のピンは5VとGNDへ、中央のピンはA0へつなぎます。曲が終わると、スケッチは自動で次の曲に進みます。

C++ (Arduino IDE)
1#include <SoftwareSerial.h>
2#include <DFRobotDFPlayerMini.h>
3
4SoftwareSerial dfSerial(10, 11);            // RX = D10 ← DFPlayer TX, TX = D11 → 1 kΩ → DFPlayer RX
5DFRobotDFPlayerMini player;
6
7const byte BTN[3] = {2, 3, 4};              // önceki, oynat/duraklat, sonraki / previous, play/pause, next
8const byte POT_PIN = A0;                    // ses ayarı potu / volume potentiometer
9bool lastState[3] = {HIGH, HIGH, HIGH};
10unsigned long lastChange[3] = {0, 0, 0};
11bool paused = false;
12int lastRaw = -100;                         // ilk turda sesi mutlaka ayarla / always set the volume on the first pass
13unsigned long lastPotRead = 0;
14unsigned long lastFinish = 0;
15
16// Butona yeni basıldıysa true döner (50 ms sıçrama filtresi) / true on a new press (50 ms debounce)
17bool pressed(byte i) {
18  bool s = digitalRead(BTN[i]);
19  if (s != lastState[i] && millis() - lastChange[i] > 50) {
20    lastState[i] = s;
21    lastChange[i] = millis();
22    return s == LOW;                        // INPUT_PULLUP: basınca LOW / LOW when pressed
23  }
24  return false;
25}
26
27void setup() {
28  for (byte i = 0; i < 3; i++) pinMode(BTN[i], INPUT_PULLUP);
29  Serial.begin(115200);
30  dfSerial.begin(9600);
31  if (!player.begin(dfSerial)) {
32    Serial.println(F("Unable to begin"));
33    while (true) {}
34  }
35  player.play(1);
36}
37
38void loop() {
39  if (pressed(0)) { player.previous(); paused = false; }
40  if (pressed(2)) { player.next(); paused = false; }
41  if (pressed(1)) {
42    if (paused) player.start();             // kaldığı yerden devam / resume
43    else player.pause();                    // duraklat / pause
44    paused = !paused;
45  }
46
47  if (millis() - lastPotRead > 100) {       // potu saniyede 10 kez oku / read the pot 10 times per second
48    lastPotRead = millis();
49    int raw = analogRead(POT_PIN);
50    if (abs(raw - lastRaw) > 20) {          // titremeyi yok say / ignore jitter
51      lastRaw = raw;
52      player.volume(map(raw, 0, 1023, 0, 30));
53    }
54  }
55
56  if (player.available() && player.readType() == DFPlayerPlayFinished) {
57    if (millis() - lastFinish > 1000) player.next();   // parça bitince sonrakine geç / go to the next track
58    lastFinish = millis();                  // bazı modüller bitişi iki kez bildirir / some modules report the end twice
59  }
60}
61
コードの部分役割
pressed()ボタンが押された瞬間だけを捉え、50 ms以内のチャタリングを無視する。押し続けてもコマンドは1回だけ
abs(raw - lastRaw) > 20はっきりした変化のときだけ音量を更新し、ポテンショメーターの値の小さな揺れでモジュールにコマンドが殺到してプチプチ音が出るのを防ぐ
map(raw, 0, 1023, 0, 30)0〜1023のアナログ値をDFPlayerの0〜30の音量の範囲に変換する
paused再生状態を覚えておき、同じボタンで一時停止と再開の両方ができるようにする
DFPlayerPlayFinished曲が終わったときに送られるメッセージ。スケッチは次の曲に進む
millis() - lastFinish > 1000互換品のモジュールの中には曲の終わりを2回知らせるものがある。このチェックで曲が飛ばされるのを防ぐ

スピーカー(3 W)と外付けアンプの選び方

DFPlayer自身のアンプ(ほとんどの基板では8002型のチップ)は、インピーダンス4 Ωか8 Ω、3 W未満のスピーカーを直接鳴らします。最もバランスがよいのは8 Ω・1〜3 Wのスピーカーです。0.5 Wの小さなスピーカーも使えますが、大音量では苦しくなります。3 Wという値は、5 Vの電源と4 Ωの負荷でのアンプの上限で、歪みがはっきりしてくる点です。普段の使用で得られるきれいな出力はもっと低くなります。スピーカーを箱に入れるか、少なくとも板に取り付けると、コーンの前と後ろからの音が打ち消し合わなくなるので、低音がはっきり良くなります。大音量では、モジュールが一瞬数百ミリアンペアを引くことがあります。パソコンのUSBポートで給電したArduinoでは、これが電圧の低下、雑音、リセットの原因になります。より大きな出力やステレオの音が欲しい場合は、DAC_LとDAC_Rのライン出力を外付けアンプにつなぎます。

出力の経路接続使う場面
内蔵アンプSPK_1とSPK_2 → 3 Wまでの4〜8 Ωのスピーカー玄関チャイム、おもちゃ、音声の警告のような小さなプロジェクト
ヘッドホンDAC_L、DAC_R、GND → 3.5 mmジャック個人で聴く。小さい音量から始める
PAM8403アンプモジュールDAC_L、DAC_R、GND → アンプのL、R、GNDの入力。アンプは5 Vで動く2 × 3 Wのステレオ、電池で動く持ち運べるスピーカー
PAM8610またはTPA3116のアンプDACの出力 → アンプの入力。アンプは12 Vで動くより大きな出力:2 × 10 W以上
アンプ内蔵スピーカー(AUX)DAC_L、DAC_R、GND → アンプ内蔵スピーカーのAUX入力手持ちのパソコン用スピーカーを使う
DFPlayerのVCCとGNDのピンの間に、できるだけモジュールの近くに100〜470 µFの電解コンデンサを入れてください。大音量での急な電流のピークをまかない、リセットを防ぎます。外付けアンプを使う場合は、アンプ、DFPlayer、Arduinoを同じGNDの点でつなぎます。別々のアダプターで給電され、グランドが分かれた回路は、ブーンという雑音の最もよくある原因です。これが重要な理由は共通グランド(GND)で説明しています。スピーカーの配線は短くし、シリアルの配線と並べて這わせないでください。

サーッという雑音、ノイズ、プチプチ音をなくすには

  • コマンドを送るときにサーッという雑音やプチプチ音がする:RXの線の1 kΩの抵抗がありません。ArduinoのTXピンとモジュールのRXピンの間に入れてください。
  • 常にサーッという雑音やブーンという音がする:電源にノイズがあるか、弱すぎます。DFPlayerを別の5 V電源から給電し、VCCとGNDの間にコンデンサを入れ、GNDをすべてつないでください。
  • 起動時に「ポン」と鳴る:begin()が送るリセットのコマンドが原因です。気になる場合は、player.begin(dfSerial, true, false)でリセットを省いてください。
  • ESP32でジーという音がする:Wi-Fiの送信中の電流のパルスが電源に入り込み、そこから音声に混ざっています。DFPlayerの電源にコンデンサを加え、できれば別の電源を使ってください。
  • 大音量で音が割れて歪む:スピーカーかアンプが限界で動いています。音量を20〜25程度に下げるか、より効率のよいスピーカーを選ぶか、外付けアンプに切り替えてください。
  • 何も再生していないときにかすかなサーッという音がする:これは基板上のアンプ自体のノイズで、小さなモジュールでは完全には消えません。無音が重要なプロジェクトでは、DACの出力をよい外付けアンプにつなぐのが最善です。

「Unable to begin」エラーとその直し方

シリアルモニタにUnable to begin:(起動できない)と表示され、続いて1.Please recheck the connection!(接続を確認してください)と2.Please insert the SD card!(SDカードを入れてください)が出た場合は、ライブラリのスケッチ例にあるbegin()のチェックが失敗しています。begin()はモジュールにリセットのコマンドを送り、「カードがオンライン」というメッセージを2秒待ちます。メッセージが届かなければfalseを返します。つまり原因は、配線、SDカード、電源、またはモジュールの応答の仕方のどれかです。次の順番で調べてください。

考えられる原因確認と解決法
TXとRXが交差していないモジュールのTXはD10(SoftwareSerialのRX)へ、RXは1 kΩを通してD11(SoftwareSerialのTX)へ。SoftwareSerial(10, 11)の(RX, TX)の順と一致させる
共通GNDがないモジュールのGNDをArduinoのGNDにつなぐ。別の電源を使う場合もGNDを共通にする
SDカードが読めないカードは挿さっているか、FAT32か、32 GB以下か、音声ファイルが少なくとも1つ入っているか。フォーマットし直すか、別のカードを試す
抵抗が違うRXの線には1 kΩが必要。10 kΩのような大きな値では信号が弱まる
電源が不十分VCCは4〜5 Vが必要。スピーカーを一時的に外し、テスターで電圧を測り、コンデンサを追加する
ボーレートが違うdfSerial.begin(9600);でなければならない。シリアルモニタの速度(115200)と混同しない
D0とD1を使っているUnoではハードウェアシリアルポートがUSBと共用。モジュールをSoftwareSerialのピンに移す
互換品のチップの応答が遅いbegin()の前にdelay(1000)を加える。効果がなければbegin(dfSerial, true, false)でリセット後の待ちを省く
DFPlayerErrorのコードライブラリでの名前意味
1Busyモジュールが処理中、またはカードが見つからない(初期化が終わっていない)
2Sleepingモジュールがスリープモード
3SerialWrongStack壊れたシリアルデータを受信した
4CheckSumNotMatchパケットのチェックサムが一致しなかった
5FileIndexOut要求した曲番号がカード上の範囲外
6FileMismatch要求したファイルが見つからない。命名を確認する
7Advertise案内のエラー。たとえば何も再生していないときにadvertise()を呼んだ
安い互換品の基板の中には、リセットのあとに期待されるメッセージを送らないものや、遅れて送るものがあります。その場合、配線が正しくてもbegin()はfalseを返します。player.begin(dfSerial, true, false)はリセットの段階を省いてチェックを通過させます。この設定でモジュールから音が出れば、それが問題でした。ただし、この設定は本当の配線の不具合も隠してしまうので、まず表の項目を確認してください。モジュールがそもそも応答しているかを知るには、player.readFileCounts()を見ます。-1が返るなら、モジュールから返事が来ていません。

ESP32でDFPlayer Miniを使う:WebページからMP3を操作する

ESP32ではSoftwareSerialは不要で、3つあるハードウェアUARTのどれでも好きなピンに割り当てられます。下のスケッチではUART2をGPIO 16(RX)とGPIO 17(TX)で使い、DFPlayerはESP32ボードの5V(VIN)ピンから給電します。ESP32の3.3 VのTX信号はそのままモジュールに合いますが、ノイズ対策として1 kΩの抵抗は残しておいてください。逆方向については、DFRobotはモジュールのロジックレベルを3.3 Vとしています。それでも、5 Vで動かした一部の互換品の基板では、TXの線でもっと高い電圧が測定されています。つなぐ前にテスターでTXとGNDの間を測り、3.6 Vを超えるなら1 kΩ + 2 kΩの分圧回路を追加してください。スケッチは家のネットワークに接続し、スマホで開けるページを提供します。ページのボタンで曲を変え、一時停止し、音量を調整できます。

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <WebServer.h>
3#include <DFRobotDFPlayerMini.h>
4
5const char *WIFI_SSID = "WIFI_ADI";         // kendi ağ adın / your network name
6const char *WIFI_PASS = "WIFI_SIFRESI";     // kendi şifren / your password
7
8HardwareSerial dfSerial(2);                 // UART2
9DFRobotDFPlayerMini player;
10WebServer server(80);
11int volumeLevel = 15;
12
13const char PAGE[] = R"rawliteral(<!DOCTYPE html><html><head>
14<meta name="viewport" content="width=device-width,initial-scale=1"><title>ESP32 MP3</title>
15<style>body{font-family:sans-serif;text-align:center}button{font-size:22px;margin:6px;padding:10px 18px}</style>
16</head><body><h2>DFPlayer Mini</h2>
17<button onclick="c('prev')">Prev</button><button onclick="c('pause')">Pause</button>
18<button onclick="c('play')">Play</button><button onclick="c('next')">Next</button><br>
19<button onclick="c('down')">Vol -</button><button onclick="c('up')">Vol +</button>
20<p id="s"></p>
21<script>function c(x){fetch('/cmd?c='+x).then(r=>r.text()).then(t=>document.getElementById('s').innerText=t)}</script>
22</body></html>)rawliteral";
23
24void handleCmd() {
25  String c = server.arg("c");
26  if (c == "next") player.next();
27  else if (c == "prev") player.previous();
28  else if (c == "pause") player.pause();
29  else if (c == "play") player.start();
30  else if (c == "up" && volumeLevel < 30) player.volume(++volumeLevel);
31  else if (c == "down" && volumeLevel > 0) player.volume(--volumeLevel);
32  server.send(200, "text/plain", "Ses / Volume: " + String(volumeLevel));
33}
34
35void setup() {
36  Serial.begin(115200);
37  dfSerial.begin(9600, SERIAL_8N1, 16, 17); // RX = GPIO16 ← DFPlayer TX, TX = GPIO17 → 1 kΩ → DFPlayer RX
38  delay(1000);                              // modül kartı okusun / let the module read the card
39  if (!player.begin(dfSerial)) {
40    Serial.println("Unable to begin");
41    while (true) delay(10);
42  }
43  player.volume(volumeLevel);
44
45  WiFi.begin(WIFI_SSID, WIFI_PASS);
46  while (WiFi.status() != WL_CONNECTED) {   // ağa bağlanana kadar bekle / wait for the network
47    delay(500);
48    Serial.print(".");
49  }
50  Serial.print("\nAdres / Address: http://");
51  Serial.println(WiFi.localIP());
52
53  server.on("/", []() { server.send(200, "text/html", PAGE); });
54  server.on("/cmd", handleCmd);
55  server.begin();
56  player.play(1);
57}
58
59void loop() {
60  server.handleClient();                    // tarayıcı isteklerini işle / handle browser requests
61}
62

書き込んだら、シリアルモニタに表示されたアドレス(たとえば192.168.1.42)をスマホのブラウザに入力します。スマホとESP32は同じWi-Fiネットワークにつながっている必要があります。接続できない場合はESP32がWi-Fiにつながらないの手順に従ってください。ESP32-WROVERモジュールのボードでは、GPIO 16と17が内部のPSRAMに使われているので、UARTを26や27のような別のピンに移してください。変えるのはdfSerial.begin()の行のピン番号だけです。スピーカーを大音量で鳴らしたときにESP32が勝手に再起動する場合は、電源が原因です。詳しくはESP32のブラウンアウトを参照してください。

Raspberry Pi PicoとMicroPythonでDFPlayer Miniを使う(UART)

Raspberry Pi Picoでは、既製のライブラリを探すより、モジュールのシリアルプロトコルを直接使うほうが簡単で勉強にもなります。どのコマンドも10バイトのパケットです。開始バイト0x7E、バージョン0xFF、長さ0x06、コマンドのコード、応答のフラグ(0 = 応答なし)、2バイトのパラメーター、2バイトのチェックサム、終了バイト0xEFです。チェックサムは、バージョンから最後のパラメーターのバイトまでの6バイトの合計を16ビットで負にしたものです。たとえば、ルートの最初の曲を再生するパケットは7E FF 06 03 00 00 01 FE F7 EFです。モジュールのほうは、曲が終わるとコード0x3D、カードの準備ができると0x3F、エラーが起きると0x40のメッセージを送ります。Picoの3.3 VのUARTはそのままモジュールに合います。ESP32のセクションのTXの電圧についての注意はここでも当てはまります。Picoのピンも5 Vには耐えられないからです。モジュールはPicoのVBUS(USBの5 V)ピンから給電してください。

コマンドコードパラメーター
次の曲 / 前の曲0x01 / 0x02なし
ルートのn番目の曲を再生0x031〜2999
音量0x060〜30
EQ0x070〜5
リセット0x0Cなし
再開 / 一時停止0x0D / 0x0Eなし
フォルダから再生0x0F上位バイトがフォルダ(1〜99)、下位バイトがファイル(1〜255)
mp3フォルダから再生0x12ファイル番号(0001.mp3なら1)
案内(advert)0x13ファイル番号
停止0x16なし
曲の終了(モジュールが送る)0x3D終わった曲の番号
MicroPython
1from machine import UART, Pin
2import time
3
4# GP0 (UART0 TX) → 1 kΩ → DFPlayer RX, GP1 (UART0 RX) ← DFPlayer TX
5uart = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1))
6btn_next = Pin(14, Pin.IN, Pin.PULL_UP)     # sonraki parça / next track
7btn_play = Pin(15, Pin.IN, Pin.PULL_UP)     # oynat-duraklat / play-pause
8TRACKS = 5                                  # /mp3 klasöründeki dosya sayısı / number of files in /mp3
9
10def send(cmd, param=0):
11    # 10 baytlık komut paketi, onay istemeden / 10-byte command frame without ACK
12    frame = bytearray([0x7E, 0xFF, 0x06, cmd, 0x00, param >> 8, param & 0xFF, 0, 0, 0xEF])
13    checksum = -sum(frame[1:7]) & 0xFFFF    # sağlama toplamı / checksum
14    frame[7] = checksum >> 8
15    frame[8] = checksum & 0xFF
16    uart.write(frame)
17    time.sleep_ms(30)
18
19buf = b""
20
21def events():
22    # gelen 10 baytlık bildirimlerin komut kodlarını döndür / return command codes of incoming messages
23    global buf
24    if uart.any():
25        buf += uart.read()
26    codes = []
27    while True:
28        start = buf.find(b"\x7e")
29        if start < 0:
30            buf = b""
31            break
32        if len(buf) - start < 10:
33            buf = buf[start:]
34            break
35        frame = buf[start:start + 10]
36        if frame[9] == 0xEF:
37            codes.append(frame[3])
38            buf = buf[start + 10:]
39        else:
40            buf = buf[start + 1:]
41    return codes
42
43def play_track(n):
44    send(0x12, n)                           # /mp3/000n.mp3 dosyasını çal / play /mp3/000n.mp3
45
46time.sleep(2)                               # modül kartı okusun / let the module read the card
47send(0x06, 18)                              # ses 18/30 / volume 18 of 30
48track = 1
49play_track(track)
50playing = True
51last_end = 0
52
53while True:
54    if btn_next.value() == 0:
55        track = track % TRACKS + 1          # son parçadan sonra başa dön / wrap after the last track
56        play_track(track)
57        playing = True
58        time.sleep_ms(300)                  # basit sıçrama önleme / simple debounce
59    if btn_play.value() == 0:
60        send(0x0E if playing else 0x0D)     # 0x0E duraklat, 0x0D devam / 0x0E pause, 0x0D resume
61        playing = not playing
62        time.sleep_ms(300)
63    for code in events():
64        # 0x3D: SD karttaki parça bitti / 0x3D: track on the SD card finished
65        if code == 0x3D and time.ticks_diff(time.ticks_ms(), last_end) > 1000:
66            last_end = time.ticks_ms()      # çift bildirimi yok say / ignore the duplicate message
67            track = track % TRACKS + 1
68            play_track(track)
69

Thonnyでコードをmain.pyとしてPicoに保存すれば、Picoは電源を入れるたびにMP3プレーヤーとして動きます。MicroPythonが初めてならMicroPythonの基本を見てください。GP14のボタンで次の曲に進み、GP15のボタンで一時停止と再開をします。各ボタンのもう片側はGNDへつなぎます。events()関数は届いたバイトをバッファにためて、0x7Eで始まり0xEFで終わるパケットを取り出します。曲の終了(0x3D)のメッセージが届くと、コードは次のファイルに進み、最後のファイルのあとは最初に戻ります。TRACKS変数を/mp3フォルダのファイル数に合わせるのを忘れないでください。

DFPlayer Miniのプロジェクトアイデア

  • メロディーの玄関チャイム:ボタンを押すとランダムなメロディーを鳴らし、夜は音量を下げる玄関チャイム。
  • おかえりシステム:PIR人感センサーが、誰かが来るとあいさつを流します。
  • カードで選ぶオルゴール:RFIDカードごとに別のフォルダを再生する、子ども向けの画面のない音楽プレーヤー。
  • しゃべる時計:RTC時計モジュールを使い、時刻を読み上げたり、毎正時を知らせたりする時計。
  • リモコンで操作するMP3プレーヤー:赤外線受信モジュールとリモコンで曲と音量を操作します。
  • ハロウィーンの小道具やびっくり箱:HC-SR04が人の接近を検知すると怖い音を鳴らします。
  • 音声の警報と通知:ガス、水漏れ、開けっぱなしのドアのとき、ビープ音の代わりに「キッチンでガスを検知しました」のようなはっきりした文を流します。
  • ディスプレイ付きMP3プレーヤー:曲番号と音量をOLEDディスプレイに表示します。

正しく名前を付けたSDカード、RXの線の1 kΩの抵抗、しっかりした5 Vの電源があれば、DFPlayer MiniはArduinoのプロジェクトに数分で本物の音を加えてくれます。何かがうまくいかなければ、まずカードと配線、次に電源を確認してください。ほとんどの問題はこの3つのどれかから生じます。シリアル通信の基本に興味があれば、UARTシリアル通信が次のステップにちょうどよいでしょう。BlueGraysアプリには、ブザーでのメロディーの演奏、簡単なピアノ、人感センサーの玄関チャイム、ESP32のメロディーといった音のプロジェクトが、回路図とステップごとのコード付きで揃っています。それらにDFPlayer Miniで本物の音を持たせることもできます。

よくある質問

DFPlayer Miniが対応するSDカードの容量は?

DFPlayer Miniが読めるのは、FAT16かFAT32でフォーマットした32 GBまでのmicroSDカードです。64 GB以上のカードはexFATでフォーマットされているので、モジュールには見えません。数百曲のMP3なら1〜16 GBのカードで十分です。

DFPlayer Miniから音が出ないのはなぜ?

まずシリアルモニタに「online」と出ているか確認してください。出ていなければ、問題は配線かSDカードです。モジュールは起動するのに音が出ない場合は、音量が0になっていないか、スピーカーがSPK_1とSPK_2につながっているか、ファイル名が呼んでいる関数と合っているかを確認してください。基板のLEDが点いていれば、モジュールは確かに再生しています。

DFPlayer MiniのRXピンに1kΩの抵抗を入れるのはなぜ?

モジュールのチップは3.3 Vで動きますが、Arduino UnoのTXピンは5 Vを出します。RXの線と直列に入れた1 kΩの抵抗がチップに流れ込む電流を制限し、シリアル通信中にスピーカーから聞こえる雑音を減らします。ESP32やPicoのような3.3 Vのボードでも、ノイズ対策として推奨されます。

DFPlayer MiniはArduinoなしで動く?

はい。IO_1とIO_2のピンをボタンを通してGNDにつなげば、短く押すと曲が変わり、長押しで音量が変わります。抵抗を通してADKEYのピンにつないだボタンで、特定の曲を再生することもできます。こうすれば、マイコンなしで電池、スピーカー、いくつかのボタンだけでMP3プレーヤーや玄関チャイムを作れます。

DFPlayer Miniにはどんなスピーカーをつなげる?

3 W未満の4 Ωか8 Ωのスピーカーなら、SPK_1とSPK_2のピンに直接つなげます。最もバランスがよいのは8 Ω・1〜3 Wのスピーカーです。スピーカーのどちらの線もGNDには絶対につながないでください。より大きな音やステレオの音には、DAC_LとDAC_Rの出力をPAM8403のようなアンプにつなぎます。

DFPlayer Miniがファイルを違う順番で再生するのはなぜ?

play(n)関数はファイル名ではなく、ファイルをカードにコピーした順番を見ています。名前で再生するには、ファイルを/mp3/0001.mp3と名付けてplayMp3Folder()を使うか、/01/001.mp3と名付けてplayFolder()を使ってください。Macでカードを準備した場合は、隠しファイルの._のファイルも削除してください。

全プロジェクトを見る
ブザーの使い方
#13初級

ブザーの使い方

呼び鈴やアラームがどうやって音を出すのか、気になったことはありませんか?Arduinoが小さなブザーを短い間隔で鳴らし、音を出す、止める、を繰り返します。電気で音が生まれる仕組みを学び、メロディーを演奏するプロジェクトへの第一歩を踏み出せます。

4.7(89)
161
ブザーでトルコ国歌を演奏
#15中級

ブザーでトルコ国歌を演奏

ボタンを押すと、小さなブザーがトルコ国歌を1音ずつ演奏し始めます。Arduinoが各音を正しい音程と長さで鳴らし、国歌の2節を最初から最後まで演奏した後、次のボタン操作を待ちます。シンプルな音響部品からメロディーが生まれる様子を、自分の耳で確かめられます。

4.9(106)
213
ブザーの周波数を調整
#14中級

ブザーの周波数を調整

4つのボタンでブザーの音を操作します。1つは音を鳴らし、1つは音を止め、残りの2つは音を高くしたり低くしたりします。音を高くするボタンや低くするボタンを押し続けると、音程が段階的に変化し、サイレンのように聞こえます。音の高低が生まれる理由を、自分の耳で確かめられます。

4.6(69)
118
ESP32とブザーでメロディーを演奏
#114初級
プレミアム

ESP32とブザーでメロディーを演奏

パッシブブザーで簡単なメロディー「きらきら星」を演奏します。Arduinoと同じようにtone()とnoTone()で音を鳴らします。ESP32 Arduino Core 3.0+でも同じ構文が使えます。パッシブブザーを使用してください。アクティブブザーではメロディーを演奏できません。

4.8(30)
55
IR受信機・リモコン・ブザーでメロディーを再生
#18初級
プレミアム

IR受信機・リモコン・ブザーでメロディーを再生

テレビのリモコンのボタンでメロディーを奏でるオルゴールを作ります。赤外線受信機がリモコンの信号を受け取り、1つ目のボタンで軽快なゲーム音楽、2つ目でおなじみの童謡、3つ目で新年の歌をブザーから流します。リモコンが目に見えない光で通信する仕組みと、音符を音に変える方法を学びます。

4.8(57)
74
ブザーとボタンで作る簡単なピアノ
#26上級
プレミアム

ブザーとボタンで作る簡単なピアノ

8個のボタンで小さなピアノを作ります。各ボタンには、低い音から順にド、レ、ミ、ファ、ソ、ラ、シ、高いドが割り当てられています。ボタンを押している間はブザーから音が鳴り、離すと止まります。簡単な曲を弾きながら、音符の正体が音の振動であることを実感できます。

4.9(66)
88
モーションセンサーで作るドアベルとライト
#25中級
プレミアム

モーションセンサーで作るドアベルとライト

玄関に誰かが近づくと、呼び鈴を押す前にわかります。モーションセンサーが人を検知するとLEDが点灯し、ブザーが高い音から低い音へ3音のチャイムを鳴らします。メロディーが終わるとライトが消え、センサーは再び待機します。音と光の両方で知らせるシンプルな玄関の見張り役です。

4.7(54)
71