In dem Experiment "Sound mit Piezo" wurden Töne über einen Piezo erzeugt. Will
man aber Töne gleichzeitig und unabhängig voneinander auf mehreren Piezos abspielen, so muss man einen
anderen Ansatz gehen ähnlich dem des LED-Blinkens ohne delay()
.
Die Töne können nicht mehr mit tone()
generiert werden, sondern werden mit
digitalWrite()
erzeugt. Da diese Funktion nur ein binäres Signal (HIGH oder
LOW) an den Pin-Ausgang sendet, wir aber zum Erzeugen der Töne eine Schwingung benötigen, müssen wir
zwischen HIGH und LOW in entsprechenden Zeitabständen hin- und herwechseln. Somit erzeugen wir eine
Rechtecksschwingung statt einem für den Ton notwendigen Sinussignal, die jedoch zur Generierung des Tons
ausreicht.
Jeder Ton hat eine ganz bestimmte Sinusfrequenz (f), z.B. ein "a" (Kammerton) bei 440Hz. Um die
Zeitverzögerung (d) zwischen den HIGH- und LOW-Signalen für einen bestimmten Ton zu berechnen,
müssen wir folgendermaßen vorgehen:
d = 1 / (2 × f)
(Wir teilen hier noch durch 2, weil der Lautsprecher einmal an und einmal aus ist)
Beispiel für A (440Hz):
d = 1 / (2 × 400) = 1136 µs (= Mikrosekunden = 1/1.000.000 Sekunden)
Somit können wir nun den Tönen mit ihren Frequenzen jeweils eine Verzögerungszeit zuordnen, z.B.:
Ton (Note) | Frequenz (in Hz) | Verzögerungszeit (in µs) |
---|---|---|
c | 261 | 1915 |
d | 294 | 1700 |
e | 329 | 1519 |
f | 349 | 1432 |
g | 392 | 1275 |
a | 440 | 1136 |
h | 493 | 1014 |
#define NUM_PIEZO_SPEAKER 2
struct PiezoSpeaker {
byte pin;
bool isPlaying;
unsigned long lastAction;
unsigned int noteDuration; // in milliseconds
bool freqState;
unsigned long lastFreq;
unsigned int freqDuration; // in microseconds
};
PiezoSpeaker piezos[] = {
{ 9, true, 0, 400, true, 0, 2028},
{10, true, 0, 600, true, 0, 3830}
};
unsigned long currentMillis = 0, currentMicros = 0;
void setup()
{
for (byte i=0; i<NUM_PIEZO_SPEAKER; i++) {
pinMode(piezos[i].pin, OUTPUT);
}
}
void loop()
{
currentMillis = millis();
currentMicros = micros();
for (byte i=0; i<NUM_PIEZO_SPEAKER; i++) {
if (currentMillis - piezos[i].lastAction < piezos[i].noteDuration) {
if (piezos[i].isPlaying == true) {
if (currentMicros - piezos[i].lastFreq < piezos[i].freqDuration) {
if (piezos[i].freqState == true) {
digitalWrite(piezos[i].pin, HIGH);
} else {
digitalWrite(piezos[i].pin, LOW);
}
} else {
piezos[i].freqState = !piezos[i].freqState;
piezos[i].lastFreq = currentMicros;
}
}
} else {
piezos[i].isPlaying = !piezos[i].isPlaying;
piezos[i].lastAction = currentMillis;
}
}
}
zurück