MezData-Logo

Exit-Room Wählscheiben-Telefon mit Arduino Uno und DFPlayer Mini

Wählscheibentelefon steuert DFPlayer Mini

Aufbau

Für einen Exit-Room soll ein Hilfetelefon mit 10 Tipps bereit gestellt werden.

 

Ein klassisches Wählscheibentelefon mit Impulswahl ist mit einem Arduino und einem DFPlayer-Mini verbunden.

Die Auswertung der Impulse wurde besonders an die "alten" Kontakte historischer Telefone angepasst.

Alle 2ms wird der Telefonpin A0 ausgelesen und der Wert in einer Variablen adcWert gemittelt, simuliert einen Tiefpass. Die typischen Kontaktschwierigkeiten alter Kontakte sind eleminiert. Steigende Flanken von adcWert werden als Impulse in wImpulse gezählt und nach 1,2 Sekunden seit dem ersten Impuls ausgewertet, das entsprechende Datei 0001.mp3 bis 0010.mp3 (10 bei der 0) von der SD-Karte im Root-Verzeichnis ausgegeben. Wird während der Ausgabe erneut gewählt, erfolgt sofort die Ausgabe der neuen Datei.

Schaltplan

Schaltung

Signalverlauf bei Wahl von Ziffer 3

OsziSignalverlauf geglättet

Alte Telefone haben teilweise schlechte Kontakte, durch einen simulierten Tiefpass werden die Messungen geglättet. Der kurze 0-Impuls am Ende hätte 4 statt 3 ergeben.

DFPlayerMini_Fast laden

Libary

Dateien auf SD-Karte speichern

DateistrukturDateien sollten mit Nummern wie 0001.mp3 gespeichert sein.

Wenn die Dateien im Root- (Haupt-) Verzeichnis abgelegt werden, gibt die Reihenfolge beim Kopieren auf die SD-Karte die Nummerierung vor, unabhängig vom Dateinamen. In Unterverzeichnissen wie "mp3" wird dagegen die Nummer im Dateinamen beachtet. Hinter den Nummern dürfen durchaus weitere beschreibende Texte stehen, siehe Beispiel rechts.

Bei diesem Beispiel wird mit der DFPlayerMini-Library aus dem Verzeichnis "mp3" mit playFromMP3Folder(nummer) gespielt.

Tondateien für SD-Karte für Beispielcode: DF-SDKarteTest.zip

Weitere Info: DFPlayer Mini Ansteuerung mit dem Arduino (Gute Beschreibung der Verzeichnisstruktur)

Beschreibung der Software

Alle 2ms wird mit dem AD-Wandler an Pin A0 die Spannung digitalisiert und mit den letzten Messwerten verrechnet in adcWert gespeichert:

adcWert = (adcWert*3+analogRead(Telefonpin))/4; // Spannung lesen und glaetten ca. 120µs

Nach dem Abheben des Hörers ertönt ein Wählton (WaehltonStueck).

Die gewählten Ziffern werden in einem Feld nummer[20] gespeichert.

Wird 2s (Wahl_Timeout) keine Ziffer mehr gewählt, wird die Nummer ausgeben und in der Variable wahl gespeichert.

Im Abschnitt NummerAuswerten kann dann entweder der Wert von wahl oder das Feld nummer[] (hier bleiben führende Nullen erhalten) ausgewertet werden.

Quellcode [ExitRoom/ExitRoom.ino]
/* ExitRoomTelefon V2.2 (cc-by-sa) Oliver Mezger 4.1.2022 
 * die gewaehlte Nummer wird in char-Array nummer[20], als uint-Wert wahl (geht nur bis 65535) 
 * und als String textNummer gespeichert. Sollte die Auswertung erleichtern..
 */
 
#include <SoftwareSerial.h>
#include <DFPlayerMini_Fast.h>
 
