Lektion 16 – Ein-Tasten-Piano

Hast Du Lust, ein richtiges Musikinstrument mit Arduino zu bauen? Na dann geht’s los!

Benötigte Bauteile

Bauteile Piezo Button

Benötigte Bauteile

Bauplan Piezo Button

Wir bauen jetzt ein Piano mit nur einer Taste. Ich würde sagen, das Piano soll einen Ton auslösen, wenn die Taste gedrückt wird. Wenn sie losgelassen wird, soll der Ton wieder ausgehen.

int speakerPin = 9;
int buttonPin = 11;

void setup() {
  pinMode(buttonPin, INPUT);
}

void loop() {
  if (digitalRead(buttonPin)==HIGH){
    tone(speakerPin, 440);
  } else {
    noTone(speakerPin);
  }
}

Wie schaffen wir es jetzt, dass wir damit eine Melodie spielen können? In der vorherigen Lektion waren wir der Lösung schon sehr nah. Da haben wir die for-Schleife benutzt, um einen Ton des Arrays zu spielen. Wie wäre es, wenn der Button dieses Mal das Zählen übernehmen würde? Dazu brauchen wir aber noch einen kleinen Trick. Wir müssen nämlich dieses Mal genau wissen, wann der Button gedrückt wird und nicht, wann er einfach nur an ist. Wenn wir nur:

if (digitalRead(buttonPin)==HIGH){
	ton = ton + 1;
}

fragen, dann wird diese Abfrage so lange wahr sein, bis wir den Button loslassen. Wenn wir hierbei versuchen würden, eine Variable hochzuzählen, wäre die bei einer Sekunde schon bei fast unendlich.

Wir müssen also nicht nur wissen, ob der Button gedrückt ist, sondern auch, ob er direkt davor nicht gedrückt war. Das geht mit einer Boolean-Variable.

Boolean

Variablen vom Typ Boolean kennen zwei Zustände, nämlich true (wahr) und false (falsch). Wenn wir eine Variable haben, die buttonPressed, also Taster gedrückt heißt, dann könnte diese den aktuellen Zustand des Tasters speichern.

  1. Beim Programmstart ist der Taster ist nicht gedrückt, die Variable buttonPressed wird auf falsch gesetzt.
  2. Geprüft wird in der ersten if-Abfrage jetzt nicht nur nach digitalRead(buttonPin)==HIGH, sondern auch darauf, ob buttonPressed== false ist. Das kann man mit dem doppelten et-Zeichen machen (&&).
  3. Ist das der Fall, wird buttonPressed auf true gesetzt.
  4. Wenn der Button nicht gedrückt ist, wird buttonPressed auf false gesetzt.

Im Programmtext sieht das so aus:

boolean buttonPressed = false;

int speakerPin = 9;
int buttonPin = 11;

void setup() {
  pinMode(buttonPin, INPUT);
}

void loop() {
  if ((digitalRead(buttonPin)==HIGH)&&(buttonPressed==false)){
    buttonPressed=true;


  } 
  if (digitalRead(buttonPin)==LOW){
    buttonPressed=false;


  }
}

Jetzt können wir eine Zählervariable mitlaufen lassen. Wenn diese zu groß wird, muss sie wieder auf 0 gesetzt werden. Das erledigt die dritte if-Abfrage:

int tonAnzahl = 27;
int ton = 0;

boolean buttonPressed = false;

int speakerPin = 9;
int buttonPin = 11;

void setup() {
  pinMode(buttonPin, INPUT);
}

void loop() {
  if ((digitalRead(buttonPin)==HIGH)&&(buttonPressed==false)){
    buttonPressed=true;

    ton=ton+1;
  } 
  if (digitalRead(buttonPin)==LOW){
    buttonPressed=false;

  }
  if (ton>=tonAnzahl){
    ton=0;
  }
}

Und nun brauchen wir nur noch die Tonausgabe hinzuzufügen:

int frequenzen[] = {
  262, 294, 330, 349, 392, 392, 440, 440, 440, 440, 392, 440, 440, 440, 440, 392, 349, 349, 349, 349, 330, 330, 392, 392, 392, 392, 262};
int tonDauer[]= {
  200, 200, 200, 200, 400, 400, 200, 200, 200, 200, 800, 200, 200, 200, 200, 800, 200, 200, 200, 200, 400, 400, 200, 200, 200, 200, 800};
int tonAnzahl = 27;
int ton = 0;

boolean buttonPressed = false;

int speakerPin = 9;
int buttonPin = 11;

void setup() {
  pinMode(buttonPin, INPUT);
}

void loop() {
  if ((digitalRead(buttonPin)==HIGH)&&(buttonPressed==false)){
    buttonPressed=true;
    tone(speakerPin, frequenzen[ton]);
    ton=ton+1;
  } 
  if (digitalRead(buttonPin)==LOW){
    buttonPressed=false;
    noTone(speakerPin);
  }
  if (ton>=tonAnzahl){
    ton=0;
  }
}

Titelbild von Damien Pollet, CC-BY-SA

Hast du weitere Fragen? Probier doch mal unser brandneues Forum zu Arduino aus!

7 thoughts on “Lektion 16 – Ein-Tasten-Piano

  1. Fehlt da nicht irgendwie die ‚tonDauer‘ im letzten Abbild ?

    konkret aus:
    void loop() {
    if ((digitalRead(buttonPin)==HIGH)&&(buttonPressed==false)){
    buttonPressed=true;
    tone(speakerPin, frequenzen[ton]);
    ton=ton+1;
    }

    ergänzt um ein ‚ delay(tonDauer[ton]); ‚ im if-Teil ergibt:

    void loop() {
    if ((digitalRead(buttonPin)==HIGH)&&(buttonPressed==false)){
    buttonPressed=true;
    tone(speakerPin, frequenzen[ton]);
    delay(tonDauer[ton]);
    ton=ton+1;
    }

    1. Hallo Simon,

      Du hast ein gutes Auge. Die Frage ist gut! Hier die Antwort: Den tone()-Befehl gibt es in zwei Ausführungen:

      • tone(Pin, Tonhöhe)
      • tone(Pin, Tonhöhe, Dauer)

      Wir benutzen hier die obere Variante, da der Ton so lange erklingen soll, wie die Taste gedrückt ist. Ich hoffe, das hilft Dir weiter.

      Liebe Grüße

      Stefan

    2. Ne ne, Simon hat da schon recht!!!
      Mal ausprobieren! Mit erster Variante bekommst du den Melodieablauf niemals hin!
      Der Ton bleibt aber mit der Eingabe von Simon auch, so lange die Taste gedrückt ist!

  2. Guten Tag,
    hat sich in dem ersten Abbild des Codes bei der if-Abfrage ein Fehler eingeschlichen?
    Dort steht „tone(9, 440)“
    Dieser Pin wurde ja am Anfang als Variable festgelegt.
    „Müsste“ es konsequenter Weise dann nicht „tone(speakerPin, 440)“ heißen?

    Übrigens eine sehr tolle und anschauliche Tutorial-Website. Großes Lob von meiner Seite.

  3. Guten Tag,

    Warum wurde den in der setup Funktion per pinMode() nicht mitgeteilt, dass man speakerPin als output verwenden möchte? Hat sich da ein Fehler geschlichen oder wird das durch die tone-funktion erledigt?

Schreibe einen Kommentar

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

Ich akzeptiere

 

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