02 Die Pulsweitenmodulation ist eine Lüge

 

Wir haben bisher folgende unterschiedliche Pin-Arten kennengelernt: Digital Output, Digital Input, Analog Input. Die letzte, die uns noch fehlt: Analog Output. Hinter Analog Output versteckt sich ein etwas komplexeres Konzept. Die Anwendung ist sehr leicht. Wir könnten dieses Kapitel relativ schnell abhandeln, aber das Verständnis der Funktionsweise ist für den weiteren Verlauf wichtig.

 

###grafik

Wir haben gesehen, dass analogRead() mit einem Konverter arbeitet, der analoge Spannungen in digitale Werte umwandelt: Ein 10Bit-Analog-Digital-Konverter. Umgekehrt besitzt das Arduino Mega keinen Digital-Analog-Konverter. Das heißt es ist nicht in der Lage echte Spannungswerte zwischen 0-5Volt zu erzeugen. Aber das Arduino bedient sich einem cleveren Trick, um trotzdem unterschiedliche (quasi) Spannungen zu erzeugen. Diese Technik heißt Pulsweitenmodulation (kurz PWM).

Aber wozu brauchen wir überhaupt einen analogen OUTPUT? Ein analoger OUTPUT wird verwendet um z.B. ein aktives Element wie die LED in ihrer Leuchtintensität zu variieren oder um Motoren schneller oder langsammer drehen zu lassen. Weitere Verwendungen sind das Generieren von Audiosignalen oder die Erzeugung von modulierten Signalen wie sie z.B. für Infrarotbedienungen gebraucht werden.

Vergleichen wir den OUTPUT eines “normalen“ digitalen OUTPUTS mit dem eines analogen OUTPUTs, wenn das Signal von LOW auf HIGH geschaltet wird:

Anfangs sind beide Signale auf LOW geschaltet. Interessant wird es, wenn beide Pins auf HIGH sind: Während digitalWrite() seinen Zustand nicht verändert, sendet analogWrite kontinuierlich eine Rechteck-Welle aus. Sie wird automatisch vom Arduino erzeugt - also ständig selbstständig ein- und ausgeschaltet. Es gibt einen weiteren Vorteil: Dieses erzeugte Signal ist einstellbar. Sehen wir uns zunächst die analogWrite() Funktion näher an.

Pins, die die AnalogWrite() Funktion unterstützen, befinden sich auf den Pins 2-13 und sind auf anderen Arduino-Boards (z. B. dem Uno) mit einem Wellensymbol gekennzeichnet. In das erste Argument wird die Pinnummer eingetragen. Das zweite beschreibt das Tastverhältnis, dieser erzeugt die unterschiedlichen Spannungen. Der Wertebereich liegt von 0 bis 255. Mit der Null sind es insgesamt 256 Werte. Wird eine 0 eingesetzt, steht das für 0Volt. Der Wert 255 ist der Höchstwert und produziert eine Spannung von 5Volt.

###Grafik

Im Gegensatz zum 10Bit analog Input besitzt analogWrite() eine etwas niedrigere Auflösung von 8Bit: 256/8 = 32. Das heißt, dass wir zwischen 0 und 5Volt nur 32 Schritte erzeugen können. Pro Schritt sind das 0,156Volt (5Volt/32).

Grundprinzip der Pulseweitenmodulation

Das Muster eines PWMs besteht aus sich kontinuierlich wiederholenden HIGH und LOW Signalen. Also ein Schwingverhalten oder Frequenz. Die Frequenz ist eine aus der Physik stammende Kenngröße. Die Einheit der Frequenz wird Hertz genannt und beschreibt den Wechsel von einem Zustand in den nächsten. Genauer: Sie gibt die Anzahl sich wiederholender Vorgänge pro Sekunde an. Frequenzen werden in der Einheit Hertz (kurz Hz) gemessen.

Das Konzept der Frequenz bezieht sich gleichermaßen auf analoge wie auch digitale Signale:

