Die tone()-Funktion
Du hast bereits gesehen, dass die Kombination aus delay(), delayMicroseconds() und digitalWrite() verwendet werden kann, um einem Piezo-Buzzer Leben einzuhauchen. Aber wenn du es etwas bequemer magst, ist die tone() Funktion dein Freund und Helfer.
Die tone() Funktion ist tief in die Arduino-Programmiersprache eingebettet und dient dazu, das Erzeugen von Tönen zu vereinfachen. Sie verwandelt deinen Mikrocontroller in einen rudimentären Synthesizer, der Töne in verschiedenen Frequenzen erzeugen kann. Historisch betrachtet war die Erzeugung von Tönen mit Mikrocontrollern eine komplexe Aufgabe, die tone() Funktion hat jedoch diesen Prozess erheblich vereinfacht.
Der Aufruf der Funktion sieht wie folgt aus: tone(Pin, Frequenz, Dauer);. Hierbei ist der Pin der Anschlusspunkt für deinen Piezo-Buzzer, die Frequenz definiert den Ton und die Dauer bestimmt, wie lange der Ton gespielt wird. Ein kleines, aber wichtiges Detail: die Frequenz nimmt nur positive Werte bis zu 65.535 an.
Zum Beispiel erzeugt tone(8, 440, 1000); einen Ton mit einer Frequenz von 440 Hz für 1000 Millisekunden auf Pin 8. Einfach, oder?
Die Schönheit der tone() Funktion liegt in ihrer Benutzerfreundlichkeit. Sie macht die Erzeugung von Tönen zum Kinderspiel. Aber, wie bei allem im Leben, gibt es auch hier Einschränkungen. Die tone() Funktion kann nur einen Ton zur gleichen Zeit erzeugen und ist nicht auf allen Arduino-Boards, vor allem den kleineren Modellen, nutzbar.
Wenn du ein neues Projekt startest und ein Alarm-, Warnsystem oder ein interaktives Kunstwerk erstellen möchtest, dann ist die tone() Funktion wahrscheinlich deine erste Wahl. Aber für komplexere musikalische Kompositionen oder hochqualitative Audioausgabe sind spezialisierte Soundmodule oder Mikrocontroller erforderlich.
Auch wenn die tone() Funktion ihren Charme hat, darf nicht vergessen werden, dass auch delay() oder delayMicroseconds() in Kombination mit digitalWrite() effektiv zur Steuerung eines Piezo-Buzzers genutzt werden können. Mit dieser Kombination hast du mehr Kontrolle über den Ton, allerdings erfordert es mehr Aufwand, eine spezifische Frequenz zu erreichen. Es ist ein bisschen wie bei einem manuellen Getriebe im Vergleich zu einem Automatikgetriebe.
Jetzt, da du ein grundlegendes Verständnis davon hast, wie die tone() Funktion und die Kombination aus delay() und digitalWrite() funktionieren, ist es an der Zeit, selbst Hand anzulegen.
Aufbau und Verkabelung
Um einen Piezo-Buzzer mit deinem Arduino Uno zu verbinden, klemme das GND des Moduls an den GND des Arduino und den Signalpin des Moduls an einen digitalen Pin deines Arduino, beispielsweise Pin 8. Vergiss nicht, dass Sicherheit immer an erster Stelle steht: Schalte den Arduino aus, bevor du mit der Verkabelung beginnst.
Der Sketch - Beispiel 1
Beispiel 1
Lade danach den folgenden Sketch auf dein Arduino Board:
// Beispiel 1
int piezoPin = 7; //Der Piezo-Pin ist der Pin, an dem der Piezo-Summer angeschlossen ist
void setup()
{
// leer - Es gibt keine Initialisierungen, die im Setup durchgeführt werden müssen
}
void loop()
{
tone(piezoPin, 100); // Mit der tone-Funktion wird ein Ton mit der Frequenz 100 Hz auf dem Piezo-Summer erzeugt
}
Sketch-Details und Erläuterungen zu Beispiel 1
Nun hast du einen konstanten Ton, der von deinem Arduino erzeugt wird. Du kannst mit verschiedenen Frequenzwerten experimentieren, um ein Gefühl dafür zu bekommen, wie sich die Frequenz auf den erzeugten Ton auswirkt. Probiere Frequenzen wie 100, 1000, 10.000 und 60.000 aus und beobachte, wie der Ton sich verändert.
Es ist wichtig zu betonen, dass das Arduino nicht primär für die Tonerzeugung entwickelt wurde. Die Fähigkeit, Töne zu erzeugen, ist eher ein Nebeneffekt der Fähigkeit, digitale Ausgänge bei spezifischen Frequenzen zu schalten. Deswegen kann die tatsächliche Wiedergabe der Töne von der theoretischen Erwartung abweichen. Aber dennoch, es ist ein beeindruckendes Werkzeug in deinen Händen. Viel Spaß beim Experimentieren!
Der Sketch - Beispiel 2
Du hast bereits gesehen, wie man mit der tone() Funktion Töne erzeugt und wie man die Frequenz dieser Töne ändert. Aber wie wäre es, wenn wir die Länge des Tones, also seine Dauer, kontrollieren könnten? Dafür ist das dritte Argument in der tone() Funktion zuständig. Lass uns das in einem konkreten Beispiel betrachten:
// Beispiel 2
int piezoPin = 7; //Der Piezo-Pin ist der Pin, an dem der Piezo-Summer angeschlossen ist
void setup()
{
Serial.begin(9600); //Die serielle Kommunikation wird mit einer Baudrate von 9600 eingerichtet
}
void loop()
{
tone(piezoPin, 5000, 2500); //Mit der tone-Funktion wird ein Ton mit der Frequenz 5000 Hz und einer Dauer von 2500 ms auf dem Piezo-Summer erzeugt
for(int i=0; i<1000; i++)
{
Serial.println(i); //Die Variable i wird auf dem seriellen Monitor ausgegeben
delay(5); //Eine Pause von 5 Millisekunden wird gemacht
}
}
Sketch-Details und Erläuterungen zu Beispiel 2
In diesem Sketch wird die tone() Funktion aufgerufen und spielt einen Ton von 5000 Hz für eine Dauer von 2500 Millisekunden (2,5 Sekunden). Der Code tone(piezoPin, 5000, 2500); sorgt dafür. Anschließend beginnt die for-Schleife, die bis zu 1000 zählt und dabei jede Zahl über den seriellen Monitor ausgibt. Jede Iteration wird für 5 Millisekunden verzögert.
Ohne die for-Schleife würde der Ton kontinuierlich abgespielt, weil der loop()-Block ständig ausgeführt wird. Durch die Verzögerung in der for-Schleife haben wir jedoch eine Pause, während der keine neuen Töne erzeugt werden. Diese Pause erlaubt es uns, die Dauer des Tones zu hören, da der Ton erst nach der vollständigen Ausführung der for-Schleife wieder gestartet wird.
Diese Art von Code kann sehr nützlich sein, um die Abläufe in deinem Arduino-Projekt besser zu kontrollieren und zu koordinieren. Es zeigt auch, dass das Arduino mehr als nur ein Ton-Generator ist, es kann auch als Taktgeber für andere Prozesse fungieren.
Du bist nun bereit, deine eigenen musikalischen Meisterwerke mit deinem Arduino zu erschaffen. Fühl den Rhythmus, experimentiere mit verschiedenen Frequenzen und Tondauern und lass deine Kreativität freien Lauf.
Sketch - Beispiel 3
In diesem dritten Beispiel lernst du, dass eine einfache delay(1000); Funktion denselben Effekt wie die for()-Schleife im vorherigen Beispiel haben kann.
// Beispiel 3
int piezoPin = 7; // Der Piezo-Pin ist der Pin, an dem der Piezo-Summer angeschlossen ist
void setup()
{
//leer
}
void loop()
{
tone(piezoPin, 5000, 2500); // Mit der tone-Funktion wird ein Ton mit der Frequenz 5000 Hz und einer Dauer von 2500 ms auf dem Piezo-Summer erzeugt
delay(1000); // Eine Pause von 1000 Millisekunden wird gemacht
}
Sketch-Details und Erläuterungen zu Beispiel 3
Der Code sendet eine Tonfrequenz von 5000 Hz für eine Dauer von 2500 Millisekunden über das Piezo-Modul, das mit dem digitalen Pin 7 verbunden ist. Die delay(1000); Funktion im Anschluss pausiert dann das Programm für 1000 Millisekunden, bevor die Schleife von vorne beginnt. Dies erzeugt einen rhythmischen Tonimpuls.
Die delay() Funktion ist in diesem Fall sehr nützlich, weil sie die Wiedergabe des Tons zeitlich trennt, ohne dass eine kompliziertere Struktur wie eine for()-Schleife benötigt wird. Sie bietet also eine einfache Möglichkeit, den Ton zu steuern und einen rhythmischen Effekt zu erzeugen.
Die Verwendung der delay() Funktion hat außerdem den Vorteil, dass sie nur einen Parameter benötigt – die Zeit in Millisekunden, die das Programm pausieren soll. Das macht sie zu einer sehr leicht verständlichen und benutzerfreundlichen Funktion.
Um das Verhalten der delay() Funktion besser zu verstehen und den Einfluss der Pausendauer auf den erzeugten Ton zu hören, kannst du mit unterschiedlichen Werten experimentieren. Ändere den Wert in der delay() Funktion und lade den geänderten Sketch erneut auf dein Arduino Board. Du wirst bemerken, dass sich der Rhythmus des Tons verändert, abhängig von der Länge der Pause.
Dieser Code ist ein weiteres gutes Beispiel dafür, wie man die tone() und die delay() Funktionen in Arduino verwendet, um Töne zu erzeugen und zu steuern. Er demonstriert auch, wie man mit verschiedenen Funktionen und Parametern experimentiert, um unterschiedliche Effekte zu erzielen und das Verhalten des Codes besser zu verstehen.
Beispiel 4
Im vierten Beispiel wird eine potenzielle Herausforderung aufgedeckt, wenn man die tone() und delay() Funktionen gemeinsam verwendet. Hier ist der vorgesehene Ton und die Verzögerung jeweils auf 500 Millisekunden eingestellt, jedoch hören wir keinen abgesetzten Ton, sondern einen durchgehenden Klang. Warum ist das so?
// Beispiel 4
int piezoPin = 7; // Der Piezo-Pin ist der Pin, an dem der Piezo-Summer angeschlossen ist
void setup()
{
//leer
}
void loop()
{
tone(piezoPin, 5000, 500); // Mit der tone-Funktion wird ein Ton mit der Frequenz 5000 Hz und einer Dauer von 500 ms auf dem Piezo-Summer erzeugt
delay(500); // Eine Pause von 500 Millisekunden wird gemacht
}
Sketch-Details und Erläuterungen zu Beispiel 4
Hier kommt es zur Überschneidung der Funktionen von tone() und delay(). Beide Funktionen nutzen integrierte Timer des Arduino. Sie starten und enden gleichzeitig, was zur Folge hat, dass der nächste Ton genau dann beginnt, wenn der vorherige endet. Daher hört man keinen Unterschied und es klingt, als würde der Ton ununterbrochen abgespielt.
Um dieses Problem zu beheben und eine hörbare Pause zwischen den Tönen zu schaffen, muss der Wert für delay() länger sein als die Dauer des Tons, die in der tone() Funktion festgelegt ist. In anderen Worten, die Dauer der Stille muss größer sein als die Dauer des Tons.
In diesem Zusammenhang kann das Experimentieren mit unterschiedlichen Werten erneut sehr aufschlussreich sein. Probiere zum Beispiel, den Wert für delay() auf 550 Millisekunden zu erhöhen und höre, wie sich der Ton ändert. Mit diesem zusätzlichen Spielraum hat der Ton genug Zeit zum Abschwellen, bevor der nächste Ton beginnt, was zu einer hörbaren Pause führt.
Dieses Beispiel unterstreicht die Wichtigkeit des Verständnisses der Funktionsweise der verschiedenen Funktionen und wie sie interagieren können. Es zeigt auch, wie man dieses Wissen nutzen kann, um effektiv Probleme zu lösen und den gewünschten Klang zu erzeugen.
Limitationen von tone()
Der Einsatz der tone()-Funktion bringt eine Reihe von Vorzügen mit sich, allerdings müssen wir uns auch einiger Einschränkungen bewusst sein. Durch seine einfache und direkte Anwendung erweist sich tone() als ideales Werkzeug zur Erzeugung von Tönen. Aber gerade wenn wir komplexe Skizzen mit mehreren Funktionen entwickeln, stößt tone() an seine Grenzen.
Ein zentraler Punkt, der bei der Anwendung der tone()-Funktion bedacht werden muss, betrifft die Nutzung der integrierten Timer des Arduino. Ein bestimmter Pin und die tone()-Funktion können den gleichen Timer verwenden. Wird die tone()-Funktion und die analogWrite() Funktion gleichzeitig an Pin 10 verwendet, können Interferenzen auftreten. Dies führt zu unerwarteten, oft eigenartigen Tönen. In diesem Fall teilen sich tone() und Pin 10 den gleichen Timer, wodurch es zu diesen Interferenzen kommt.
Ebenfalls sollte berücksichtigt werden, dass die tone()-Funktion nicht in der Lage ist, gleichzeitig auf mehreren Pins zu arbeiten. Sollen verschiedene Töne nacheinander auf verschiedenen Pins ausgegeben werden, muss zunächst der Ton auf dem ersten Pin mittels noTone() beendet werden, bevor ein neuer Ton auf einem anderen Pin gestartet werden kann.
Eine weitere Beschränkung betrifft die Wiedergabe von sehr niedrigen Frequenzen. Während tone() durchaus dazu in der Lage ist, niedrige Frequenzen zu erzeugen, gibt es eine untere Grenze, unter der die Wiedergabe ungenau wird. Frequenzen unter 31 Hz können nicht genau wiedergegeben werden. Dies liegt an der begrenzten Geschwindigkeit, mit der das Arduino die digitalen Pins ein- und ausschalten kann.
Trotz dieser Einschränkungen bietet die tone()-Funktion einen hohen Nutzen, wenn es darum geht, auf einfache Weise Töne zu erzeugen. Sie ist ideal für Anwendungen geeignet, bei denen es weniger auf die Genauigkeit der Töne ankommt, sondern eher auf die einfache Implementierung und Nutzung.
Aufgabenstellung
Aufgabe 1: Experimentieren mit tone() und analogWrite()
In dieser Aufgabe untersuchst du das Problem-Verhalten von tone() und analogWrite(), wenn sie gleichzeitig am gleichen Pin ausgeführt werden. Du benötigst dazu dein Arduino-Board, einen Piezo-Buzzer und ein LED-Modul.
Aufbau und Verkabelung zu Aufgabe 1:
Verbinde den Piezo mit Pin 7 und das LED-Modul mit Pin 10 des Arduino-Boards.
Aufbau und Verkabelung zu Aufgabe 2:
Die Potentiometer lassen dich die Werte für Frequenz, Tondauer und delay() während der Ausführung des Sketches verändern. Verbinde zusätzlich einen Piezo-Buzzer mit Pin 7. Den Lösungscode kannst du mit dem unteren Button downloaden.
//Lösung 2
int piezoPin = 7; // Der Piezo-Pin ist der Pin, an dem der Piezo-Summer angeschlossen ist
int potPin1 = A0; // Der Potentiometer-Pin für die Frequenz
int potPin2 = A1; // Der Potentiometer-Pin für die Tondauer
int potPin3 = A2; // Der Potentiometer-Pin für die Verzögerung
void setup()
{
Serial.begin(9600); // Die serielle Kommunikation mit einer Baudrate von 9600 wird gestartet
}
void loop()
{
int frequency = analogRead(potPin1); // Die Frequenz wird vom Potentiometer gelesen
int duration = analogRead(potPin2); // Die Tondauer wird vom Potentiometer gelesen
int delayTime = analogRead(potPin3); // Die Verzögerung wird vom Potentiometer gelesen
tone(piezoPin, frequency, duration); // Der Ton wird mit den eingestellten Werten abgespielt
delay(delayTime); // Eine Pause entsprechend der eingestellten Verzögerung wird gemacht
Serial.print("Frequenz: ");
Serial.print(frequency);
Serial.print(" | Dauer: ");
Serial.print(duration);
Serial.print(" | Verzögerung: ");
Serial.println(delayTime);
}
Experimentiere mit den Potentiometern und höre auf die von dir erzeugten Klänge. Notiere dir die besten Kombinationen von Frequenz, Dauer und Verzögerung für zukünftige Projekte.
Schaffst du es den Code eingenständig zu schreiben? Den Lösungscode kannst du mit dem unteren Button downloaden. Beobachte das Verhalten des LED-Moduls und höre genau auf den Ton des Piezo-Buzzers. Ändere dann den Pin des LED-Moduls und beobachte, wie sich das Verhalten ändert.
//Lösung 1
int piezoPin = 7; // Der Piezo-Pin ist der Pin, an dem der Piezo-Summer angeschlossen ist
int ledPin = 10; // Der LED-Pin ist der Pin, an dem die LED angeschlossen ist
void setup()
{
pinMode(ledPin, OUTPUT); // Der LED-Pin wird als Ausgang definiert
}
void loop()
{
tone(piezoPin, 5000); // Mit der tone-Funktion wird ein Ton mit der Frequenz 5000 Hz auf dem Piezo-Summer erzeugt
analogWrite(ledPin, 128); // Mit der analogWrite-Funktion wird das LED-Pin auf eine PWM-gesteuerte Helligkeit von 50% gesetzt
delay(1000); // Eine Pause von 1000 Millisekunden wird gemacht
analogWrite(ledPin, 0); // Das LED-Pin wird auf eine Helligkeit von 0% gesetzt, also ausgeschaltet
delay(1000); // Eine Pause von 1000 Millisekunden wird gemacht
}
Aufgabe 2: Erstelle deine eigenen Sounds
Jetzt bist du dran, kreativ zu werden. Du kannst tone() und delay auch mehrmals hintereinander anordnen, um verschiedene Klänge zu erzeugen. In diesem Teil der Aufgabe erstellst du einen Test-Sketch, in dem du die Werte für Frequenz, Tondauer und delay() mit Potentiometern steuerst und die Werte an den seriellen Monitor sendest.
Zuerst verbindest du drei Potentiometer mit den analogen Eingangspins deines Arduino-Boards (A0, A1 und A2).