mp3-Play­er mit einem mp3-Shield

Lese­zeit: 9 Minu­ten

Seite als PDF

Die Hard­ware

Ein Shield ist ein Bau­teil, das auf einen Ardui­no UNO auf­ge­steckt wird. Das mp3-Shield VS1053 ver­fügt über u. a. über einen Deco­der für mp3 und einen Steck­platz für Mini-SD-Kar­ten. Es wer­den zwar alle digi­ta­len und ana­lo­gen Anschlüs­se her­aus­ge­führt, sie sind aber nur sehr ein­ge­schränkt nutzbar.

Das Shield ver­wen­det den ⇒SPI-Bus und auch noch ande­re digi­ta­le Pins, die für die Ansteue­rung des Shields benö­tigt wer­den. Daher sind nur die 🔗digi­ta­len Pins 5 und 10 unein­ge­schränkt nutzbar.

Ziel des Projekts

mp3-Datei­en sol­len von einer SD-Kar­te abge­spielt wer­den. Du benö­tigst eine Micro-SD-Kar­te, die mit FAT32 for­ma­tiert wur­de.
Kopie­re meh­re­re mp3-Datei­en auf die SD-Kar­te.
Du musst die Namen nach fol­gen­dem Mus­ter ändern und num­me­rie­ren:
track001.mp3, track002.mp3, track003.mp3 ...

Der Play­er soll mit einem Tas­ten­feld mit vier Tas­ten oder mit einer Fern­be­die­nung gesteu­ert werden.

Benö­tig­te Biblio­theken

Funk­tio­nen der Biblio­thek VS1053

Schlüs­sel­wortAkti­on
begin()Play­er starten
get­Sta­te()Sta­tus des Play­ers abfragen
0 = der Play­er wur­de nicht gestartet
1 = der Start des Play­ers war erfolgreich
playTrack(Nummer)
track001.mp3 → playTrack(1)
track002.mp3 → playTrack(2)
spielt den Track (Num­mer)
Track darf eine wav oder mp3-Datei sein
playMP3(Dateiname)
track001.mp3 → playMP3(track001.mp3)
track002.mp3 → playMP3(track002.mp3)
im Unter­schied zu playTrack()
dür­fen Datei­na­men ange­ge­ben werden
stop­Track()stoppt den gera­de lau­fen­den Track
pau­se­Mu­sic()pau­siert den gera­de lau­fen­den Track
resu­me­Mu­sic()setzt die Wie­der­ga­be nach der Pau­se fort
isPlay­ing()stellt fest, ob gera­de die Wie­der­ga­be läuft
0 = es wird nichts abgespielt
1 = es wird eine Track abgespielt
setVolume(links, rechts)Laut­stär­ke set­zen -> links, rechts
1, 1 sehr laut
je grö­ßer der Wert, des­to leiser 
setVolume(beide_Kanäle)setzt die Laut­stär­ke für links/rechts auf den glei­chen Wert
setBassAmplitude(Wert);Bäs­se ein­stel­len: erlaub­te Wer­te: 0 bis 15
setTrebleAmplitude(Wert)Höhen ein­stel­len: erlaub­te Wer­te: -8 bis 7
Send­Sin­gleM­I­DI­no­te()spielt ein „Beep“

Play­er im Seri­el­len Monitor

Bei­spiel: ein­fa­cher mp3-Play­er mit Steue­rung über den Seri­el­len Monitor

#include "vs1053_SdFat.h"

// Bezeichnung der SD-Karte
SdFat sd;

// Bezeichnung des mp3-Shields
vs1053 MP3player;

// Variable für das Lesen des Verzeichnisses
File Verzeichnis;
File Datei;

// Tracknummer/Anzahl der Tracks
int Track;
int TrackMax;

