Introduction
In this project, we are going to build a simple yet powerful DIY MP3 player using an Arduino and the DFPlayer Mini module. The DFPlayer Mini is a great choice for hobbyists because it is cheap, compact, and has a built-in power amplifier. Unlike other modules, it can be used with or without an Arduino, but by connecting it to a microcontroller, we can create custom controls like buttons, sensors, or even a remote control to play specific sounds.
📌Why use the DFPlayer Mini?
There are several reasons why this module is better than using a standard SD card shield for audio:Built-in DAC: It handles the audio processing internally, so the Arduino doesn't have to work hard.
Direct Speaker Support: You can connect a small speaker (up to 3W) directly to the pins without needing an external amplifier.
Format Support: It supports both MP3 and WAV files, which are common and easy to manage.
Preparing Your SD Card
Before you power on the circuit, you must prepare your Micro SD card correctly:Format: Use a PC to format the card to FAT32.
Folders: Create a folder named
mp3.Naming Files: Name your songs
0001.mp3, 0002.mp3, etc. The module is very sensitive to naming conventions; if the names are random, the Arduino might fail to find the file.Arduino MP3 Player Using DFPlayer Mini Module
If you want to build your own MP3 player with Arduino, the DFPlayer Mini module makes it simple and fun. This project lets your Arduino play MP3 files directly from a Micro-SD card and control playback with buttons, volume, and more.
🛠️ What You Need
To build this project, you will use:
✔ DFPlayer Mini MP3 Module
✔ Micro-SD card with MP3 files
✔ Speaker (8 Ω – 4 Ω)
✔ Breadboard & jumper wires
✔ Push Buttons
✔ USB Port
Circuit Diagram
👉 Connect the speaker to SPK1 and SPK2 for sound output.
How the Circuit Works
The connection between the Arduino and the DFPlayer Mini uses Serial Communication. We use theSoftwareSerial library so that we can keep the main Hardware Serial (pins 0 and 1) free for uploading code.Crucial Note: You must place a 1k Ohm resistor between the Arduino’s TX pin and the DFPlayer’s RX pin. This is because the DFPlayer Mini operates at 3.3V, while the Arduino provides 5V. Without this resistor, you will likely hear a loud "buzzing" or "popping" noise in the speaker, and it might eventually damage the module.
Understanding the Enhanced MP3 Player Code
This updated version of the code does more than just play music; it adds a User Interface (UI) using a 16x2 LCD and implements advanced button controls. Below is a breakdown of how the logic works:
1. Custom Character Creation
To make the display look professional, the code uses uint8_t arrays to define custom icons for Play (0), Pause (1), Next (2), and Volume (4/5). These are loaded into the LCD's memory using the lcd.createChar() command during the setup() phase. This adds a visual element that standard text cannot provide.
2. Advanced Button Logic (Short vs. Long Press)
Instead of using simple digitalRead commands that can be unreliable, this code implements a "timer" logic using millis(). This allows a single button to perform two different tasks:
Short Press: Skips to the next or previous song.
Long Press: Adjusts the volume up or down. This is achieved by checking how long the button pin remains in the
LOWstate. If the duration exceedslongPressTimeL(250ms), the volume changes; otherwise, the track changes.
3. Communicating via Hexadecimal Commands
The code features a custom function called execute_CMD. This is a deep-level communication method that sends a 10-byte data packet to the DFPlayer Mini.
Start Byte (0x7E): Tells the module a command is coming.
Checksum: This is a mathematical calculation that ensures the data wasn't corrupted during transmission. Using this method instead of a basic library allows for faster response times and more control over features like specific volume levels (0-30).
4. User Feedback on LCD
Every time you interact with the player, the lcd.setCursor and lcd.print functions update the display. Whether you are pausing the music or cranking up the volume, the screen provides instant confirmation. We have included delay(500) and lcd.clear() sequences to ensure the text doesn't flicker and is easy for the user to read.
<LiquidCrystal_I2C.h> Library 👇
CODE
#include "SoftwareSerial.h"
#include "Wire.h"
#include "LiquidCrystal.h"
LiquidCrystal lcd(A5,A4,A3,A2,A1,A0);
uint8_t bPLAY[8] = {0x00, 0x00, 0x08, 0x0C, 0x0E, 0x0C, 0x08, 0x00};
uint8_t bPAUSE[8] = {0x00, 0x00, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00};
uint8_t bNEXT[8] = {0x00, 0x00, 0x11, 0x19, 0x1D, 0x19, 0x11, 0x00};
uint8_t bPREVIOUS[8] = {0x00, 0x00, 0x11, 0x13, 0x17, 0x13, 0x11, 0x00};
uint8_t bUPVOLUME[8] = {0x00, 0x00, 0x04, 0x04, 0x0E, 0x04, 0x04, 0x00};
uint8_t bDOWNVOLUME[8] = {0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00};
// Set the LCD address to 0x27 for a 16 chars and 2 line display
SoftwareSerial dfpSerial(10, 11);
/*************************
DF Player Serial Format:
1. START_BYTE 0x7E
2. VERSION 0xFF
3. LENGTH 0x06
4. COMMAND CMD / operation
5. FEEDBACK 1: with Feedback, 0: no feedback
6. PARAMETER_1 Parameter of Command (High data byte)
7. PARAMETER_2 Parameter of Command (Low data byte)
8. CHECKSUM
9. CHECKSUM
10. END_BYTE 0xEF
*/
# define START_BYTE 0x7E
# define VERSION 0xFF
# define LENGTH 0x06
# define FEEDBACK 0x00
# define END_BYTE 0xEF
# define ACTIVATED LOW
const byte buttonPin = 5;
int buttonNext = 4;
int buttonPause = 3;
int buttonPrevious = 2;
boolean isPlaying = false;
unsigned long buttonTimerL = 0;
unsigned long longPressTimeL = 250;
boolean buttonActiveL = false;
boolean longPressActiveL = false;
unsigned long buttonTimerR = 0;
unsigned long longPressTimeR = 250;
boolean buttonActiveR = false;
boolean longPressActiveR = false;
byte currVolume = 25;
void setup () {
lcd.begin(16,2);
pinMode(buttonPause, INPUT_PULLUP);
pinMode(buttonNext, INPUT_PULLUP);
pinMode(buttonPrevious, INPUT_PULLUP);
pinMode(buttonPin, INPUT_PULLUP);
Serial.begin(9600);
dfpSerial.begin (9600);
delay(1000);
//playFirst();
isPlaying = false;
setVolume(currVolume);
delay(500);
lcd.createChar(0, bPLAY);
lcd.createChar(1, bPAUSE);
lcd.createChar(2, bNEXT);
lcd.createChar(3, bPREVIOUS);
lcd.createChar(4, bUPVOLUME);
lcd.createChar(5, bDOWNVOLUME);
lcd.home();
lcd.setCursor(3,0);
lcd.print("MP3 PLAYER");
Serial.println("Setup Completed.");
}
// display all keycodes
void displayKeyCodes(void) {
uint8_t i = 0;
// while (1) {
lcd.clear();
lcd.print("Codes 0x");
lcd.print(i, HEX);
lcd.print("-0x");
lcd.print(i + 16, HEX);
lcd.setCursor(0, 1);
for (int j = 0; j < 16; j++) {
lcd.write(i + j);
}
i += 16;
delay(4000);
// }
}
void loop () {
// Button PREVIOUS / Volume DOWN
if (digitalRead(buttonPrevious) == LOW) {
if (buttonActiveL == false) {
buttonActiveL = true;
buttonTimerL = millis();
}
//if ((millis() - buttonTimerL > longPressTimeL) && (longPressActiveL == false)) {
if (millis() - buttonTimerL > longPressTimeL) { // multiple long press
longPressActiveL = true;
volumeDown();
Serial.println("Volume DOWN: ");
Serial.println(currVolume);
}
}
else {
if (buttonActiveL == true) {
if (longPressActiveL == true) {
longPressActiveL = false;
} else {
playPrevious();
Serial.println("Playing PREVIOUS song");
}
buttonActiveL = false;
}
}
// Button PLAY / PAUSE
if (digitalRead(buttonPause) == ACTIVATED)
{
Serial.println("Button PLAY");
if(isPlaying)
{
pause();
isPlaying = false;
Serial.println("Pause");
}else
{
isPlaying = true;
play();
Serial.println("Play");
}
}
// Button NEXT / Volume UP
if (digitalRead(buttonNext) == LOW) {
if (buttonActiveR == false) {
buttonActiveR = true;
buttonTimerR = millis();
}
//if ((millis() - buttonTimerR > longPressTimeR) && (longPressActiveR == false)) {
if (millis() - buttonTimerR > longPressTimeR) { // Try multiple long press
longPressActiveR = true;
volumeUp();
Serial.println("Volume UP: ");
Serial.println(currVolume);
}
}
else {
if (buttonActiveR == true) {
if (longPressActiveR == true) {
longPressActiveR = false;
} else {
playNext();
Serial.println("Playing NEXT song");
}
buttonActiveR = false;
}
}
}
void play() {
// Playback
execute_CMD(0x0D,0,1);
lcd.clear();
lcd.setCursor(3,0);
lcd.print("MP3 PLAYER");
lcd.setCursor(14, 1);
lcd.setCursor(0, 1);
lcd.print("Play");
delay(1000);
lcd.clear();
lcd.setCursor(3,0);
lcd.print("MP3 PLAYER");
lcd.setCursor(6,1);
lcd.print("Play");
delay(500);
}
void pause() {
execute_CMD(0x0E,0,0);
lcd.clear();
lcd.setCursor(3,0);
lcd.print("MP3 PLAYER");
lcd.setCursor(14, 1);
lcd.write(1);
lcd.setCursor(0, 1);
lcd.print("Pause");
delay(1000);
lcd.clear();
lcd.setCursor(3,0);
lcd.print("MP3 PLAYER");
lcd.setCursor(5,1);
lcd.print("Pause");
delay(500);
}
void playNext() {
// Next
execute_CMD(0x01,0,1);
lcd.clear();
lcd.setCursor(3,0);
lcd.print("MP3 PLAYER");
lcd.setCursor(14, 1);
lcd.write(2);
lcd.setCursor(0, 1);
lcd.print("Next");
delay(1000);
lcd.clear();
lcd.setCursor(3,0);
lcd.print("MP3 PLAYER");
lcd.setCursor(6,1);
lcd.print("Play");
delay(500);
}
void playPrevious() {
// Previous
execute_CMD(0x02,0,1);
lcd.clear();
lcd.setCursor(3,0);
lcd.print("MP3 PLAYER");
lcd.setCursor(14, 1);
lcd.write(3);
lcd.setCursor(0, 1);
lcd.print("Previous");
delay(1000);
lcd.clear();
lcd.setCursor(3,0);
lcd.print("MP3 PLAYER");
lcd.setCursor(6,1);
lcd.print("Play");
delay(500);
}
void volumeUp() {
if (currVolume < 30) {
currVolume++;
setVolume(currVolume);
lcd.clear();
lcd.setCursor(3,0);
lcd.print("MP3 PLAYER");
lcd.setCursor(14, 1);
lcd.write(4);
lcd.setCursor(0, 1);
lcd.print("Vol-UP");
delay(1000);
lcd.clear();
lcd.setCursor(3,0);
lcd.print("MP3 PLAYER");
lcd.setCursor(6,1);
lcd.print("Play");
delay(500);
}
}
void volumeDown() {
if (currVolume > 0){
currVolume--;
setVolume(currVolume);
lcd.clear();
lcd.setCursor(3,0);
lcd.print("MP3 PLAYER");
lcd.setCursor(14, 1);
lcd.write(5);
lcd.setCursor(0, 1);
lcd.print("Vol-DOWN");
delay(1000);
lcd.clear();
lcd.setCursor(3,0);
lcd.print("MP3 PLAYER");
lcd.setCursor(6,1);
lcd.print("Play");
delay(500);
}
}
void setVolume(int volume) {
execute_CMD(0x06, 0, volume); // Set the volume (0x00~0x30)
delay(2000);
}
void execute_CMD(byte CMD, byte Par1, byte Par2) {
// Excecute the command and parameters
// Calculate the checksum (2 bytes)
word checksum = -(VERSION + LENGTH + CMD + FEEDBACK + Par1 + Par2);
// Build the command line
byte Command_line[10] = { START_BYTE, VERSION, LENGTH, CMD, FEEDBACK,
Par1, Par2, highByte(checksum), lowByte(checksum), END_BYTE};
//Send the command line to the module
for (byte k = 0; k < 10; k++) {
dfpSerial.write(Command_line[k]);
}
}
⚠️Troubleshooting Common Issues
If your project isn't making any sound, check the following: Power Supply: The DFPlayer Mini requires a stable 5V. If you are powering the Arduino via a laptop USB, it might not provide enough current for both the Arduino and the speaker. Wiring: Double-check that the TX of the Arduino goes to the RX of the DFPlayer (through a resistor). SD Card Slot: Ensure the card is pushed in all the way. Some cheap modules have loose SD slots.


إرسال تعليق