Компоненты · 13 мин чтения

DFPlayer Mini и Arduino: воспроизведение MP3, SD-карта и динамик

Как работать с DFPlayer Mini на Arduino: резистор 1k на RX, SD-карта и имена вида 0001.mp3, код с библиотекой, кнопки, динамик, а также примеры для ESP32 и Pico.

DFPlayer Mini — самый дешёвый и простой способ проигрывать MP3 на Arduino: он сам декодирует аудиофайлы с карты microSD, напрямую раскачивает динамик своим маленьким встроенным усилителем и получает команды от Arduino по двухпроводному последовательному каналу. В отличие от писка зуммера, он может играть песни, речь, мелодии дверного звонка или голосовые предупреждения вроде «Дверь всё ещё открыта». При первом подключении почти все сталкиваются с одними и теми же проблемами: звука нет, динамик шипит, файлы играют не по порядку или монитор порта пишет «Unable to begin». Это руководство решает каждую из них и объясняет, почему они возникают.

Сначала ты разберёшься с пинами модуля и узнаешь, зачем на линию RX ставят резистор 1 kΩ. Затем увидишь, как отформатировать SD-карту в FAT32, назвать файлы и папки по схеме 0001.mp3 и 01, проиграть первый звук с библиотекой DFRobotDFPlayerMini, настроить громкость и эквалайзер, переключать треки кнопками и подобрать подходящий динамик или внешний усилитель. В последних разделах — пошаговое решение ошибки «Unable to begin», MP3-плеер на ESP32 с управлением через веб-страницу и пример на MicroPython для Raspberry Pi Pico без библиотеки. Если нужен только писк или простая мелодия, проще взять зуммер.

MP3-плеер DFPlayer Mini
DFPlayer Mini: всего 20 × 20 мм, а на плате слот для карты microSD, микросхема MP3-декодера и маленький усилитель, способный раскачать динамик мощностью до 3 W.

Что такое DFPlayer Mini и как он работает?

DFPlayer Mini — это самостоятельный MP3-плеер, состоящий из микросхемы MP3-декодера, 24-битного ЦАП, слота для карты microSD и маленького монофонического усилителя. Arduino нужно лишь отправлять короткие команды вроде «играть трек 3» или «громкость 20»; чтение файла с карты, декодирование сжатого звука и раскачка динамика — работа модуля. Поэтому даже Arduino Uno с 2 КБ ОЗУ легко проигрывает музыку. Команды передаются на скорости 9600 бод пакетами по 10 байт, а модуль отвечает в том же формате, когда трек заканчивается, карта вставляется или извлекается либо возникает ошибка. Микросхема на плате зависит от производителя (YX5200-24SS, MH2024K-24SS, GD3200B и другие). Все они понимают одни и те же команды, но могут отвечать с разной задержкой, и эта деталь ещё пригодится при разборе ошибки «Unable to begin». Управлять модулем можно тремя способами: через последовательный порт (UART), кнопками на пинах IO или резисторной лестницей ADKEY.

ХарактеристикаЗначение
Поддерживаемые файлыMP3, WAV, WMA
Частоты дискретизации8 / 11,025 / 12 / 16 / 22,05 / 24 / 32 / 44,1 / 48 kHz
ЦАП24 бита; динамический диапазон 90 dB, отношение сигнал/шум 85 dB
НосительКарта microSD (TF) до 32 ГБ, FAT16 или FAT32; поддерживаются и USB-флешки
Ёмкость папокДо 100 папок, 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 мм

Распиновка DFPlayer Mini

ПинНазваниеНазначение
1VCCВход питания, 3,2–5,0 V
2RXПоследовательный вход: подключается к пину TX платы через резистор 1 kΩ
3TXПоследовательный выход: идёт на пин RX платы
4DAC_RЛинейный выход правого канала (наушники или усилитель)
5DAC_LЛинейный выход левого канала (наушники или усилитель)
6 и 8SPK_1, SPK_2Выход на динамик: сюда подключаются два вывода динамика мощностью до 3 W
7GNDЗемля
9IO_1Кнопка на GND, короткое нажатие: предыдущий трек; долгое: тише
10GNDЗемля
11IO_2Кнопка на GND, короткое нажатие: следующий трек; долгое: громче
12ADKEY1Вход для нескольких кнопок через резисторную лестницу
13ADKEY2Второй вход резисторной лестницы
14USB+D+ для USB-флешки
15USB−D− для USB-флешки
16BUSYLOW во время воспроизведения, HIGH в покое