void setup() 
{
  Serial.begin(9600);
  
  // auf Seriellen Monitor warten
  while (!Serial)
  {
    delay(10);
  }

  // SD Karte starten
  sd.begin(SD_SEL, SPI_FULL_SPEED);

  // Anzahl der Tracks im Wurzelverzeichnis zählen
  // Char-Array für den Dateinamen
  char Dateiname[13];
  if (!sd.chdir("/")) sd.errorHalt("keine SD-Karte vorhanden");

  Verzeichnis.open("/");
  Serial.println("Dateiname    Größe");
  Serial.println("------------------------------");

  while (Datei.openNext(&Verzeichnis, O_READ)) 
  {
    Datei.getName(Dateiname, sizeof(Dateiname));

    // handelt es sich um eine Musikdatei (isFnMusic)
    if (isFnMusic(Dateiname)) 
    {
      Serial.print(Dateiname);

      // Dateigröße ermitteln, in MB umwandeln, Punkt durch Komma ersetzen
      float DateiGroesse = Datei.fileSize();
      String Groesse = String(DateiGroesse / 1000000);
      Groesse.replace(".", ",");
      Serial.println("\t" + Groesse + " MB");
      TrackMax++;
    }
    Datei.close();
  }

  Serial.println();
  Serial.println("Anzahl der Tracks: " + String(TrackMax));
  Serial.println("------------------------------");

  // Player starten
  MP3player.begin();

  // Höhen: erlaubte Werte: -8 bis 7
  MP3player.setTrebleAmplitude(4);

  // Bässe: erlaubte Werte 0 bis 15
  MP3player.setBassAmplitude(7);

  // Status des Players ermitteln
  if (MP3player.getState() == 1) Serial.println("Player erfolgreich gestartet");

  // Lautstärke setzen -> links, rechts -> 1, 1 sehr laut
  // je größer die Werte desto leiser
  MP3player.setVolume(50, 50);
  Serial.println();
  Serial.println("Welchen Track spielen? 1 bis " + String(TrackMax));
}

void loop() 
{
  while (Serial.available() > 0) 
  {
    String Eingabe = Serial.readStringUntil('\n');

    int Track = Eingabe.toInt();
    if (Track <= TrackMax) 
    {
      // kurzes "Beep" spielen
      MP3player.SendSingleMIDInote();
      MP3player.SendSingleMIDInote();

      // laufenden Track stoppen/aktuellen Track abspielen
      MP3player.stopTrack();
      Serial.println("Spiele Track " + String(Track));
      MP3player.playTrack(Track);
    } 
    else Serial.println("Der Track " + String(Track) + " existiert nicht!");
  }
}

Play­er mit Tastenfeld

Die Bele­gung der Tasten:

  • 1: ein Titel vorwärts
  • 2: ein Titel zurück
  • 3: Titel nach einer Pau­se wei­ter spielen
  • 4: Titel pausieren

Das Tas­ten­feld

Der Schalt­plan

Biblio­the­ken und Variable

Im Kopf des Pro­gramms wer­den die benö­tig­ten Biblio­the­ken ein­ge­bun­den und die Varia­blen definiert.

#include "vs1053_SdFat.h"
#include "Adafruit_Debounce.h"

// Bezeichnung der SD-Karte
SdFat sd;

// Bezeichnung des mp3-Shields
vs1053 MP3player;

// Variable für das Lesen des Verzeichnisses
File Verzeichnis;
File Datei;

// die Taster
int TASTER1 = A0; // zurück
int TASTER2 = A1; // weiter
int TASTER3 = A2; // weiter nach Pause
int TASTER4 = A3; // Pause

// "Prallverhinderer" für die Tasten starten
Adafruit_Debounce Taste_zurueck(TASTER1, LOW);
Adafruit_Debounce Taste_naester(TASTER2, LOW);
Adafruit_Debounce Taste_weiter(TASTER3, LOW);
Adafruit_Debounce Taste_Pause(TASTER4, LOW);

// Tracknummer/Anzahl der Tracks
int Track = 1;
int TrackMax = 0;

Der set­up-Teil