#define Telefonpin A0        // zum Telefon
#define Testoutput 13        // zur Kontrolle
#define ADC_abgehoben 900    // wenn unter diesem Wert, ist Hoerer abgehoben
#define ADC_Waehlscheibe 200 // wenn unter diesem Wert, ist Wahlkontakt geschlossen
#define Ziffer_Timeout 200   // nach dieser Zeit kommt kein weiterer Impuls mehr
#define Wahl_Timeout 2000    // nach dieser Zeit wird keine Ziffer mehr gewaehlt
#define WaehltonStueck 12    // Das MP3 fuer den Waehlton, spielt 0012.mp3
#define RichtigStueck 13     // Das MP3 fuer richtige Loesung
#define FalschStueck 14      // Das MP3 fuer falsche Loesungmp3
 
 
SoftwareSerial mySerial(10, 11); // RX, TX, fuer DF-Player
DFPlayerMini_Fast myMP3;
unsigned char nummerLaenge=0;    // Laenge der gewaehlten Nummer
unsigned char nummer[20];        // gewaehlte Nummer
String textNummer="";            // Nummer als String
String loesung="123123";         // richtige Nummer
 
void setup() {
  Serial.begin(115200);         // Ausgabe ueber serieller Monitor
  mySerial.begin(9600);         // Anbindung des DF-Player
  myMP3.begin(mySerial);
  Serial.println(F("Setting volume to 20"));
  myMP3.volume(20); // 0..30
  delay(20);
  pinMode(Testoutput,OUTPUT);
}
typedef enum {ruhe,abgehoben,impuls0,impuls1,naechsteZiffer,NummerAuswerten,NummerVorlesen} wZustandtyp;
wZustandtyp wZustand = ruhe;
 