Ein Hertz (Hz) gibt an wieviele HIGH und LOW Signale pro Sekunde stattfinden. Demnach sind 3Hz dreimal HIGH und dreimal LOW Signale pro Sekunde.

Das Tastverhältnis

Das Tastverhältnis gibt an wie das Verhältnis von HIGH zu LOW ist. Beträgt das Tastverhältnis 50%, so nimmt der HIGH und der LOW Zustand die gleiche Zeitdauer an. Dies hat Auswirkungen auf die Intensität des ausgehenden Signals - z.B. wie hell eine LED leuchtet . Um das Tastverhältnis zu definieren sehen wir uns das kleinste Element einer Frequenz an: eine Periode.

Das Tastverhältnis wird ausgerechnet, in dem die Zeit einer Schwingung (HIGH+LOW) mit der Zeitdauer für das HIGH dividiert wird.

Tastverhältnis = time on / time total
Tastverhältnis = 50% / 100% = 0,5
0,5 sind 50%

 

Erinnern wir uns, dass der Pegel des analogWrite() von 0 bis 255 reicht. Wenn wir eine LED mit 50% Intensität zum leuchten bringen lassen wollen, multiplizieren wir die 256 mal 0,5. Das ergibt einen Wert von 128. Aber in Wirklichkeit entspricht 50% dem Wert 127 und nicht 128. Wir zählen den Wert 0 nicht zu den 128 dazu.

Hier sind einige unterschiedliche Tastverhältnisse im Vergleich miteinander:

Die Frequenz der analogWrite() Pins

In Bezug auf die PWM fehlt uns eine letzte Sache. Wir haben noch nicht besprochen, wie oft das oben beschriebene Tastverhältnis pro Sekunde wiederholt wird.

Die Pulsweitenmodulation wird von den internen Timern des Arduinos erzeugt. Insgesamt besitzt das Board 5 timer: timer0 bis timer4. Jeder einzelne timer ist in der Lage 2-3 Pins mit einem PWM-Signal zu versorgen: Sie teilen sich die gleiche Frequenz, können aber unterschiedliche Tastverhältnisse haben.

Der timer0 unterscheidet sich von den übrigen timern. Er ist zuständig für millis() und micros() Funktionen. In späteren Kapiteln mehr zu diesem Thema. Timer0 operiert in fast PWM, alle anderen timer im sogenannten phase correct PWM.

Dies bedeutet, dass die PWM-Pins mit unterschiedlichen Frequenzen arbeiten:
– Pin 4 und 13 werden von timer0 kontrolliert, der eine Frequenz von ca. 976Hz hat.
– Alle anderen PWM-Pins werden durch die timer1-4 kontrolliert, die eine Frequenz von ca. 490Hz haben.

Angenommen wir haben ein Tastverhältnis von 75% mit analogWrite(2,191) eingestellt, dann wird dieses Signal 490x pro Sekunde am Pin 2 ausgegeben. Dadurch haben wir den Anschein einer Spannung von 3,75Volt.

Aber wozu brauchen wir überhaupt ein PWM? Theoretisch könnten wir auch selber mit einem gängigen digitalWrite() solch ein PWM imitieren. Es ist aber eine Frage der Geschwindigkeit und der Ressourcen. Es ist wesentlich effektiver, eine echte Pulsweitenmodulation zu verwenden.

Setzen wir das obere Beispiel mit einem sehr einfachen Code ins Praktische um. Verändere den Pegelwert und uploade den Sketch. Experimentiere mit Werten zwischen 0 und 255. Trägst du einen höheren Wert als 255 ein, wird trotzdem 255 als Maximum angenommen.


void setup() 
{
  pinMode(ledPin, OUTPUT);
}


void loop() 
{
  //verändere den Pegel und trage Werte zwischen 0-255 ein
  analogWrite(2, 255);
}

Im oberen Sketch hardcoden wir den Wert für den Pegel, d. h. wir tippen ihn direkt ein und er verändert sich nicht. Lass uns einen Schritt weiter gehen und eine LED hoch- und runter dimmen.