При работе через последовательный порт нужны только пины VCC, GND, RX, TX и выходы на динамик. Пин BUSY сообщает, закончился ли трек, без всякого обмена по UART, а маленький светодиод на плате тоже горит во время воспроизведения. Пины IO_1 и IO_2 позволяют модулю работать вообще без Arduino: если поставить кнопку между каждым из них и GND, короткое нажатие переключает трек, а долгое меняет громкость. Кнопки, подключённые к пинам ADKEY через резисторы разного номинала, могут ещё и запускать конкретные треки. Значит, для дверного звонка или говорящей игрушки без микроконтроллера хватит батарейки, динамика и двух кнопок. Пины USB+ и USB− нужны для воспроизведения с USB-флешки вместо SD-карты и в большинстве проектов остаются неподключёнными.

Подключение DFPlayer Mini к Arduino и резистор 1k на RX

Пин DFPlayerArduino UnoESP32Raspberry Pi Pico
VCC5V5V (VIN)VBUS (USB 5 V, пин 40)
GNDGNDGNDGND
RXD11 через резистор 1 kΩGPIO 17 (TX2) через резистор 1 kΩGP0 (UART0 TX) через резистор 1 kΩ
TXD10GPIO 16 (RX2)GP1 (UART0 RX)
SPK_1 и SPK_2Два вывода динамикаДва вывода динамикаДва вывода динамика
BUSY (необязательно)D5Не используетсяНе используется
Arduino Uno
Arduino Uno
ESP32
ESP32
Raspberry Pi Pico
Raspberry Pi Pico

Линии данных перекрещиваются: TX модуля идёт на RX платы, а его RX — на TX платы. Аппаратный последовательный порт Uno на D0 и D1 занят загрузкой по USB и монитором порта, поэтому модуль подключаем к D10 (RX) и D11 (TX) через SoftwareSerial. Резистор 1 kΩ последовательно со входом RX модуля — вовсе не мелочь. Микросхема DFPlayer работает с логикой 3,3 V, а пин TX у Uno выдаёт 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 читает карты microSD объёмом до 32 ГБ, отформатированные в FAT16 или FAT32. Карты на 64 ГБ и больше продаются отформатированными в exFAT, а эту систему модуль не читает; для нескольких сотен треков с лихвой хватит карты на 1–16 ГБ. Кодировать 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 папок, 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(), копируй их по одному и по порядку: при копировании всех сразу порядок может перепутаться.
  5. Безопасно извлеки карту и вставь её в модуль при выключенном питании: если вставлять или вынимать её во время работы, файлы могут повредиться.
macOS создаёт для каждого файла скрытые копии вроде ._0001.mp3, а также скрытые папки вроде .Spotlight-V100 и .fseventsd. DFPlayer тоже считает их файлами, поэтому играет не тот трек, стоит тишина или readFileCounts() показывает больше файлов, чем должно быть. Если карта готовилась на Mac, выполни в «Терминале» dot_clean -m /Volumes/CARD_NAME или удали скрытые файлы вручную. Папка System Volume Information, которую создаёт Windows, обычно проблем не вызывает.

Библиотека DFRobotDFPlayerMini и первый тестовый скетч

  1. В Arduino IDE открой «Менеджер библиотек» (Library Manager), введи DFRobotDFPlayerMini и установи библиотеку от DFRobot. Установка подробно описана в статье Как добавить библиотеку в Arduino.
  2. Скопируй хотя бы один MP3 в корень SD-карты, вставь карту в модуль и собери схему, как показано в таблице.
  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(порт, isACK, doReset)Запускает модуль; по умолчанию отправляет сброс и ждёт сообщения о том, что карта готова
volume(0–30)Задаёт громкость; volumeUp() и volumeDown() меняют её на одну ступень
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 секунд ждёт сообщения о готовности карты, поэтому запуск в несколько секунд — это нормально. По умолчанию библиотека ждёт подтверждения от модуля после каждой команды, так что команды не накапливаются. И всё же не отправляй volume() или play() на каждом проходе loop(): модуль, на который команды сыплются без остановки, может зависнуть, а динамик будет щёлкать. Отправляй команду, только когда что-то изменилось.

