Arnov Sharma
Published © MIT

WALKPi PCB Version

Audio Player Project Powered by Pico 2 and DF Mini Player

BeginnerFull instructions provided1 hour1,958
WALKPi PCB Version

Things used in this project

Hardware components

Raspberry Pi Pico 2
Raspberry Pi Pico 2
×1
SSD1306
×1
DFPlayer - A Mini MP3 Player
DFRobot DFPlayer - A Mini MP3 Player
×1
PCBWay Custom PCB
PCBWay Custom PCB
×1

Software apps and online services

Fusion
Autodesk Fusion
Arduino IDE
Arduino IDE

Story

Read more

Custom parts and enclosures

Fusion360File

Schematics

SCH

Code

code

C/C++
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <SoftwareSerial.h>
#include <DFRobotDFPlayerMini.h>
#include <Adafruit_NeoPixel.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define SSD1306_I2C_ADDRESS 0x3C
#define LED_PIN 0
#define NUM_LEDS 4

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT);
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);

// DFPlayer connections
SoftwareSerial mySerial(9, 8); // RX (Pico) to TX (DFPlayer), TX (Pico) to RX (DFPlayer)
DFRobotDFPlayerMini myDFPlayer;

// Button pins
const int buttonPinNext = 27; // Next song button
const int buttonPinPrev = 26; // Previous song button
const int buttonPinSelect = 12; // Select song button
const int buttonPinVolumeUp = 13; // Volume up button
const int buttonPinVolumeDown = 14; // Volume down button

String songNames[50]; // Placeholder for song names from the SD card
int totalSongs = 0;
int currentSongIndex = 0; // Start with the first song
int volume = 10; // Initial volume level (0-30)
unsigned long lastDebounceTime = 0; // For navigation button debounce
unsigned long debounceDelay = 250; // Debounce delay in milliseconds for navigation buttons
bool isPlaying = false;

// Function declarations
void listSongsFromSD();
void displayVolume();
void playVisualizer();
void displaySongInfo();
void setLEDsRed();
void setLEDsPurpleAndBlue();

void setup() {
    // Initialize Serial and the display
    Serial.begin(9600);
    mySerial.begin(9600);
    display.begin(SSD1306_SWITCHCAPVCC, SSD1306_I2C_ADDRESS);
    display.clearDisplay();

    // Initialize DFPlayer
    display.setTextSize(1);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.println("Init DFPlayer...");
    display.display();
    delay(1000); // Pause for observation

    if (!myDFPlayer.begin(mySerial)) {
        display.setCursor(0, 10);
        display.println("DFPlayer Init Failed!");
        display.display();
        while (true); // Halt further execution
    }
    myDFPlayer.volume(10);  // Set initial volume

    display.setCursor(0, 20);
    display.println("DFPlayer Initialized");
    display.display();
    delay(1000); // Pause for observation

    // Set up button pins
    pinMode(buttonPinNext, INPUT_PULLUP);
    pinMode(buttonPinPrev, INPUT_PULLUP);
    pinMode(buttonPinSelect, INPUT_PULLUP);
    pinMode(buttonPinVolumeUp, INPUT_PULLUP);
    pinMode(buttonPinVolumeDown, INPUT_PULLUP);

    // Initialize the LED strip
    strip.begin();
    strip.show(); // Initialize all pixels to 'off'
    setLEDsRed(); // Set initial state to red

    // Display welcome message
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.drawRect(0, 0, 128, 64, SSD1306_WHITE); // Frame box
    display.setCursor(18, 25);
    display.println("Welcome!");
    display.display();
    delay(2000);
    display.clearDisplay();
    display.display();

    // Read and display song names from SD card
    listSongsFromSD();
}

