Juke­box mit Klingeltönen

Lese­zeit: 8 Minu­ten

Lösung
Seite als PDF

RTTTL Klin­gel­tö­ne

RTTTL (Ring Tone Text Trans­fer Lan­guage) sind Klin­gel­tö­ne, die ursprüng­lich von Nokia für ihre Mobil­te­le­fo­ne ent­wi­ckelt wur­den. Ein Klin­gel­ton muss drei Bestand­tei­le haben:

  • den Namen des Klingeltons
  • die Stan­dard­vor­ga­ben: die Dau­er der Noten und die ver­wen­de­te Oktave
  • die durch Kom­ma­ta getrenn­ten Noten (inter­na­tio­na­le Noten­be­zeich­nung c, d, e, f, g, a, b) alle Tei­le sind durch einen Dop­pel­punkt getrennt

Bei­spiel Te Deum:

TeDeum:d=4,o=5,b=63:8c,8f,16f,16g,8a

d=4: Stan­dard­no­ten­län­ge Viertelnote

o=5: Anga­be der Oktave

b=63: Abspiel­ge­schwin­dig­keit 63 Schlä­ge pro Minute

8c: Note C als Ach­tel­no­te gespielt

Klin­gel­tö­ne zum Down­load bei 🔗PICAXE (abge­ru­fen am 8.5.23)

Juke­box im Seri­el­len Monitor

Das Pro­gramm ver­wen­det im ers­ten Schritt den Seri­el­len Moni­tor um ver­schie­de­ne Melo­dien abzuspielen.

So sieht es aus:

Ver­wen­de­te Hardware

Der Laut­spre­cher wird mit dem Signal­pin (gel­bes Kabel) an den Pin 7 des Ardui­nos ange­schlos­sen, das schwar­ze Kabel führt zu GND am Ardui­no. Der Wider­stand dient nur dazu die Laut­stär­ke zu reduzieren.

Benö­tig­te Biblio­thek installieren

Kli­cke auf das Sym­bol Biblio­thek und suche im nächs­ten Dia­log nach der Biblio­thek PlayRtttl.

Defi­ni­ti­on der Varia­blen und Ein­bin­den der Bibliothek

Die Klin­gel­tö­ne müs­sen für den Befehl zum Abspie­len als char-Array defi­niert wer­den. Die ecki­gen Klam­mern zei­gen, dass es sich um ein Array handelt.

Titel und Inter­pret sol­len aus dem Array extra­hiert wer­den. Der ers­te Dop­pel­punkt mar­kiert den Beginn der Noten.
Der / dient als Tren­nung zwi­schen Inter­pret und Titel.

Leer­zei­chen sind in Varia­blen nicht erlaubt.
Bei Titel, die ein Leer­zei­chen ent­hal­ten, wird es zunächst mit einem Unter­strich „mas­kiert“. Der Unter­strich wird spä­ter durch ein Leer­zei­chen ersetzt.

# include "PlayRtttl.hpp"

# define Lautsprecher 7

// Interpret und Titel als String
String TitelSong;

char TeDeum[] =
"Charpentier/Te_Deum:d=4,o=5,b=63:8c,8f,16f,16g,8a,8f,c6,8a,8a,8a#,16c6,16a#,16a,16a#,8c6,16g,16f,16g,16a,8g,8c,8f,16f,16g,8a,8f,c6,8a,8a,16a#,16c6,16a,16a#,g,16f,2f";

char FuerElise[] =
"Beethoven/Für_Elise:d=8,o=5,b=125:32p,e6,d#6,e6,d#6,e6,b,d6,c6,4a.,32p,c,e,a,4b.,32p,e,g#,b,4c.6,32p,e,e6,d#6,e6,d#6,e6,b,d6,c6,4a.,32p,c,e,a,4b.,32p,d,c6,b,2a";

char OdeandieFreude[] =
"Beethoven/Ode_an_die_Freude:d=4,o=6,b=100:a5,a5,a_5,c,c,a_5,a5,g5,f5,f5,g5,a5,a.5,8g5,2g5,";