Громкость, эквалайзер и объявления по очереди с пином BUSY

Громкость меняется от 0 до 30. С маленьким динамиком для большинства комнат хватает 15–20; выше 25, особенно при слабом питании, звук может начать искажаться (клиппинг), а модуль — перезагружаться. Настройка эквалайзера меняет баланс низких и высоких частот; на маленьких динамиках режим BASS может сделать звук глухим, поэтому начни с NORMAL. Нумерованные папки очень удобны для говорящих проектов: положи слова «Температура» и «градусов» в папку 01, а числа от 001.mp3 до 100.mp3 в папку 02, и Arduino сможет произносить числа целым предложением. Самый надёжный способ узнать, что файл доиграл, — пин BUSY: он в LOW, пока модуль играет, и в HIGH, когда модуль простаивает. Скетч ниже читает BUSY на D5 и проигрывает файлы один за другим, не накладывая их друг на друга:

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() сначала отправляет команду, до 1 секунды ждёт, пока BUSY перейдёт в LOW (модулю нужно несколько сотен миллисекунд, чтобы начать играть), а затем ждёт окончания трека. Аудиофайлы можно записать своим голосом или сгенерировать в сервисе синтеза речи (TTS); если обрезать тишину в начале и в конце каждого файла, объявление звучит естественнее. Чтобы прервать музыку коротким предупреждением, используй advertise(n): модуль проиграет объявление из папки /advert, а затем продолжит музыку с того же места. Эта команда работает только во время воспроизведения трека; если вызвать её, когда модуль простаивает, она вернёт ошибку.

Переключение треков кнопками и громкость с потенциометра

Теперь соберём собственный MP3-плеер: три кнопки работают как «предыдущий трек», «воспроизведение/пауза» и «следующий трек», а потенциометр задаёт громкость. Подключи кнопки между D2, D3, D4 и GND; так как используются встроенные подтягивающие резисторы, внешние резисторы не нужны (почему — объясняется в статье Как подключить кнопку). Крайние выводы потенциометра идут на 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 мс; если держать кнопку, всё равно уходит одна команда
abs(raw - lastRaw) > 20Обновляет громкость только при заметных изменениях, чтобы мелкие колебания показаний потенциометра не заваливали модуль командами и не вызывали щелчков
map(raw, 0, 1023, 0, 30)Переводит аналоговое значение 0–1023 в диапазон громкости DFPlayer 0–30
pausedЗапоминает состояние воспроизведения, чтобы одна и та же кнопка и ставила на паузу, и продолжала
DFPlayerPlayFinishedСообщение, которое приходит по окончании трека; скетч переходит к следующему
millis() - lastFinish > 1000Некоторые клоны сообщают о конце трека дважды; эта проверка не даёт пропустить трек

Выбор динамика (3 W) и внешнего усилителя

Собственный усилитель DFPlayer (на большинстве плат это микросхема типа 8002) напрямую раскачивает динамик мощностью до 3 W с сопротивлением 4 Ω или 8 Ω. Лучший баланс даёт динамик на 8 Ω и 1–3 W; маленькие динамики на 0,5 W тоже работают, но на большой громкости не справляются. Цифра 3 W — это верхний предел усилителя при питании 5 V и нагрузке 4 Ω, в точке, где искажения становятся явными; чистая мощность в обычном использовании ниже. Если установить динамик в корпус или хотя бы на панель, басы заметно улучшатся, потому что звук от передней и задней стороны диффузора перестаёт гасить друг друга. На большой громкости модуль может кратковременно потреблять несколько сотен миллиампер; если Arduino питается от USB-порта компьютера, это может вызвать просадки напряжения, шипение и перезагрузки. Если нужна большая мощность или стереозвук, подключи линейные выходы DAC_L и DAC_R к внешнему усилителю:

