RailFX Arduino Sound Modul

RailFX: Sound-Modul mit Arduino

Dieses Sound-Modul mit Arduino des RailFX-Systems spielt MP3 und WAV Dateien von einer SD-Karte ab. Über die Zeitsteuerung des Control-Modul lassen sich unterschiedliche Szenarien realisieren.

Bauteile

Schaltung

RailFX Arduino Sound Modul MP3 Ton Lautsprecher

Das RailFX Sound-Modul basiert auf dem Arduino-Nano. An seinen Pins 2 und 3 ist es mit dem DFPlayer Mini verbunden. Dabei handelt es sich um einen MP3-Player, der Dateien von einer SD-Karte abspielt. Er wird über die Arduino-Pins GND und 5V mit Storm versorgt.

Am DFPlayer ist ebenfalls ein Lautsprecher angeschlossen. Es bietet sich an, die Spannung mit einem Elektrolytkondensator (z.B. 100uF, 16V) zu stabilisieren.


Sieh dir jetzt meinen neuen Arduino-Videokurs an: Jetzt ansehen!


Achtung: Am Pin A4 wird das Control-Signal des RailFX Control-Moduls angelegt. Es steuert die Tageszeit und ist zwingend erforderlich.

Vorbereitung

Für die Tonausgabe wird der DFPlayer Mini verwendet. Er spielt MP3- und WAV-Dateien von einer SD-Karte ab. Für die Nutzung muss die DFPlayer Mini Bibliothek eingebunden werden. Klicke dafür im Arduino-Menü auf Sketch>Bibliotheken einbinden>Bibliotheken verwalten und gib im Suchfeld »dfplayer mini« ein. Installiere die Bibliothek DFPlayer Mini MP3 by Makuna in der aktuellen Version.

Die SD-Karte muss im FAT16 oder FAT32-Dateisystem formatiert sein. Darüber hinaus müssen sich die Dateien im Ordner »01« befinden und die Dateinamen müssen aufeinander folgend 001.mp3, 002.mp3, 003.mp3 usw. benannt sein. Wie erwähnt, dürfen auch WAV-Dateien verwendet werden: 001.mp3, 002.wav, 003.mp3 …

Ein paar Beispieldateien kann man hier herunterladen. (Ordner in 01 umbenennen und in das Hauptverzeichnis der SD-Karte.)

Im Array spieleSoundInStunde kann man dann entscheiden, wann eine bestimmte Sound-Datei abgespielt werden soll. Damit kann man komplexe akustische Szenarien umsetzen, z.B. Vogelzwitschern am Morgen, Berufsverkehr am Nachmittag oder eine grölende Gruppe betrunkener Touristen (klar, können auch Fußballfans oder ein Junggesellinnenabschied sein) in der Nacht.

Einstellungen im Code

