Parallele Sounds mit Piezo und Arduino

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().

Funktionsweise

Aufbau der Schaltung
Abb.: Aufbau der Schaltung

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

Verwendete Bauteile

Aufbau

Verdrahtung des Piezo
Abb.: Verdrahtung des Piezo
Aufbau der Schaltung
Abb.: Aufbau der Schaltung

Sketch

#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