void setup()
{  
  // "Prellverhinderer" starten
  Taste_zurueck.begin();
  Taste_naester.begin();
  Taste_weiter.begin();
  Taste_Pause.begin();
  
  // Seriellen Monitor starten
  Serial.begin(9600);

  // auf Seriellen Monitor warten
  while (!Serial);
  
  Serial.println();

  // SD Karte starten
  sd.begin(SD_SEL, SPI_FULL_SPEED);

  // Anzahl der Tracks im Wurzelverzeichnis zählen
  // Char-Array für den Dateinamen
  char Dateiname[13];
  if (!sd.chdir("/")) sd.errorHalt("keine SD-Karte vorhanden");

  Verzeichnis.open("/");
  Serial.println("Dateiname    Größe");
  Serial.println("------------------------------");

  while (Datei.openNext(&Verzeichnis, O_READ))
  {
    Datei.getName(Dateiname, sizeof(Dateiname));

    // handelt es sich um eine Musikdatei (isFnMusic)
    if (isFnMusic(Dateiname) )
    {
      Serial.print(Dateiname);

      // Dateigröße ermitteln, in MB umwandeln, Punkt durch Komma ersetzen
      float DateiGroesse = Datei.fileSize();
      String Groesse = String(DateiGroesse / 1000000);
      Groesse.replace(".", ",");
      Serial.println("\t" + Groesse + " MB");
      TrackMax ++;
    }
    Datei.close();
  }

  Serial.println();
  Serial.println("Anzahl der Tracks: " + String(TrackMax));
  Serial.println("------------------------------");

  // Player starten
  MP3player.begin();

  // Höhen: erlaubte Werte: -8 bis 7
  MP3player.setTrebleAmplitude(4);

  // Bässe: erlaubte Werte 0 bis 15
  MP3player.setBassAmplitude(7);

  // Status des Players ermitteln
  if (MP3player.getState() == 1) Serial.println("Player erfolgreich gestartet");

  // Lautstärke setzen -> links, rechts -> 1, 1 sehr laut
  // je größer die Werte desto leiser
  MP3player.setVolume(50, 50);

  // 1. Track spielen
  Serial.println("Spiele Track " + String(Track));
  MP3player.playTrack(Track);
}

Der loop-Teil

void loop()
{
  // testen, ob eine Taste gedrückt wurde
  Taste_zurueck.update();
  Taste_naester.update();
  Taste_weiter.update();
  Taste_Pause.update();
  
  // vorherigen Track abspielen
  if (Taste_zurueck.justPressed())
  {
    vorherigerTitel();
  }

  // nächster Track
  if (Taste_naester.justPressed())
  {
    naechsterTitel();
  }

  // Pause
  if (Taste_weiter.justPressed())  
  {
    Pause();
  }

  // weiter abspielen
  if (Taste_Pause.justPressed())
  {
    Weiter();
  }

  // wenn der aktuelle Titel beendet ist
  if (!MP3player.isPlaying())
  {
    if (Track < TrackMax) Track ++;
    else Track = 1;
    Serial.println("Spiele Track " + String(Track));
    MP3player.playTrack(Track);
  }
}

Funk­tio­nen

im loop-Teil wer­den meh­re­re ⇒Funk­tio­nen aufgerufen:

void naechsterTitel()
{
  // kurzes Beep spielen
  MP3player.SendSingleMIDInote();
  MP3player.SendSingleMIDInote();

  // aktuellen Track stoppen
  MP3player.stopTrack();

  // wenn der letzte Track gespielt wurde
  // -> Neustart mit 1
  if (Track < TrackMax) Track ++;
  else Track = 1;
  Serial.println("Spiele Track " + String(Track));
  MP3player.playTrack(Track);
}

void vorherigerTitel()
{
  // kurzes "Beep" spielen
  MP3player.SendSingleMIDInote();
  MP3player.SendSingleMIDInote();

  // laufenden Track stoppen/aktuellen Track abspielen
  MP3player.stopTrack();
  if (Track > 1) Track --;
  Serial.println("Spiele Track " + String(Track));
  MP3player.playTrack(Track);
}

void Pause()
{
  MP3player.SendSingleMIDInote();
  MP3player.SendSingleMIDInote();

  // Track pausieren
  Serial.println("Pause Track " + String(Track));
  MP3player.pauseMusic();
}

void Weiter()
{ 
  MP3player.SendSingleMIDInote();
  MP3player.SendSingleMIDInote();

  // Wiedergabe fortsetzen
  Serial.println("Weiter Track " + String(Track));
  MP3player.resumeMusic();
}

Play­er mit Fernbedienung

Ver­schie­de­ne Infra­rot-Emp­fän­ger mit VS1838B-Modul