Путь сигналаПодключениеКогда?
Встроенный усилительSPK_1 и SPK_2 → динамик 4–8 Ω мощностью до 3 WНебольшие проекты: дверные звонки, игрушки, голосовые оповещения
НаушникиDAC_L, DAC_R и GND → гнездо 3,5 ммЛичное прослушивание; начинай с малой громкости
Модуль усилителя PAM8403DAC_L, DAC_R и GND → входы L, R и GND усилителя; усилитель питается от 5 VСтерео 2 × 3 W, портативная колонка на батарейках
Усилитель PAM8610 или TPA3116Выходы ЦАП → вход усилителя; усилитель питается от 12 VБольше мощности: от 2 × 10 W
Активная колонка (AUX)DAC_L, DAC_R и GND → вход AUX активной колонкиКогда есть готовая компьютерная колонка
Поставь электролитический конденсатор на 100–470 µF между пинами VCC и GND модуля DFPlayer, как можно ближе к модулю: он покрывает резкие скачки тока на большой громкости и предотвращает перезагрузки. Если используется внешний усилитель, соедини усилитель, DFPlayer и Arduino в одной точке GND: схемы, которые питаются от разных адаптеров с раздельной землёй, — самая частая причина гула. Почему это важно, мы объясняем в статье Общая земля (GND). Делай провода динамика короткими и не прокладывай их рядом с проводами последовательного порта.

Как избавиться от шипения, шума и щелчков

  • Шипение и щелчки при отправке команд: на линии RX нет резистора 1 kΩ. Поставь его между пином TX Arduino и пином RX модуля.
  • Постоянное шипение или гул: источник питания шумит или слишком слабый. Запитай DFPlayer от отдельного источника 5 V, добавь конденсатор между VCC и GND и соедини все GND вместе.
  • Хлопок при запуске: его вызывает команда сброса, которую отправляет begin(). Если он мешает, пропусти сброс с помощью player.begin(dfSerial, true, false).
  • Треск с ESP32: импульсы тока во время передачи по Wi-Fi попадают в питание, а оттуда в звук. Добавь конденсатор в питание DFPlayer и по возможности используй отдельный источник.
  • Хриплый, искажённый звук на большой громкости: динамик или усилитель работает на пределе. Убавь громкость примерно до 20–25, выбери более чувствительный динамик или перейди на внешний усилитель.
  • Тихое шипение, когда ничего не играет: это собственный шум встроенного усилителя, и на маленьких модулях он никогда не пропадает полностью. В проектах, где важна тишина, лучший результат даёт подключение выхода ЦАП к хорошему внешнему усилителю.

Ошибка «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 (RX для SoftwareSerial), а его RX — на D11 (TX для SoftwareSerial) через 1 kΩ; это должно совпадать с порядком (RX, TX) в SoftwareSerial(10, 11)
Нет общей земли GNDGND модуля должен быть соединён с GND Arduino; при отдельном источнике питания тоже соедини земли
SD-карта не читаетсяКарта вставлена, в FAT32, не больше 32 ГБ и на ней есть хотя бы один аудиофайл? Отформатируй её заново или попробуй другую карту
Не тот резисторЛинии RX нужен 1 kΩ; большие номиналы вроде 10 kΩ ослабляют сигнал
Не хватает питанияНа VCC должно быть 4–5 V; временно отключи динамик, измерь напряжение мультиметром и добавь конденсатор
Не та скоростьДолжно быть dfSerial.begin(9600); не путай со скоростью монитора порта (115200)
Заняты D0 и D1На Uno аппаратный последовательный порт общий с USB; перенеси модуль на пины SoftwareSerial
Микросхема-клон отвечает с опозданиемДобавь delay(1000) перед begin(); если не помогает, используй begin(dfSerial, true, false), чтобы пропустить ожидание после сброса
Код DFPlayerErrorИмя в библиотекеЗначение
1BusyМодуль занят или карта не найдена (инициализация не завершена)
2SleepingМодуль в режиме сна
3SerialWrongStackПолучены повреждённые последовательные данные
4CheckSumNotMatchКонтрольная сумма пакета не совпала
5FileIndexOutЗапрошенный номер трека вне диапазона на карте
6FileMismatchЗапрошенный файл не найден; проверь имена
7AdvertiseОшибка объявления, например advertise() вызвана, когда ничего не играет
Некоторые дешёвые платы-клоны после сброса вообще не присылают ожидаемое сообщение или присылают его поздно; тогда begin() возвращает false, хотя подключение правильное. player.begin(dfSerial, true, false) пропускает шаг сброса и проходит проверку; если с такой настройкой модуль звучит, проблема была именно в этом. Однако эта настройка скрывает и настоящую ошибку подключения, поэтому сначала проверь пункты из таблицы. Чтобы понять, отвечает ли модуль вообще, посмотри на player.readFileCounts(): если функция возвращает -1, ответа от модуля нет.

