Standardmäßig bietet der Arduino Uno mit dem Befehl "analogWrite(...)" die Möglichkeit, PWM-Signale mit einer Auflösung von 8 Bit und einer PWM-Frequenz von 490 Hz (Pin D3, D9, D10 und D11) bzw. 980 Hz (Pin D5 und D6) auszugeben. Wer für seine Anwendung eine höhere Auflösung und/oder eine höhere oder tiefere PWM-Frequenz haben möchte, muss zwangsläufig selbst diverse Bits in den entsprechenden Timer-/Counter-und Port-Registern setzen.
Die PWM-Pins des Arduino Uno werden von den Timern 0, 1 und 2 kontrolliert:
- Pins D5 und D6: Timer0 (8 Bit)
- Pins D9 und D10: Timer1 (16 Bit)
- Pins D3 und D11: Timer2 (8 Bit)
Das folgende Beispiel zeigt die Verwendung des 16 Bit Timer1, wie ein PWM-Signal mit anderer Frequenz und Auflösung als standardmäßig vorgegeben, programmiert wird. Mit Timer1 können nur die Pins D9 und D10 als PWM-Pins verwendet werden!
Verwendete Register:
- Timer Counter Control Register A: TCCR1A
- Output Compare Register A: OCR1A (für PWM-Pin D9)
- Output Compare Register B: OCR1B (für PWM-Pin D10)
- Port B Data Direction Register: DDRB
Vorgehensweise:
- 1. Modus wählen
- 2. PWM-Frequenz festlegen
- 3. Ausgangs-Aktion festlegen
- 4. Pin als Ausgang definieren
- 5. Setzen des Wertes der Pulsweite
1. Modus wählen:
Timer 1 erlaubt drei Modi: 8 Bit-, 9 Bit- und 10 Bit-PWM. Die Auswahl erfolgt über die Bits "Waveform Generation Mode" WGM10, WGM11 und WGM12 der "Timer/Counter Controll Register" A und B (TCCR1A und TCCR1B).
Die Bits WGM10 und WGM11 befinden sich im Timer/Counter Control Register A (TCCR1A), das Bit WGM12 im Timer/Counter Control Register B (TCCR1B).
TCCR1A - Timer/Counter1 Control Register A: 7 6 5 4 3 2 1 0 COM1A1 COM1A0 COM1B1 COM1B0 - - WGM11 WGM10
TCCR1B - Timer/Counter1 Control Register B: 7 6 5 4 3 2 1 0 ICNC1 ICES1 - WGM13 WGM12 CS12 CS11 CS10
Codebeispiel: Loeschen der Timer/Counter Control Register A und B
TCCR1A = 0;
TCCR1B = 0;
In der nachfolgenden Tabelle sind die Einstellungen der Bits für den gewünschten Modus ersichtlich:
Einstellungen der Bits Modus WGM12 WGM11 WGM10 Fast PWM 8Bit 1 0 1 Fast PWM 9Bit 1 1 0 Fast PWM 10Bit 1 1 1
Codebeispiel: Den Modus Fast PWM-Mode 9 Bit einstellen
TCCR1A |= (0 << WGM10) | (1 << WGM11);
TCCR1B |= (1 << WGM12);
Modus Fast PWM-Mode 10 Bit einstellen
TCCR1A |= (1 << WGM10) | (1 << WGM11);
TCCR1B |= (1 << WGM12);
2. PWM-Frequenz festlegen
Die PWM-Frequenz ist abhängig von der Taktfrequenz des Prozessors, der Auflösung und der Einstellung des Vorteilers (Prescaler).
Vorgaben:
- PWM-Auflösung 8, 9 oder 10 Bit
- CPU-Frequenz Arduino Uno: 16.000.000 Hz
- Mögliche Vorteiler: 1, 8, 64, 256 oder 1024
In Abhängigkeit der Auflösung wird die PWM-Frequenz [Hz] nach folgender Formel ermittelt:
8-Bit PWM: Frequenz = CPU Frequenz/Vorteilerx256
9-Bit PWM: Frequenz = CPU Frequenz/Vorteilerx512
10-Bit PWM: Frequenz = CPU Frequenz/Vorteilerx1024
Berechnungsbeispiel:
Z.B. Auflösung = 10 Bit, Vorteiler = 256:
PWM Frequenz = 16.000.000 / (256 * 1024) = 61 Hz
oder z.B. Auflösung = 10 Bit, Vorteiler = 8:
PWM Frequenz = 16.000.000 / (8 * 1024) = 1.953 Hz (Wird im untenstehenden Programmbeispiel verwendet)
oder z.B. Auflösung = 9 Bit, Vorteiler = 1:
PWM Frequenz = 16.000.000 / (1 * 512) = 31.250 Hz
Nachfolgende Tabelle zeigt alle möglichen PWM-Frequenzen in Abhängigkeit der Auflösung und des Vorteilers bei einer Taktfrequenz des Uno von 16 MHz. Wie man sieht, liegt die höchste PWM-Frequenzen bei 62,5 kHz, die tiefste Frequenz bei 15 Hz:
Mögliche PWM Frequenzen [Hz] Vorteiler Auflösung 8 Bit
(256)9 Bit
(512)10 Bit
(1024)1 62.500,0 31.250,0 15.625,0 8 7.812,5 3.906,3 1.953,1 64 976,6 488,3 244,1 256 244,1 122,1 61,0 1024 61,0 30,5 15,3
Berechnung möglicher PWM Frequenzen [Hz] in Excel
Der gewünschte Vorteiler muss im Timer/Counter Control Register B (TCCR1B) mit den Bits "Clock Select" CS10, 11 und 12 gesetzt werden: 7 6 5 4 3 2 1 0 ICNC1 ICES1 - WGM13 WGM12 CS12 CS11 CS10
Die Bitkombination für den gewünschten Vorteiler ist in nachfolgender Tabelle ersichtlich: Vorteiler CS12 CS11 CS10 Keine Taktquelle
(Timer/Counter Stopp)0 0 0 Takt / 1 (keine Teilung) 0 0 1 Takt / 8 0 1 0 Takt / 64 0 1 1 Takt / 256 1 0 0 Takt / 1024 1 0 1
Codebeispiel: Vorteiler auf Takt / 8 setzen
TCCR1B |= (1 << CS11);
3. Ausgangsaktion festlegen
Hier legt man mit den "Compare Output Mode" - Bits des Timer/Counter1 Control Register A (TCCR1A) fest, ob das PWM-Signal nicht invertiert oder invertiert ausgegeben wird, oder ob das Signal abgeschaltet wird:
- Für PWM-Pin D9 : Bit COM1A0 und COM1A1
- Für PWM-Pin D10: Bit COM1B0 und COM1B1
7 6 5 4 3 2 1 0 COM1A1 COM1A0 COM1B1 COM1B0 - - WGM11 WGM10
Einstellungen der Bits für ein invertiertes/nicht invertiertes PWM Signal PWM Ausgang COM1A1/
COM1B1COM1A0/
COM1B0PWM ausgeschaltet 0 0 PWM Ausgang nicht inventiert 1 0 PWM Ausgang inventiert 1 1
Codebeispiel: Nichtinvertiertes PWM-Signal setzen
TCCR1A |= (1 << COM1A1);
4. PWM-Pin als Ausgang definieren:
Die PWM-Pins D9 und D10 sind Pins des Port B und können durch direktes Setzen der entsprechenden Bits DDB1 oder DDB2 im Data Direction Register Port B (DDRB) als Binärausgang definiert werden.
PWM-Pin als Ausgang definieren: Digitalpins Port B 7 6 5 4 3 2 1 0 DDB7 DDB6 DDB5 DDB4 DDB3 DDB2 DDB1 DDB0 - - D13 D12 D11 D10 D9 D8
Codebeispiel: PWM-Pin D9 als Ausgang definieren
DDRB |= (1 << DDB1);
5. Pulsweite setzen:
Die gewünschte Pulsweite kann nun, je nach verwendetem PWM-Pin, in das 16-Bit Output Compare Register A (OCR1A) für PWM-Pin D9 oder Output Compare Register B (OCR1B) für PWM-Pin D10 geschrieben werden. In Abhängigkeit der eingestellten Auflösung von 8, 9 oder 10 Bit kann der Wertebereich der Pulsweite 0 bis 255, 0 bis 511 oder 0 bis 1023 betragen. Bei einer Auflösung von z.B. 9 Bit und einer Pulsweite von 255 beträgt das Impuls-Pausenverhältnis somit 50:50.
Codebeispiel: Setzen des Impuls-Pausenverhältnis
//Potiwert einlesen mit einer Auflösung Analogeingang A2 = 10 Bit
potiWert = analogRead(potiPin);
OCR1A = potiWert;
Programmbeispiel:
Im folgenden Beispielprogramm wird die Helligkeit einer LED durch ein Potentiometer mit Pulsweitenmodulation gesteuert (PWM-Frequenz = 1.953 Hz, Auflösung 10 Bit = 1024 Stufen).
Verwendete Bauteile:
- 1 Arduino Uno
- 1 LED
- 1 Widerstand 220 Ohm
- 1 Poti 10 kOhm
C++ PWM Programm 1.953Hz
C++ PWM Programm 31.250Hz Lüftersteuerung
PWM Lüftersteuerung für Be- und Entlüftung
Das folgende ESP32 Codebeispiel startet einen seriellen Kommunikationsport, überprüft die CPU-Taktfrquenz, die XTAL Frequenz und den APB-Bustakt und gibt sie über die serielle Schnittstelle aus. Der GPIO-Pin 5 wird mit maximaler Geschwindigkeit getaktet.
Die XTAL Frequenz ist die periphere Takt-Frequenz und der APB-Busclock (APB_CLK) wird vom CPU_CLK abgeleitet.
C++ ESP32 CPU-Frequenz ermitteln
Die ESP32 CPU Frequenz, die periphere Takt-Frequenz XTAL und der APB-Busclock am Seriellen Monitor
Mit dem folgenden Codebeispiel wird der PWM-GPIO-Pin 5 definiert, dann erfolgt die Konfiguration der Frequenz und der Auflösung des PWM-Kanals. In der Hauptschleife erhöht sich allmählich das Tastverhältnis des PWM auf den maximalen Wert und reduziert sich allmählich wieder auf den Minimalwert.
C++ ESP32 PWM Beispiel 1
Das gleiche Programm wie das vorherige mit Ausnahme der Auflösung. Diese ist jetzt auf 4 Bit eingestellt und das Tastverhältnis im Bereich 0 - 15.
C++ ESP32 PWM Beispiel 2
Das nächste Programm ist ein ESP32 PWM Generator mit einem 1,3" OLED Display, der über den Seriellen Monitor konfigurierbar ist.
C++ ESP32 PWM Gemerator
Der PWM Generator ist über den Seriellen Monitor kofigurierbar.
f = Frequenz; d = Ti/Tp 0-1023; r = Aufloesung 8-16 Bit; p = GPIO.
C++ ESP32 PWM mit Poti, LED und 1,3" OLED-Display
ESP32 PWM mit Poti, LED und OLED-Display 1,3"
C++ ESP32 PWM 4 Kanal Multidimmer mit Potis, LEDs und OLED-Display 1,3
PWM-Signal 1kHz 8Bit Auflösung
PWM-Signal 20kHz 12Bit Auflösung