Die Ver­wen­dung einer ⇒Fern­be­die­nung (Keyes-Fern­be­die­nung) bie­tet mehr Mög­lich­kei­ten, den Play­er zu steuern:

  • Pfeil links: vor­he­ri­ger Titel
  • Pfeil rechts: nächs­ter Titel
  • Pfeil unten: Laut­stär­ke um 5 verringern
  • Pfeil oben: Laut­stär­ke um 5 erhöhen
  • OK: Zufalls­ge­nera­tor ausschalten

Test­pro­gramm Keyes-Fernbedienung

// benötigte Bibliothek einbinden
#include "IRremote.hpp"

// der Pin, an dem der Infrarot-Empfänger angeschlossen ist
int EmpfaengerPin = 5;

void setup() 
{
  // Seriellen Monitor starten
  Serial.begin(9600);
  
  // Infrarot-Empfänger starten
  IrReceiver.begin(EmpfaengerPin);
}

void loop() 
{
  // decode() -> Daten lesen
  if (IrReceiver.decode()) 
  {
    // kurzes delay, damit nur ein Tastendruck gelesen wird
    
    delay(200);

    // resume -> nächsten Wert lesen
    IrReceiver.resume();

    /*
      der Empfänger empfängt zwischendurch Signale, 
      die nicht ausgewertet werden können
      es sollen dehalb nur die korrekt erkannten Tasten ausgewertet werden
      die Dezimalwerte der korrekten erkannten Tasten liegen zwischen > 0 und < 95
      es wird abgefragt, ob das empfangene Kommando decodedIRData.command
      zwischen 0 und (&&) 95 liegt
    */
    if (IrReceiver.decodedIRData.command > 0 && IrReceiver.decodedIRData.command < 95) 
    {
      Serial.print("Dezimalwert: ");

      // IrReceiver.decodedIRData.command = Wert der gedrückten Taste
      Serial.print(IrReceiver.decodedIRData.command);
      Serial.print(" -> ");

      // Werte abfragen und anzeigen
      if (IrReceiver.decodedIRData.command == 22) Serial.println("Taste 1");
      if (IrReceiver.decodedIRData.command == 25) Serial.println("Taste 2");
      if (IrReceiver.decodedIRData.command == 13) Serial.println("Taste 3");
      if (IrReceiver.decodedIRData.command == 12) Serial.println("Taste 4");
      if (IrReceiver.decodedIRData.command == 24) Serial.println("Taste 5");
      if (IrReceiver.decodedIRData.command == 94) Serial.println("Taste 6");
      if (IrReceiver.decodedIRData.command == 8) Serial.println("Taste 7");
      if (IrReceiver.decodedIRData.command == 28) Serial.println("Taste 8");
      if (IrReceiver.decodedIRData.command == 90) Serial.println("Taste 9");
      if (IrReceiver.decodedIRData.command == 82) Serial.println("Taste 0");
      if (IrReceiver.decodedIRData.command == 66) Serial.println("Taste *");
      if (IrReceiver.decodedIRData.command == 74) Serial.println("Taste #");
      if (IrReceiver.decodedIRData.command == 68) Serial.println("Pfeil links");
      if (IrReceiver.decodedIRData.command == 67) Serial.println("Pfeil rechts");
      if (IrReceiver.decodedIRData.command == 70) Serial.println("Pfeil oben");
      if (IrReceiver.decodedIRData.command == 21) Serial.println("Pfeil unten");
      if (IrReceiver.decodedIRData.command == 64) Serial.println("OK");
    }
  }
}

Test­pro­gramm belie­bi­ge Fernbedienung

#include "IRremote.hpp"

int EmpfaengerPin = 5;

void setup() 
{
  Serial.begin(9600);

  // Empfänger starten
  IrReceiver.begin(EmpfaengerPin);
}

void loop() 
{
  // Daten lesen
  if (IrReceiver.decode()) 
  {
    delay(200);
        
    // resume -> nächsten Wert lesen
    IrReceiver.resume();
    if (IrReceiver.decodedIRData.command > 0) 
    {
      /*
        printIRResultMinimal zeigt die verwendete Taste
        P = Protokoll
        C = Kommando in Hex
      */

      Serial.print(F("P = Protokoll C = Taste hexadezimal: "));
      IrReceiver.printIRResultMinimal(&Serial);
      Serial.print(F(" Dezimal: "));
      Serial.println(IrReceiver.decodedIRData.command);
    }
  }
}