int lautstaerke = 10;                      // Lautstärke des DFPlayers (0 – 30);
int mp3WahrscheinlichkeitJeStunde[24] = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}; // Wahrscheinlichkeit, mit der MP3s abgespielt werden, 10 oft, 100 selten
const int mp3Anzahl = 10; // Menge der MP3-Dateien auf der SD-Karte
int mp3Dauer[mp3Anzahl] = {16, 16, 15, 17, 17, 18, 19, 18, 19, 9}; // Dauer der MP3-Dateien in Sekunden
int spieleSoundInStunde[24][mp3Anzahl] = {
  {1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // Welche MP3s werden um  0 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // Welche MP3s werden um  1 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // Welche MP3s werden um  2 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // Welche MP3s werden um  3 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // Welche MP3s werden um  4 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // Welche MP3s werden um  5 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 1, 1, 0, 0, 0, 0, 0}, // Welche MP3s werden um  6 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 1, 1, 0, 0, 0, 0, 0}, // Welche MP3s werden um  7 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 1, 1, 0, 0, 0, 0, 0}, // Welche MP3s werden um  8 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 1, 1, 0, 0, 0, 0, 0}, // Welche MP3s werden um  9 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 1, 1, 0, 0, 0, 0, 0}, // Welche MP3s werden um 10 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 1, 1, 0, 0, 0, 0, 0}, // Welche MP3s werden um 11 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 1, 1, 1, 0, 0}, // Welche MP3s werden um 12 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 1, 1, 1, 0, 0}, // Welche MP3s werden um 13 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 1, 1, 1, 0, 0}, // Welche MP3s werden um 14 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 1, 1, 1, 0, 0}, // Welche MP3s werden um 15 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 1, 1, 1, 0, 0}, // Welche MP3s werden um 16 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 1, 1, 1, 0, 0}, // Welche MP3s werden um 17 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, // Welche MP3s werden um 18 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, // Welche MP3s werden um 19 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, // Welche MP3s werden um 20 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, // Welche MP3s werden um 21 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, // Welche MP3s werden um 22 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1}  // Welche MP3s werden um 23 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
};

Im Code kann man die Lautstärke des DFPlayers über die Variable lautstaerke einstellen. Darüber hinaus sollte man die Anzahl der MP3s in der Variable mp3Anzahl angeben.

Über die Variable mp3WahrscheinlichkeitJeStunde kann man die Wahrscheinlichkeit bestimmen, mit der ein Sound abgespielt wird. Je kleiner der Wert, desto öfter wird ein Sound abgespielt.

Das Array spieleSoundInStunde[24][mp3Anzahl] entscheidet darüber, zu welcher Stunde eine Sound-Datei (per Zufall) abgespielt wird. Dabei bedeutet 0, dass sie nicht und 1, dass sie abgespielt wird. Die Länge der jeweiligen Zeilen muss mit der Anzahl der Sound-Dateien übereinstimmen.

Code: Sound-Modul mit Arduino

/*
     Rail-FX Sound-Modul
     StartHardware.org

     Permalink: https://starthardware.org/railfx-sound-modul-mit-arduino/
*/

#include "SoftwareSerial.h"              // Wird für den DFPlayer benötigt
#include "DFRobotDFPlayerMini.h"         // Wird für den DFPlayer benötigt

/* ***** ***** Einstellungen ***** ***** ***** *****  ***** ***** ***** *****  ***** ***** ***** ***** */

int lautstaerke = 10;                      // Lautstärke des DFPlayers (0 – 30);
int mp3WahrscheinlichkeitJeStunde[24] = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}; // Wahrscheinlichkeit, mit der MP3s abgespielt werden, 10 oft, 100 selten

const int mp3Anzahl = 10; // Menge der MP3 Dateien auf der SD-Karte
int mp3Dauer[mp3Anzahl] = {14, 10, 12, 20, 54, 30, 39, 45, 22, 3}; // Dauer der MP3 Dateien in Sekunden