void loop() {
    unsigned long currentMillis = millis();

    // Display song menu
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.drawRect(0, 0, 128, 64, SSD1306_WHITE); // Frame box
    display.drawLine(0, 10, 128, 10, SSD1306_WHITE); // Line under the title
    display.setCursor(5, 0);
    display.print("Select Song:");

    // Display the list of songs with an arrow
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(5, 13 + currentSongIndex * 10);
    display.print(">");
    for (int i = 0; i < totalSongs; i++) {
        display.setCursor(15, 13 + i * 10);
        display.print(songNames[i]);
    }

    // Display current volume
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(5, 55);
    display.print("Volume: ");
    display.print(volume);
    display.display();

    // Check for button presses with debounce for navigation buttons
    if ((currentMillis - lastDebounceTime) > debounceDelay) {
        if (digitalRead(buttonPinNext) == LOW) {
            currentSongIndex = (currentSongIndex + 1) % totalSongs; // Loop back to start
            lastDebounceTime = currentMillis;
        }
        if (digitalRead(buttonPinPrev) == LOW) {
            currentSongIndex = (currentSongIndex - 1 + totalSongs) % totalSongs; // Loop to end
            lastDebounceTime = currentMillis;
        }
        if (digitalRead(buttonPinSelect) == LOW) {
            myDFPlayer.play(currentSongIndex + 1); // Play selected song
            isPlaying = true;
            lastDebounceTime = currentMillis;
            playVisualizer();
        }
    }

    // Check for volume button presses separately with a shorter debounce delay
    if (digitalRead(buttonPinVolumeUp) == LOW) {
        if ((currentMillis - lastDebounceTime) > 50) { // Shorter debounce delay for volume buttons
            if (volume < 30) { // Max volume is 30
                volume++;
                myDFPlayer.volume(volume); // Update volume on DFPlayer
                displayVolume();
            }
            lastDebounceTime = currentMillis;
        }
    }
    if (digitalRead(buttonPinVolumeDown) == LOW) {
        if ((currentMillis - lastDebounceTime) > 50) { // Shorter debounce delay for volume buttons
            if (volume > 0) { // Min volume is 0
                volume--;
                myDFPlayer.volume(volume); // Update volume on DFPlayer
                displayVolume();
            }
            lastDebounceTime = currentMillis;
        }
    }

    // Automatically play the next song if the current one ends
    if (myDFPlayer.available()) {
        if (myDFPlayer.readType() == DFPlayerPlayFinished) {
            currentSongIndex = (currentSongIndex + 1) % totalSongs;
            myDFPlayer.play(currentSongIndex + 1);
            displaySongInfo();
        }
    }

    // Handle LED colors based on whether a song is playing
    if (isPlaying) {
        setLEDsPurpleAndBlue();
    } else {
        setLEDsRed();
    }
}

// Function to list songs from SD card (Mock implementation)
void listSongsFromSD() {
    // Placeholder implementation to list songs
    songNames[0] = "Song 1";
    songNames[1] = "Song 2";
    songNames[2] = "Song 3";
    totalSongs = 3;
}

// Function to display volume change
void displayVolume() {
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.drawRect(0, 0, 128, 64, SSD1306_WHITE); // Frame box
    display.setCursor(35, 10); // Adjusted position
    display.print("Volume");
    display.setCursor(55, 35); // Position below the word
    display.print(volume);
    display.display();
    delay(1000); // Show volume for 1 second
}

// Simple visualizer function
void playVisualizer() {
    // Basic visualization while playing
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.drawRect(0, 0, 128, 64, SSD1306_WHITE); // Frame box
    display.setCursor(10, 20);
    display.print("Now Playing:");
    display.setTextSize(1);
    display.setCursor(10, 40);
    display.print(songNames[currentSongIndex]);
    display.display();
  
    // Visualizer loop
    for (int i = 0; i < 20; i++) {
        display.fillRect(i * 6, 50, 5, random(10, 30), SSD1306_WHITE);
        display.display();
        delay(50);
        display.fillRect(i * 6, 50, 5, random(10, 30), SSD1306_BLACK);
    }
}

// Function to display current song info
void displaySongInfo() {
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.drawRect(0, 0, 128, 64, SSD1306_WHITE); // Frame box
    display.setCursor(10, 20);
    display.print("Playing:");
    display.setTextSize(1);
    display.setCursor(10, 40);
    display.print(songNames[currentSongIndex]);
    display.display();
}

// Functions to control the LED strip
void setLEDsRed() {
    for (int i = 0; i < NUM_LEDS; i++) {
        strip.setPixelColor(i, strip.Color(255, 0, 0)); // Red color
    }
    strip.show();
}

void setLEDsPurpleAndBlue() {
    for (int i = 0; i < NUM_LEDS; i++) {
        strip.setPixelColor(i, strip.Color(128, 0, 128)); // Purple color
    }
    strip.show();
    delay(500);

    for (int i = 0; i < NUM_LEDS; i++) {
        strip.setPixelColor(i, strip.Color(0, 0, 255)); // Blue color
    }
    strip.show();
    delay(500);
}

Credits

Arnov Sharma
336 projects • 342 followers
Just your average MAKER

Comments