Der Zufalls­ge­nera­tor ist lei­der nur ein "Pseudo"-Zufallsgenerator. Nach jedem Neu­start des Pro­gramms star­tet der Play­er immer mit dem glei­chen Titel. Er prüft auch nicht, ob der nach­fol­gen­de Titel nicht erst kur­zem abge­spielt wur­de. Ich den­ke aber, dass die zufäl­li­ge Rei­hen­fol­ge umso brauch­ba­rer wird, je mehr Titel auf der SD-Kar­te vor­han­den sind.

Mit der Tas­te "OK" auf der Fern­be­die­nung wird der Zufalls­ge­nera­tor ein- oder ausgeschaltet.

Der Schalt­plan

Das Pro­gramm

#include "vs1053_SdFat.h"
#include "IRremote.hpp"

// der Pin, an dem der Infrarot-Empfänger angeschlossen ist
int EmpfaengerPin = 4;
// Bezeichnung der SD-Karte
SdFat sd;

// Bezeichnung des mp3-Shields
vs1053 MP3player;

// Variable für das Lesen des Verzeichnisses
File Verzeichnis;
File Datei;

// Tracknummer/Anzahl der Tracks
int Track = 1;
int TrackMax = 0;

int LautstaekeLinks = 50;
int LautstaerkeRechts = 50;

bool zufaelligeWiedergabe = true;

void setup()
{  
  // Infrarot-Empfänger starten
  IrReceiver.begin(EmpfaengerPin);
  
  // Seriellen Monitor starten
  Serial.begin(9600);

  // auf Seriellen Monitor warten
  while (!Serial);
  
  Serial.println();

  // SD Karte starten
  sd.begin(SD_SEL, SPI_FULL_SPEED);

  // Anzahl der Tracks im Wurzelverzeichnis zählen
  // Char-Array für den Dateinamen
  char Dateiname[13];
  if (!sd.chdir("/")) sd.errorHalt("keine SD-Karte vorhanden");

  Verzeichnis.open("/");
  Serial.println("Dateiname    Größe");
  Serial.println("------------------------------");

  while (Datei.openNext(&Verzeichnis, O_READ))
  {
    Datei.getName(Dateiname, sizeof(Dateiname));

    // handelt es sich um eine Musikdatei (isFnMusic)
    if (isFnMusic(Dateiname) )
    {
      Serial.print(Dateiname);

      // Dateigröße ermitteln, in MB umwandeln, Punkt durch Komma ersetzen
      float DateiGroesse = Datei.fileSize();
      String Groesse = String(DateiGroesse / 1000000);
      Groesse.replace(".", ",");
      Serial.println("\t" + Groesse + " MB");
      TrackMax ++;
    }
    Datei.close();
  }

  Serial.println();
  Serial.println("Anzahl der Tracks: " + String(TrackMax));
  Serial.println("------------------------------");

  // Player starten
  MP3player.begin();

  // Höhen: erlaubte Werte: -8 bis 7
  MP3player.setTrebleAmplitude(4);

  // Bässe: erlaubte Werte 0 bis 15
  MP3player.setBassAmplitude(7);

  // Status des Players ermitteln
  if (MP3player.getState() == 1) Serial.println("Player erfolgreich gestartet");

  // Lautstärke setzen -> links, rechts -> 1, 1 sehr laut
  // je größer die Werte desto leiser
  MP3player.setVolume(LautstaekeLinks, LautstaerkeRechts);

  randomSeed(millis());
  if (zufaelligeWiedergabe) Track = random(1, TrackMax);
  else Track = 1;

  // 1. Track spielen
  Serial.println("Spiele Track " + String(Track));
  MP3player.playTrack(Track);

}