void loop() {
  static unsigned char wImpulse = 0; // Impulszaehler
  static unsigned long wMillis;      // Zeitmarken fuer TimeOuts
  static unsigned int adcWert=1023;  // ADC-Wert an Telefonpin
  static unsigned int wahl=0;        // Nummer als Integer
  static unsigned char i=0;          // fuer Zaehlvorgaenge
  delay(2);                          // alle 2 ms ADC-Abtastung
  //digitalWrite(Testoutput,HIGH);
  adcWert = (adcWert*3+analogRead(Telefonpin))/4; // Spannung lesen und glaetten ca. 120µs
  //digitalWrite(Testoutput,LOW);
  //Serial.println(adcWert);
  switch (wZustand){                // ZustandsAutomat
    case ruhe:                      // Warten auf Hoerer abnehmen
      if(adcWert < ADC_abgehoben){
        wZustand=abgehoben;
        Serial.print(F("\nAbgehoben-ADCWert: "));
        Serial.println(analogRead(Telefonpin));
        myMP3.playFromMP3Folder(WaehltonStueck); // spiele Waehlton
      }
      break;
    case abgehoben:                   // Waehlton spielen und auf Impulse warten
      if(adcWert >= ADC_abgehoben+50){// wieder aufgelegt?
        myMP3.pause();
        Serial.println(F("Aufgelegt"));
        wZustand = ruhe;
      }
      if(adcWert < ADC_Waehlscheibe){ // Waehlscheibe betaetigt?
        wZustand = impuls0;
        wImpulse = 0;
        nummerLaenge=0;
        myMP3.pause();
      }
      break;
    case impuls0:                     // Waehlscheibenkontakt geschlossen
      if(adcWert > ADC_Waehlscheibe){ // Impuls Waehlscheibenkontakt geoeffnet?
        wMillis=millis(); // Zeitmarke setzen
        wImpulse++; // Impuls zaehlen
        wZustand = impuls1;
      }
      //Serial.println(adcWert); // Werteverlauf ausgeben
      break;
    case impuls1:                     // Waehlscheibenkontakt offen
      if(adcWert < ADC_Waehlscheibe){ // Kontakt wieder geschlossen?
        wZustand = impuls0;
      }
      if(millis()-wMillis > Ziffer_Timeout){ // kein weiterer Impuls
        Serial.print(wImpulse);
        wMillis=millis(); // Zeitmarke setzen
        wZustand = naechsteZiffer;
        nummer[nummerLaenge++]=wImpulse%10; // 10 Impulse -> Ziffer 0
      }
      //Serial.println(adcWert);      // Werteverlauf ausgeben
      break;
    case naechsteZiffer:
      if(adcWert < ADC_Waehlscheibe){  // Waehlscheibe betaetigt?
        wZustand = impuls0;
        wImpulse = 0;
      }
      if(millis()-wMillis > Wahl_Timeout){ // kein weitere Ziffer
        wZustand=NummerAuswerten;
        Serial.print(F("\nGewaehlte Nummer: "));
        wahl=0;
        textNummer="";
        for(i=0;i<nummerLaenge;i++){
          Serial.print(nummer[i]);
          wahl=wahl*10 + nummer[i];
          textNummer+= (char)('0'+nummer[i]); // Werte in ASCII-Zeichen umwandeln
        }
        Serial.println();
      }
      break;
    case NummerAuswerten: // Aktion mit der gewaehlten Nummer
      /* Beispiel fuer einfach nur das gewaehlte Stueck spielen
      myMP3.playFromMP3Folder(wahl); // einfach Stueck spielen
      wZustand=abgehoben;
       */
      // Bei einstelligen Nummern wird Stueck 0 bis 9 gespielt, sonst wird mit loesung verglichen
      if (nummerLaenge == 1){ // Nummer ist einstellig?
        myMP3.playFromMP3Folder(wahl); // einfach Stueck spielen, bei 0 -> 0000.mp3
      }
      else if(textNummer==loesung){
        Serial.println(F("Richtig"));
        myMP3.playFromMP3Folder(RichtigStueck); // Richtig
      }
      else {
        Serial.println(F("Falsch"));
        myMP3.playFromMP3Folder(FalschStueck); // Falsch
      }
      wZustand=abgehoben;
      /*  Beispiel fuer gewaehlte Nummer vorlesen
      i=0;
      wZustand=NummerVorlesen;
      */
      break;
    case NummerVorlesen: // Vorlesen der Nummer bis Waehlscheibe oder aufgelegt
      if(i >= nummerLaenge || analogRead(Telefonpin) < ADC_Waehlscheibe ||analogRead(Telefonpin) >= ADC_abgehoben+50 ){
        wZustand=abgehoben;
        break;
      }
      if(nummer[i]==0){ // Bei Ziffer 0 soll Stueck 10 spielen
        myMP3.playFromMP3Folder(10);
      }
      else myMP3.playFromMP3Folder(nummer[i]);
      i++;
      delay(600);   // Warten bis Player in Gang kommt
      do{
        delay(350); // nicht zu schnell hintereinander isPlaying abfragen
      } while(myMP3.isPlaying());  
      break;
  }
}
 

Auswertung nur mit der Wählscheibe z.B. für GeoCache-Anwendung

Hier wurde nur die Wählscheibe an A0 mit 330Ω gegen 5V angeschlossen, die Auswertung erfolgt nicht über AD-Wandlung, es kann beliebiger Digitalpin verwendet werden.r

Quellcode [GeoCache/GeoCache.ino]
/* GeoCache-Telefon V1.0 (cc-by-sa) Oliver Mezger 27.12.21 */
 
#include <SoftwareSerial.h>
#include <DFPlayerMini_Fast.h>
 
#define Telefonpin A0        // zum Telefon
#define Testoutput 13        // zur Kontrolle
#define Ziffer_Timeout 200   // nach dieser Zeit kommt kein weiterer Impuls mehr
#define Wahl_Timeout 2000    // nach dieser Zeit wird keine Ziffer mehr gewaehlt
 
 
SoftwareSerial mySerial(10, 11); // RX, TX
DFPlayerMini_Fast myMP3;
unsigned char nummerLaenge=0;    // Laenge der gewaehlten Nummer
unsigned char nummer[20];        // gewaehlte Nummer
String textNummer="";
String loesung="123123"; // richtige Nummer
 