int spieleSoundInStunde[24][mp3Anzahl] = {
  {1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // Welche MP3s werden um  0 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // Welche MP3s werden um  1 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // Welche MP3s werden um  2 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // Welche MP3s werden um  3 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // Welche MP3s werden um  4 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // Welche MP3s werden um  5 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen

  {0, 0, 0, 1, 1, 0, 0, 0, 0, 0}, // Welche MP3s werden um  6 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 1, 1, 0, 0, 0, 0, 0}, // Welche MP3s werden um  7 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 1, 1, 0, 0, 0, 0, 0}, // Welche MP3s werden um  8 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 1, 1, 0, 0, 0, 0, 0}, // Welche MP3s werden um  9 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 1, 1, 0, 0, 0, 0, 0}, // Welche MP3s werden um 10 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 1, 1, 0, 0, 0, 0, 0}, // Welche MP3s werden um 11 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen

  {0, 0, 0, 0, 0, 1, 1, 1, 0, 0}, // Welche MP3s werden um 12 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 1, 1, 1, 0, 0}, // Welche MP3s werden um 13 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 1, 1, 1, 0, 0}, // Welche MP3s werden um 14 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 1, 1, 1, 0, 0}, // Welche MP3s werden um 15 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 1, 1, 1, 0, 0}, // Welche MP3s werden um 16 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 1, 1, 1, 0, 0}, // Welche MP3s werden um 17 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen

  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, // Welche MP3s werden um 18 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, // Welche MP3s werden um 19 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, // Welche MP3s werden um 20 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, // Welche MP3s werden um 21 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, // Welche MP3s werden um 22 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
  {0, 0, 0, 0, 0, 0, 0, 0, 1, 1}  // Welche MP3s werden um 23 Uhr abgespielt? 1 = abspielen, 0 = nicht abspielen
};

int mp3proStunde[24][mp3Anzahl];
int mp3AnzahlproStunde[24];

int arrayIndex = 0;                         // Hilfsvariable



/* ***** ***** Ab hier beginnt der Programmcode, der nicht angepasst werden muss ***** ***** ***** ***** */

/* Speicher-Variablen */
long soundTimer = 0;                     // Timer des DFPlayers
long soundTimeout = 0;                   // Speichert die Abspieldauer des aktuellen MP3
int soundState = 0;                      // Status des DFPlayers

int soundRandom;
int theSound;
int soundPlaying = false;

/* Variablen vom Controlmodul um die Uhrzeit festzustellen*/
boolean receive = false;
boolean receiveStarted = false;
int receiveTimeout = 10;
long receiveTimer = 0;
int receivedTime = 0;
int receivePulse = 0;
int lastReceivePulse = 0;
int receivePin = 18;
int myTime = 1;

/* Objekte anlegen */
SoftwareSerial mySoftwareSerial(3, 2);   // RX, TX für den DFPlayer
DFRobotDFPlayerMini myDFPlayer;          // DFPlayer Objekt

#define PAYLOAD_SIZE 2                   // nötig für die Kommunikation zum Master
int uhrzeit = 0;                         // speichert die Uhrzeit vom Master-Modul (0 und 255)
byte nodePayload[PAYLOAD_SIZE];          // speichert die Daten vom Master-Modul zwischen

void setup() {
  Serial.begin(115200);                  // started die serielle Kommunikation
  pinMode(receivePin, INPUT);            // Empfangspin vom Control-Modul
  mySoftwareSerial.begin(9600);          // started die serielle Kommunikation für den DFPlayer
  //randomSeed(19);

  /* DFPlayer Setup */
  Serial.println(F("Initializing DFPlayer ... "));
  if (!myDFPlayer.begin(mySoftwareSerial, false)) {  // nutze softwareSerial um mit dem DFPlayer zu sprechen
    Serial.println(F("Fehler: Prüfe Verbindung zum DFPlayer und SD-Karte"));
    while (true);

  }

  Serial.println(F("DFPlayer Mini online."));
  myDFPlayer.setTimeOut(1000);           // Set serial communictaion time out 500ms
  myDFPlayer.volume(lautstaerke);        // Einstellen der Lautstärke
  delay(1000);                           // Nach der Lautstärkeeinstellung sollte man etwas warten

  for (int i = 0; i < 24; i++) {              // zähle 24 Stunden durch
    arrayIndex = 0;                           // Hilfsvariable resetten
    for (int j = 0; j < mp3Anzahl; j++) {     // zähle alle MP3s durch
      if (spieleSoundInStunde[i][j] == 1) {   // Wenn mp3 zu der Stunde gespielt werden soll
        mp3proStunde[i][arrayIndex] = j;      // merke dir die mp3-Nummer
        arrayIndex++;
      }
    }
    mp3AnzahlproStunde[i] = arrayIndex;   // berechnet Anzahl der MP3s pro Stunde
  }
}

void loop() {
  receiveFunction();                      // Führe Anweisungen für Empfang aus
  if (receiveStarted == false) {          // Falls gerade keine Daten empfangen werden:
    soundAn();                            // Spiele Sound ab
  }
}

void soundAn() {
  switch (soundState) {
    case 0:
      if (mp3AnzahlproStunde[myTime] > 0) {
        soundRandom = random(mp3WahrscheinlichkeitJeStunde[myTime]);
        if (soundRandom < 1) {
          soundState = 1;

          theSound = random(mp3Anzahl) + 1;
          while (spieleSoundInStunde[myTime][theSound - 1] == 0) {
            theSound = random(mp3Anzahl) + 1;
          }

          soundTimer = millis();
          soundTimeout = mp3Dauer[theSound - 1] * 1000;
          Serial.print("Modellbauzeit: "); Serial.print(myTime); Serial.print("\t theSound: "); Serial.print(theSound); Serial.print("\t soundTimeout: "); Serial.print(millis()); Serial.print("\t soundTimeout: "); Serial.println(soundTimeout);
          myDFPlayer.playFolder(1, theSound); // play specific mp3 in SD:/01/001.mp3; Folder Name(01); File Name(1~255)
          soundPlaying = true;

        } else {
          soundTimer = millis();
          soundTimeout = 500;
          soundState = 1;
        }
      }
      break;
    case 1:
      if (soundTimer + soundTimeout < millis()) {
        myDFPlayer.pause();
        soundPlaying = false;
        soundState = 0;
      }
      break;
  }
}

/* Funktionen für die Fehlerausgabe des DFPlayers und für Datenempfang vom Control-Modul*/

void printDetail(uint8_t type, int value) {     // DF Player Fehlermeldungen
  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!"));
      break;
    case DFPlayerCardOnline:
      Serial.println(F("Card Online!"));
      break;
    case DFPlayerUSBInserted:
      Serial.println("USB Inserted!");
      break;
    case DFPlayerUSBRemoved:
      Serial.println("USB Removed!");
      break;
    case DFPlayerPlayFinished:
      Serial.print(F("Number:"));
      Serial.print(value);
      Serial.println(F(" Play Finished!"));
      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"));
          break;
        case Advertise:
          Serial.println(F("In Advertise"));
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }
}

/* ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** */

void receiveFunction() {                      // Empfängt die Uhrzeit vom Control-Modul
  receivePulse = digitalRead(receivePin);     // Lies den Empfangspin aus

  if ((receiveTimer + receiveTimeout < millis()) && (receiveStarted == true)) {
    // Bei Timeout und aktivem Empfang
    receiveStarted = false;                   // beende aktiven Empfang
    myTime = receivedTime - 1;                // speichere die empfangene Zeit
    receivedTime = 0;                         // setze die Hilfsvariable zum Zeitempfang zurück
    Serial.print("Modelbauzeit\t"); Serial.println(myTime);                  // serielle Ausgabe
  }
  // falls ein Puls am Empfangspin erfasst wird, der vorher nicht da war
  if ((receivePulse == 0) && (lastReceivePulse == 1)) {
    receiveTimer = millis();                  // starte Timer neu
    if (receiveStarted == false) receiveStarted = true;  // starte aktiven Empfang, wenn noch nicht geschehen
    receivedTime++;                           // es gab einen Puls, also erhöhe die Hilfsvariable zum Zeitempfang
  }
  lastReceivePulse = receivePulse;            // aktuellen Zustand am Pin für nächsten Durchlauf merken
}

Wenn dir das Projekt gefallen hat und du von weiteren interessanten Projekten inspiriert werden willst, sieh dir doch mal mein neues E-Book »Arduino Projekte Volume 1« an!

  • Die beliebtesten Arduino-Projekte von StartHardware
  • Inklusive Schaltplan, Beschreibung und Code
  • Arduino-Schnellstart-Kapitel
  • Kompakter Programmierkurs


3 Gedanken zu „RailFX: Sound-Modul mit Arduino“

  1. Hi Stefan,
    auch dieses Modul ist super
    ich habe nur ein Problem mit der Ordner Struktur. Du schreibst das Alle Sound Dateien im Ordner 01 gespeichert werden müssen, etwas weiter unten steht das die Dateien auf 24 Ordner 01,02,03 …. verteilt werden müssen. Wie muß das genau aussehen ? Ordner 01 und darunter 24 weitere Ordner und da dann die Sound Dateien, oder 24 Ordner auf der obersten Ebene, aber da nimmt er nur aus 01.

    Vielen Dank und Grüsse
    Peter

    1. Hi Peter, ich hab jetzt mal einen Screenshot der Ordnerstruktur mit eingefügt. Ich hoffe, das hilft. :-) Liebe Grüße Stefan

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

 

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.