DFPlayer Mini и ESP32: управление MP3 с веб-страницы

На ESP32 SoftwareSerial не нужен: любой из трёх аппаратных UART можно назначить на выбранные пины. В скетче ниже UART2 работает на GPIO 16 (RX) и GPIO 17 (TX), а DFPlayer питается от пина 5V (VIN) платы ESP32. Сигнал TX у ESP32 на 3,3 V напрямую совместим с модулем, но резистор 1 kΩ всё равно оставь как защиту от помех. В обратном направлении DFRobot указывает логический уровень модуля 3,3 V; тем не менее на линии TX некоторых плат-клонов с питанием 5 V намеряли более высокое напряжение. Перед подключением измерь мультиметром напряжение между 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 сама перезагружается, когда динамик играет громко, проблема в питании; подробности — в статье Brownout на ESP32.

DFPlayer Mini с Raspberry Pi Pico и MicroPython (UART)

На Raspberry Pi Pico вместо поиска готовой библиотеки проще и полезнее работать напрямую с последовательным протоколом модуля. Каждая команда — это пакет из 10 байт: стартовый байт 0x7E, версия 0xFF, длина 0x06, код команды, флаг обратной связи (0 = без подтверждения), двухбайтовый параметр, двухбайтовая контрольная сумма и конечный байт 0xEF. Контрольная сумма — это 16-битное отрицание суммы шести байтов от версии до последнего байта параметра. Например, пакет, который запускает первый трек в корне, выглядит так: 7E FF 06 03 00 00 01 FE F7 EF. Модуль, в свою очередь, присылает сообщения с кодом 0x3D, когда трек заканчивается, 0x3F, когда карта готова, и 0x40 при ошибке. UART у Pico на 3,3 V подходит модулю напрямую; предупреждение о напряжении на TX из раздела про ESP32 действует и здесь, потому что пины Pico тоже не выдерживают 5 V. Питай модуль от пина VBUS (USB 5 V) на Pico.