void loop()
{
  if (IrReceiver.decode()) 
  {
    // kurzes delay, damit nur ein Tastendruck gelesen wird
    
    delay(200);

    // resume -> nächsten Wert lesen
    IrReceiver.resume();

    /*
      der Empfänger empfängt zwischendurch Signale, 
      die nicht ausgewertet werden können
      es sollen dehalb nur die korrekt erkannten Tasten ausgewertet werden
      die Dezimalwerte der korrekten erkannten Tasten liegen zwischen > 0 und < 95
      es wird abgefragt, ob das empfangene Kommando decodedIRData.command
      zwischen 0 und (&&) 95 liegt
    */
    if (IrReceiver.decodedIRData.command > 0 && IrReceiver.decodedIRData.command < 95) 
    {
      // IrReceiver.decodedIRData.command = Wert der gedrückten Taste
      // Werte abfragen und anzeigen
      if (IrReceiver.decodedIRData.command == 64) ZufallSchalten();
      if (IrReceiver.decodedIRData.command == 66) Weiter();
      if (IrReceiver.decodedIRData.command == 74) Pause();
      if (IrReceiver.decodedIRData.command == 68) vorherigerTitel();
      if (IrReceiver.decodedIRData.command == 67) naechsterTitel();
      if (IrReceiver.decodedIRData.command == 70) Lauter();
      if (IrReceiver.decodedIRData.command == 21) Leiser();
    }
  }

  // wenn der aktuelle Titel beendet ist
  if (!MP3player.isPlaying())
  {
    if (zufaelligeWiedergabe)
    {
      randomSeed(millis());
      Track = random(1, TrackMax);
    }
    else
    {
      if (Track < TrackMax) Track ++;
      else Track = 1;
    }
    Serial.println("Spiele Track " + String(Track));
    MP3player.playTrack(Track);
  }
}

void naechsterTitel()
{
  // kurzes Beep spielen
  MP3player.SendSingleMIDInote();
  MP3player.SendSingleMIDInote();

  // aktuellen Track stoppen
  MP3player.stopTrack();

  if (zufaelligeWiedergabe) 
  {
    randomSeed(millis());
    Track = random(1, TrackMax);
  }
  else
  {
    // wenn der letzte Track gespielt wurde
    // -> Neustart mit 1
    if (Track < TrackMax) Track ++;
    else Track = 1;
    // Serial.println("Spiele Track " + String(Track));
  }
  Serial.println("Spiele Track " + String(Track));
  MP3player.playTrack(Track);
}

void vorherigerTitel()
{
  // kurzes "Beep" spielen
  MP3player.SendSingleMIDInote();
  MP3player.SendSingleMIDInote();

  MP3player.stopTrack();

  if (zufaelligeWiedergabe) 
  {
    randomSeed(millis());
    Track = random(1, TrackMax);
  }
  else
  {
    // laufenden Track stoppen/aktuellen Track abspielen
    if (Track > 1) Track --;
    else Track = TrackMax;
  }

  Serial.println("Spiele Track " + String(Track));
  MP3player.playTrack(Track);
}

void Pause()
{
  MP3player.SendSingleMIDInote();
  MP3player.SendSingleMIDInote();

  // Track pausieren
  Serial.println("Pause Track " + String(Track));
  MP3player.pauseMusic();
}

void Weiter()
{ 
  MP3player.SendSingleMIDInote();
  MP3player.SendSingleMIDInote();

  // Wiedergabe fortsetzen
  Serial.println("Weiter Track " + String(Track));
  MP3player.resumeMusic();
}

void Lauter()
{
  Serial.println(String(LautstaekeLinks) + "," + String(LautstaerkeRechts));
  if (LautstaekeLinks >= 0) LautstaekeLinks -= 5;
  if (LautstaerkeRechts >=0 ) LautstaerkeRechts -= 5;
  MP3player.setVolume(LautstaekeLinks, LautstaerkeRechts);
}

void Leiser()
{
  Serial.println(String(LautstaekeLinks) + "," + String(LautstaerkeRechts));
  if (LautstaekeLinks < 100) LautstaekeLinks += 5;
  if (LautstaerkeRechts < 100) LautstaerkeRechts += 5;
  MP3player.setVolume(LautstaekeLinks, LautstaerkeRechts);
}

void ZufallSchalten()
{
  zufaelligeWiedergabe = !zufaelligeWiedergabe;
  if (zufaelligeWiedergabe) Serial.println("Zufall ein");
  else Serial.println("Zufall aus");
}

Quel­len


Startseite
Aufgaben A-Z
Suchen
Downloads
Fehlermeldungen
Seite als PDF

Ver­wand­te Anleitungen:


Letzte Aktualisierung: Okt. 6, 2025 @ 12:21