8 bit MP3 Player
8 bit MP3 Player
What I wanted to learn, and why it interested me: I want to learn about MP3 player and thus play any sound effect that I want for further development.
Final outcome: A MP3 Player that plays a series of songs from the SD card and enables pause, next, previous, and volumn functions.
Images of final creative/exploratory output
A video of the whole system working.
A video of all the songs in the SD card played.
Process images from development towards creative/exploratory output
The volumn potentiometer and the three buttons.
The colorful wires that I got for the LCD and the DF player because they just have so many pins to connect with.
Process and reflection:
This project might look simple at first glance, but the actual coding process was unexpectedly challenging. Building the whole system meant combining several different pieces of knowledge, and merging multiple codes into one functioning program. Honestly, the chance of everything running perfectly on the first try was almost zero. I went through countless rounds of debugging and revision, and along the way discovered problems I didn’t even know could exist.
Sometimes I have to realize there is something completely out of knowledge and I have to look up for how to solve it. For instance, instead of reading the potentiometer value directly, I should write a linear increase logic to adjust the volumn. In the end, I’m really happy that a project that appears so simple on the surface turned out to teach me so much about coding, problem-solving, and patience.
Technical details
This is the electrical schematic drawing.
#include "Arduino.h"
#include "DFRobotDFPlayerMini.h"
#include <SoftwareSerial.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
SoftwareSerial softSerial(10, 11);
DFRobotDFPlayerMini myDFPlayer;
LiquidCrystal_I2C lcd(0x27, 16, 2);
const int BUTTON_PLAY_PAUSE = 2;
const int BUTTON_PREV = 3;
const int BUTTON_NEXT = 4;
const int POT_VOLUME = A0;
bool isPlaying = true;
int currentTrack = 1;
int lastTrack = 0;
int lastVolume = -1;
int lastButtonState_PlayPause = HIGH;
int lastButtonState_Prev = HIGH;
int lastButtonState_Next = HIGH;
const unsigned long debounceDelay = 50;
struct Song {
char name[17];
char artist[17];
};
Song playlist[] = {
{"Fun 8Bit Game", "DJARTMUSIC"}, // 0001.mp3
{"Console Dreams", "DJARTMUSIC"}, // 0002.mp3
{"Return 8Bit", "DJARTMUSIC"}, // 0003.mp3
{"Retro Game", "NIKneT_Art"} // 0004.mp3
};
const int TOTAL_TRACKS = 4;
void setup() {
softSerial.begin(9600);
Serial.begin(115200);
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("8-Bit Player");
lcd.setCursor(0, 1);
lcd.print("Starting...");
pinMode(BUTTON_PLAY_PAUSE, INPUT_PULLUP);
pinMode(BUTTON_PREV, INPUT_PULLUP);
pinMode(BUTTON_NEXT, INPUT_PULLUP);
Serial.println(F("Initializing DFPlayer..."));
if (!myDFPlayer.begin(softSerial, true, true)) {
Serial.println(F("Unable to begin:"));
Serial.println(F("1.Please recheck the connection!"));
Serial.println(F("2.Please insert the SD card!"));
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("DFPlayer Error!");
lcd.setCursor(0, 1);
lcd.print("Check SD Card");
while(true) { delay(0); }
}
Serial.println(F("DFPlayer Mini online."));
// default
myDFPlayer.volume(15);
delay(100);
myDFPlayer.play(1);
currentTrack = 1;
delay(500);
updateLCD();
}
void loop() {
handleButtons();
handleVolume();
if (currentTrack != lastTrack) {
updateLCD();
lastTrack = currentTrack;
}
if (myDFPlayer.available()) {
handleDFPlayerMessage();
}
}
void handleButtons() {
int reading_PlayPause = digitalRead(BUTTON_PLAY_PAUSE);
int reading_Prev = digitalRead(BUTTON_PREV);
int reading_Next = digitalRead(BUTTON_NEXT);
// pause
if (reading_PlayPause == LOW && lastButtonState_PlayPause == HIGH) {
delay(debounceDelay);
if (digitalRead(BUTTON_PLAY_PAUSE) == LOW) {
if (isPlaying) {
myDFPlayer.pause();
isPlaying = false;
lcd.setCursor(0, 0);
lcd.print("|| PAUSED ");
Serial.println(F("Paused"));
} else {
myDFPlayer.start();
isPlaying = true;
updateLCD();
Serial.println(F("Playing"));
}
}
}
lastButtonState_PlayPause = reading_PlayPause;
// prev song
if (reading_Prev == LOW && lastButtonState_Prev == HIGH) {
delay(debounceDelay);
if (digitalRead(BUTTON_PREV) == LOW) {
myDFPlayer.previous();
currentTrack--;
if (currentTrack < 1) currentTrack = TOTAL_TRACKS;
Serial.print(F("Previous track: "));
Serial.println(currentTrack);
}
}
lastButtonState_Prev = reading_Prev;
// next song
if (reading_Next == LOW && lastButtonState_Next == HIGH) {
delay(debounceDelay);
if (digitalRead(BUTTON_NEXT) == LOW) {
myDFPlayer.next();
currentTrack++;
if (currentTrack > TOTAL_TRACKS) currentTrack = 1;
Serial.print(F("Next track: "));
Serial.println(currentTrack);
}
}
lastButtonState_Next = reading_Next;
}
void handleVolume() {
int potValue = analogRead(POT_VOLUME);
int volume = map(potValue, 0, 1023, 0, 30);
// volumn code when greater than 1
if (abs(volume - lastVolume) > 1) {
myDFPlayer.volume(volume);
lastVolume = volume;
// show volumn
lcd.setCursor(0, 1);
lcd.print("Volume: ");
if (volume < 10) lcd.print(" ");
lcd.print(volume);
lcd.print(" ");
Serial.print(F("Volume: "));
Serial.println(volume);
delay(500);
// return to normal
if (isPlaying) {
updateLCD();
}
}
}
void updateLCD() {
lcd.clear();
// track x/x
lcd.setCursor(0, 0);
lcd.print("Track ");
lcd.print(currentTrack);
lcd.print("/");
lcd.print(TOTAL_TRACKS);
lcd.print(" ");
lcd.print((char)0x7E); //the play sign, thanks claude for the character code
// song name
lcd.setCursor(0, 1);
lcd.print(playlist[currentTrack - 1].name);
// clean extra token
int nameLen = strlen(playlist[currentTrack - 1].name);
for (int i = nameLen; i < 16; i++) {
lcd.print(" ");
}
Serial.print(F("Now playing: "));
Serial.print(playlist[currentTrack - 1].name);
Serial.print(F(" - "));
Serial.println(playlist[currentTrack - 1].artist);
}
void handleDFPlayerMessage() {
uint8_t type = myDFPlayer.readType();
int value = myDFPlayer.read();
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!"));
lcd.clear();
lcd.print("SD Card Removed!");
break;
case DFPlayerCardOnline:
Serial.println(F("Card Online!"));
break;
case DFPlayerPlayFinished:
Serial.print(F("Track "));
Serial.print(value);
Serial.println(F(" finished"));
// auto play next
currentTrack++;
if (currentTrack > TOTAL_TRACKS) {
currentTrack = 1; // loop
}
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"));
lcd.clear();
lcd.print("File Not Found!");
break;
case Advertise:
Serial.println(F("In Advertise"));
break;
default:
break;
}
break;
default:
break;
}
}
///https://wiki.dfrobot.com/DFPlayer_Mini_SKU_DFR0299#Copy%20your%20mp3%20into%20you%20micro%20SD%20card
///claude 10/05/2025 debugged
///history assignments, projects and official website