void setup() {
  Serial.begin(115200);
  mySerial.begin(9600);
  myMP3.begin(mySerial);
  Serial.println(F("Setting volume to 20"));
  myMP3.volume(20); // 0..30
  delay(20);
  pinMode(Testoutput,OUTPUT);
  pinMode(Telefonpin,INPUT);
}
typedef enum {ruhe,impuls0,impuls1,naechsteZiffer,NummerAuswerten} wZustandtyp;
wZustandtyp wZustand = ruhe;
 
void loop() {
  static unsigned char wImpulse = 0; // Impulszaehler
  static unsigned long wMillis;      // Zeitmarken fuer TimeOuts
  static unsigned int wahl=0;        // Nummer als Integer
  switch (wZustand){
    case ruhe:                   // auf Impulse warten
      if(!digitalRead(Telefonpin)){ // Waehlscheibe betaetigt?
        wZustand = impuls0;
        wImpulse = 0;
        nummerLaenge=0;
        myMP3.pause();
        delay(20); // Entprellen
      }
      break;
    case impuls0:                     // Waehlscheibenkontakt geschlossen
      if(digitalRead(Telefonpin)){ // Impuls Waehlscheibenkontakt geoeffnet?
        wMillis=millis(); // Zeitmarke setzen
        wImpulse++; // Impuls zaehlen
        wZustand = impuls1;
        delay(20);  // Entprellen
      }
      break;
    case impuls1:                     // Waehlscheibenkontakt offen
      if(!digitalRead(Telefonpin)){ // Kontakt wieder geschlossen?
        delay(20);  // Entprellen
        if(!digitalRead(Telefonpin)){ // Kurze Impulse ignorieren
          wZustand = impuls0;
        }
      }
      if(millis()-wMillis > Ziffer_Timeout){ // kein weiterer Impuls
        Serial.print(wImpulse);
        wMillis=millis(); // Zeitmarke setzen
        wZustand = naechsteZiffer;
        nummer[nummerLaenge++]=wImpulse%10; // 10 Impulse -> Ziffer 0
      }
      break;
    case naechsteZiffer:
      if(!digitalRead(Telefonpin)){  // Waehlscheibe betaetigt?
        wZustand = impuls0;
        wImpulse = 0;
        delay(20);  // Entprellen
      }
      if(millis()-wMillis > Wahl_Timeout){ // kein weitere Ziffer
        wZustand=NummerAuswerten;
        Serial.print(F("\nGewaehlte Nummer: "));
        wahl=0;
        textNummer="";
        for(unsigned char i=0;i<nummerLaenge;i++){
          Serial.print(nummer[i]);
          wahl=wahl*10 + nummer[i];
          textNummer+= (char)('0'+nummer[i]); // Werte in ASCII-Zeichen umwandeln
        }
        Serial.println();
        Serial.println(textNummer);
      }
      break;
    case NummerAuswerten: // Hier sollte jetzt die Aktion mit der gewaehlten Nummer passieren
      if(textNummer==loesung){
        Serial.println(F("Richtig"));
        myMP3.playFromMP3Folder(2); // spiele Stueck
      } else {
        Serial.println(F("Falsch"));
        myMP3.playFromMP3Folder(1); // spiele Stueck
      }
      wZustand=ruhe;
      break;
  }
}
 

 

Wählscheibentelefon Links

Nummernschalter wikipedia.org/wiki/Nummernschalter

Impulswahl (IWV) nach Mehrfrequenzwahl (MFV) konvertieren

DFPlayer Mini Links

DFRobot wiki.dfrobot.com/DFPlayer_Mini_SKU_DFR0299

PowerBroker2 / DFPlayerMini_Fast