char Bolero[] =
"Ravel/Bolero:d=4,o=5,b=80:c6,8c6,16b,16c6,16d6,16c6,16b,16a,8c6,16c6,16a,c6,8c6,16b,16c6,16a,16g,16e,16f,2g,16g,16f,16e,16d,16e,16f,16g,16a,g,g,";

Der setup-Teil

Hier wird der Seri­el­le Moni­tor gestar­tet und das Menü angezeigt.

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

  // auf serielle Verbindung warten
  while (!Serial) { ; }
  delay(500);

  // Menü im Seriellen Monitor
  Serial.println("1: Te Deum");
  Serial.println("2: Für Elise");
  Serial.println("3: Ode an die Freude");
  Serial.println("4: Bolero");
  Serial.println("5: Titel anzeigen");
  Serial.println("--------------------");
}

Der loop-Teil

Erläu­te­run­gen der Anweisungen:

while (Serial.available();

Die nächs­ten Anwei­sun­gen wer­den nur dann aus­ge­führt, wenn im Seri­el­len Moni­tor etwas ein­ge­ge­ben wird

char Zei­chen = Seri​al​.read();

Vom Seri­el­len Moni­tor wird ein Zei­chen gelesen

if (Zei­chen == '1')

Wenn 1 ein­ge­ge­ben wur­de, wer­den die Anwei­sun­gen in den geschweif­ten Klam­mern ausgeführt

Ent­spre­chen­de Anwei­sun­gen gel­ten für die übri­gen Ziffern

Titel­Song = String(TeDeum);

Für die „Wei­ter­ver­ar­bei­tung“ muss das char-Array in einen String umge­wan­delt werden

Zei­ge­Ti­tel();

Auf­ruf der Funk­ti­on Zei­ge­ti­tel (Erläu­te­rung im nächs­ten Abschnitt)

playRtttlBlocking(Lautsprecher, TeDe­um);

Titel auf dem Pin des Laut­spre­chers abspielen

void loop() 
{ 
  // auf serielle Eingabe warten 
  while (Serial.available() > 0) 
  { 
    // Eingabe im Seriellen Monitor lesen 
    char Zeichen = Serial.read(); 

    if (Zeichen == '1') 
    { 
      // char-Array des Titels in String umwandeln 
      TitelSong = String(TeDeum); 

      // Funktion aufrufen, Interpret/Titel extrahieren 
      ZeigeTitel(); 

      // Titel spielen 
      playRtttlBlocking(Lautsprecher, TeDeum); 
    } 

    if (Zeichen == '2') 
    { 
      TitelSong = String(FuerElise); 
      ZeigeTitel(); 
      playRtttlBlocking(Lautsprecher, FuerElise); 
    } 
    
    if (Zeichen == '3') 
    { 
      TitelSong = String(OdeandieFreude); 
      ZeigeTitel(); 
      playRtttlBlocking(Lautsprecher, OdeandieFreude); 
    } 

    if (Zeichen == '4') 
    { 
      TitelSong = String(Bolero); 
      ZeigeTitel(); 
      playRtttlBlocking(Lautsprecher, Bolero); 
    } 

    if (Zeichen == '5') 
    { 
      Serial.println("1: Te Deum"); 
      Serial.println("2: Für Elise"); 
      Serial.println("3: Ode an die Freude"); 
      Serial.println("4: Bolero"); 
      Serial.println("5: Titel anzeigen"); 
      Serial.println("--------------------");      
    } 
  } 
} 

Die Funk­ti­on ZeigeTitel

Der loop-Teil ruft die Funk­ti­on Zei­ge­Ti­tel auf. Der String Titel­song muss jetzt nach Namen des Inter­pre­ten und Namen des Titels getrennt werden. 

➨Funk­tio­nen

Titel­Song = TitelSong.substring(0, TitelSong.indexOf(":"));

Nach dem ers­ten Dop­pel­punkt suchen (indexOf) und mit sub­string den ers­ten Teil vom ers­ten Buch­sta­ben (0) bis zum : extrahieren

TitelSong.replace("_", " ");

Alle _ durch Leer­zei­chen ersetzen

String Inter­pret = TitelSong.substring(0, TitelSong.indexOf("/"));

Die Buch­sta­ben im String Titel­Song von 0 bis zum / ent­hal­ten den Interpreten

String Titel = TitelSong.substring(TitelSong.indexOf("/") + 1, TitelSong.length());

Der zwei­te Teil des Strings Titel­Song ent­hält den Titel. Er beginnt mit dem Zei­chen hin­ter dem / (+1) und endet mit der Län­ge des Strings (length)

void ZeigeTitel() 
{ 
  // Teil des Strings bis zum # kürzen, enthält die Informationen zu Interpret und Titel
  TitelSong = TitelSong.substring(0, TitelSong.indexOf(":")); 

  // _ durch leerzeichen ersetzen 
  TitelSong.replace("_", " "); 

  // erster Teil des Strings bis zum / -> Name des Interpreten 
  String Interpret = TitelSong.substring(0, TitelSong.indexOf("/")); 

  // zweiter Teil des Strings vom / + 1 bis zum Ende des Strings -> Name des Titels 
  String Titel = TitelSong.substring(TitelSong.indexOf("/") + 1, TitelSong.length()); 

  Serial.println("Spiele:"); 

  // Interpret anzeigen 
  Serial.print(Interpret + " "); 

  // Titel anzeigen 
  Serial.println(Titel); 
  Serial.println("---------------------------"); 
}

Juke­box mit Tas­ten­pad und LCD

Die Tas­ten eines Tas­ten­pads sol­len jetzt die Titel auswählen.

So sieht es aus:

Benö­tig­te Bauteile:

  • Laut­spre­cher
  • Tas­ten­pad
  • LCD 1602
  • Lei­tungs­dräh­te

Der Schalt­plan

(Fah­re mit der Maus über das Bild, um die Bezeich­nun­gen der Bau­tei­le zu sehen)

Zusätz­lich benö­tig­te Biblio­thek installieren

Kli­cke auf das Sym­bol Biblio­thek und suche im nächs­ten Dia­log nach der Biblio­thek Liquid­Crys­tal I2C.

Defi­ni­ti­on der Varia­blen und Ein­bin­den der Bibliotheken

# include "PlayRtttl.hpp"
# include "LiquidCrystal_I2C.h"

// Name des LCDs (lcd) festlegen
LiquidCrystal_I2C lcd(0x27, 20, 4);

# define Lautsprecher  7

// Variable für die gedrückte Taste des Tastenpads
int GedrueckteTaste;

String TitelSong;

char TeDeum[] =
"Charpentier/Te_Deum:d=4,o=5,b=63:8c,8f,16f,16g,8a,8f,c6,8a,8a,8a#,16c6,16a#,16a,16a#,8c6,16g,16f,16g,16a,8g,8c,8f,16f,16g,8a,8f,c6,8a,8a,16a#,16c6,16a,16a#,g,16f,2f";

char FuerElise[] =
"Beethoven/Für_Elise:d=8,o=5,b=125:32p,e6,d#6,e6,d#6,e6,b,d6,c6,4a.,32p,c,e,a,4b.,32p,e,g#,b,4c.6,32p,e,e6,d#6,e6,d#6,e6,b,d6,c6,4a.,32p,c,e,a,4b.,32p,d,c6,b,2a";

char OdeandieFreude[] =
"Beethoven/Ode_an_die_Freude:d=4,o=6,b=100:a5,a5,a_5,c,c,a_5,a5,g5,f5,f5,g5,a5,a.5,8g5,2g5,";

char Bolero[] =
"Ravel/Bolero:d=4,o=5,b=80:c6,8c6,16b,16c6,16d6,16c6,16b,16a,8c6,16c6,16a,c6,8c6,16b,16c6,16a,16g,16e,16f,2g,16g,16f,16e,16d,16e,16f,16g,16a,g,g,";

Der set­up-Teil

Im set­up-Teil wird das LCD gestartet.

void setup() 
{ 
  // LCD starten 
  lcd.init(); 

  // Hintergrundbeleuchtung einschalten 
  lcd.backlight(); 
}

Der loop-Teil

Das gedrück­te Tas­te des Tas­ten­pads wird mit ana­logRead am Ein­gang A0 abgefragt:

int Ana­log­wert = analogRead(A0);

Die Ana­lo­gen Ein­gän­ge lie­fern Wer­te zwi­schen 0 und 1023. Je nach gedrück­ter Tas­te erge­ben sich die­se Werte:

Eine switch case Abfra­ge weist je nach Wert die ent­spre­chen­de Akti­on zu.

Bei­spiel Abfra­ge der lin­ken Taste:

int Analogwert = analogRead(A0);

switch (Analogwert)
{
  case 0 ... 20:
      // char-Array des Titels in String umwandeln
      TitelSong = String(TeDeum);

      // Funktion aufrufen, Interpret/Titel extrahieren
      ZeigeTitel(TitelSong);

      // Titel spielen
      playRtttlBlocking(Lautsprecher, TeDeum);
      break;

case 0 … 20 fragt den Wer­te­be­reich zwi­schen 0 und 20 ab. Die übri­gen Wer­te­be­rei­che wer­den ent­spre­chend zugewiesen.

Beach­te das Leer­zei­chen vor und hin­ter den drei Punkten!

Der voll­stän­di­ge loop-Teil:

void loop() 
{ 
  // Tastenpad am Eingang A0 abfragen 
  int Analogwert = analogRead(A0); 
  
  // linke Taste; 
  switch (Analogwert) 
  { 
    case 0 ... 20: 
      // char-Array des Titels in String umwandeln 
      TitelSong = String(TeDeum); 

      // Funktion aufrufen, Interpret/Titel extrahieren 
      ZeigeTitel(); 

      // Titel spielen 
      playRtttlBlocking(Lautsprecher, TeDeum); 
      break; 

    // obere Taste 
    case 30 ... 60: 
      TitelSong = String(FuerElise); 
      ZeigeTitel(); 
      playRtttlBlocking(Lautsprecher, FuerElise); 
      break; 

    // rechte Taste 
    case 70 ... 120: 
      TitelSong = String(OdeandieFreude); 
      ZeigeTitel(); 
      playRtttlBlocking(Lautsprecher, OdeandieFreude); 
      break; 

    // untere Taste 
    case 150 ... 200: 
      TitelSong = String(Bolero); 
      ZeigeTitel(); 
      playRtttlBlocking(Lautsprecher, Bolero); 
      break; 

    // rechte äußere Taste 
    case 300 ... 400: 
      lcd.clear(); 
      lcd.setCursor(0, 0); 
      lcd.print("1: Te Deum"); 
      lcd.setCursor(0, 1); 
      lcd.print("2: F\365r Elise"); 
      lcd.setCursor(0, 2); 
      lcd.print("3: Ode an die Freude"); 
      lcd.setCursor(0, 3); 
      lcd.print("4: Bolero"); 
      break; 
  } 
}

Die Funk­ti­on ZeigeTitel

Die Funk­ti­on Zei­ge­Ti­tel zeigt Inter­pret und Titel auf dem LCD an.

void ZeigeTitel() 
{ 
  // Teil des Strings bis zum ersten Doppelpunkt kürzen, enthält die Informationen zu Interpret und Titel
  TitelSong = TitelSong.substring(0, TitelSong.indexOf(":")); 

  // _ durch leerzeichen ersetzen 
  TitelSong.replace("_", " "); 

  // erster Teil des Strings bis zum / -> Name des Interpreten 
  String Interpret = TitelSong.substring(0, TitelSong.indexOf("/")); 

  // zweiter Teil des Strings vom / + 1 bis zum Ende des Strings -> Name des Titels 
  String Titel = TitelSong.substring(TitelSong.indexOf("/") + 1, TitelSong.length()); 

   // Titel auf dem LCD anzeigen 
  lcd.clear(); 
  lcd.setCursor(0, 0); 
  lcd.print("Spiele:"); 
  lcd.setCursor(0, 1); 
  lcd.print(Interpret); 
  lcd.setCursor(0, 2); 
  lcd.print(Titel); 
}

Seite als PDF

Ver­wand­te Aufgaben:


Letzte Aktualisierung: 20. Nov 2023 @ 11:24