КомандаКодПараметр
Следующий / предыдущий трек0x01 / 0x02Нет
Играть n-й трек в корне0x031–2999
Громкость0x060–30
Эквалайзер0x070–5
Сброс0x0CНет
Продолжить / пауза0x0D / 0x0EНет
Играть из папки0x0FСтарший байт — папка (1–99), младший — файл (1–255)
Играть из папки mp30x12Номер файла (1 для 0001.mp3)
Объявление (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

Если сохранить код на Pico как main.py через Thonny, Pico будет работать как MP3-плеер при каждом включении; если MicroPython для тебя в новинку, загляни в статью Основы MicroPython. Кнопка на GP14 переключает на следующий трек, а кнопка на GP15 ставит на паузу и продолжает; второй вывод каждой кнопки идёт на GND. Функция events() собирает входящие байты в буфер и выделяет пакеты, которые начинаются с 0x7E и заканчиваются 0xEF. Когда приходит сообщение «трек закончился» (0x3D), код переходит к следующему файлу, а после последнего возвращается к первому. Не забудь задать в переменной TRACKS количество файлов в папке /mp3.

Идеи проектов с DFPlayer Mini

  • Мелодичный дверной звонок: звонок, который при нажатии кнопки играет случайную мелодию, а ночью звучит тише.
  • Система приветствия: PIR-датчик движения запускает приветствие, когда кто-то входит.
  • Музыкальная шкатулка на картах: каждая RFID-карта запускает свою папку; музыкальный плеер без экрана для детей.
  • Говорящие часы: часы с модулем часов реального времени (RTC), которые произносят время или объявляют каждый час.
  • MP3-плеер с пультом: переключение треков и громкость через ИК-приёмник и пульт.
  • Реквизит для Хэллоуина или коробка-розыгрыш: HC-SR04 включает страшный звук, когда замечает, что кто-то подходит.
  • Голосовые тревоги и оповещения: понятные фразы вроде «На кухне обнаружен газ» вместо писка, когда утечка газа, протечка воды или дверь осталась открытой.
  • MP3-плеер с дисплеем: номер трека и громкость на OLED-дисплее.

С правильно названными файлами на SD-карте, резистором 1 kΩ на линии RX и надёжным питанием 5 V DFPlayer Mini за считаные минуты добавит настоящий звук в твои проекты на Arduino. Если что-то не так, сначала проверь карту и подключение, потом питание: почти любая проблема кроется в одном из этих трёх мест. Если интересны основы последовательной связи, хороший следующий шаг — статья Последовательный интерфейс UART. В приложении BlueGrays есть звуковые проекты: мелодии на зуммере, простое пианино, дверной звонок с датчиком движения и мелодии на ESP32, у каждого схема подключения и пошаговый код, а потом им можно дать настоящий звук с DFPlayer Mini.

Частые вопросы

Какой объём SD-карты поддерживает DFPlayer Mini?

DFPlayer Mini читает карты microSD объёмом до 32 ГБ, отформатированные в FAT16 или FAT32. Карты на 64 ГБ и больше поставляются в формате exFAT, поэтому модуль их не видит. Для нескольких сотен MP3 с лихвой хватит карты на 1–16 ГБ.

Почему DFPlayer Mini не воспроизводит звук?

Сначала убедись, что в мониторе порта появляется «online»; если нет, проблема в подключении или SD-карте. Если модуль запускается, но звука нет, проверь, что громкость не 0, динамик подключён к SPK_1 и SPK_2, а имена файлов соответствуют вызываемой функции. Если светодиод на плате горит, модуль действительно играет.

Зачем на пин RX модуля DFPlayer Mini ставят резистор 1k?

Микросхема модуля работает от 3,3 V, а пин TX у Arduino Uno выдаёт 5 V. Резистор 1 kΩ последовательно с линией RX ограничивает ток, текущий в микросхему, и уменьшает шипение динамика во время обмена данными. Его советуют ставить и на платах с логикой 3,3 V, таких как ESP32 и Pico, для защиты от помех.

Может ли DFPlayer Mini работать без Arduino?

Да. Если подключить пины IO_1 и IO_2 к GND через кнопки, короткое нажатие переключает трек, а долгое меняет громкость. Кнопки, подключённые к пинам ADKEY через резисторы, могут ещё и запускать конкретные треки. Так можно собрать MP3-плеер или дверной звонок всего из батарейки, динамика и нескольких кнопок, без микроконтроллера.

Какой динамик можно подключить к DFPlayer Mini?

Динамик на 4 Ω или 8 Ω мощностью до 3 W подключается напрямую к пинам 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Средний

Гимн Турции на зуммере

Нажми кнопку, и маленький зуммер начнёт нота за нотой играть Государственный гимн Турции. Arduino играет каждую ноту нужной высоты и длительности, исполняет два куплета гимна от начала до конца и ждёт

4.9(106)
213
Настройка частоты зуммера
#14Средний

Настройка частоты зуммера

Ты управляешь звуком зуммера четырьмя кнопками: одна включает звук, другая выключает, а две оставшиеся делают его выше или ниже. Удерживай кнопку вверх или вниз, и высота звука меняется шаг за шагом,

4.6(69)
118
Мелодия на зуммере с ESP32
#114Новичок
Premium

Мелодия на зуммере с ESP32

Воспроизведение простой мелодии (Twinkle Twinkle Little Star) на пассивном зуммере. Ноты играются функциями tone() и noTone(), как в Arduino, — ESP32 работает с тем же синтаксисом в Arduino Core 3.0+. Нужен пассивный зуммер (активный мелодию не сыграет).

4.8(30)
55
Мелодии с ИК-пультом и зуммером
#18Новичок
Premium

Мелодии с ИК-пультом и зуммером

Собери музыкальную шкатулку, которая играет мелодии по кнопкам пульта от телевизора. Инфракрасный приёмник ловит сигнал пульта; одна кнопка играет на зуммере весёлую мелодию из видеоигры, другая — зна

4.8(57)
74
Простое пианино на зуммере и кнопках
#26Продвинутый
Premium

Простое пианино на зуммере и кнопках

Собери своё маленькое пианино из восьми кнопок. Каждая кнопка — одна нота, от низкой к высокой: до, ре, ми, фа, соль, ля, си и верхнее до. Нота звучит через зуммер, пока ты держишь кнопку, и замолкает

4.9(66)
88
Дверной звонок и свет с датчиком движения
#25Средний
Premium

Дверной звонок и свет с датчиком движения

Когда кто-то подходит к твоей двери, ты узнаёшь об этом ещё до звонка. Как только датчик движения замечает человека, загорается светодиод, а зуммер играет мелодию из трёх нот сверху вниз; когда мелоди

4.7(54)
71