ArduinoVariablePWMFrequenz

Aus Hackerspace Ffm
Wechseln zu: Navigation, Suche

Die standard Frequenz ist 490 Hz, an manchen Pins 980 Hz. Für die meisten Anwendungen ist das ausreichend. Braucht man mehr Auswahl, kann man über den Prescaler sehr einfach weitere Frequenzen zur Verfügung stellen.

Für die 490 Hz Pins gibt es folgende Möglichkeiten:

Teiler Frequenz
1 31.372,55
8 3.921,16
64 490,2
256 122,55
1024 30,64

Für 980 Hz Pins diese:

Teiler Frequenz
1 62.500
8 7.812,5
64 976,56
256 244,14
1024 61,035

Eingestellt werden können diese über das Register TCCRnB. Das n steht für den Timer. Also gehört das Register TCCR1B zum Timer 1.

TCCR1B.PNG

Die wichtigen bits sind CS12, CS11 und CS10 die mit dem Ausdruck CSn2:0 zusammengefasst werden.

CSn2-0 ClockSelect.PNG

Im Code schreibt man dann für eine Frequenz von 31372 Hz:

 TCCR1B = TCCR1B & 0b11111000 | 0x01; 


Möchte man jede x-beliebige Frequenz zu der ein Arduino fähig ist erzeugen, wird es schnell kompliziert. Man muss sich ausgiebig mit dem Datenblatt und dem inneren Aufbau der Timer/Counter auseinander setzen.

Timer unterscheiden sich grundlegend in ihrer Bit-Tiefe bzw. Auflösung. Es gibt 8 bit (256) und 16 bit (65.536) Timer. Zum Verständnis nochmal die PWM als Diagramm mit Periode und Duty Cycle.

Period DutyCycle Flank.PNG Periods 1Second.PNG

Wir gehen von einem Arduino mit 16 Mhz aus. Jede Sekunde besteht aus 16.000.000 Takten.

Ein 16-bit Timer kann in seinem Register TCNTn bis zu 65.536 Takte in einer Periode hochzählen. Das ist seine maximale Auflösung die bestimmt wie fein der Duty Cycle eingestellt werden kann. Üblicherweise hat ein PWM-Ausgang 256 Möglichkeiten den Duty Cycle einzustellen.

Teilen wir diese Auflösung durch die Takte der MCU pro Sekunde, haben wir eine Frequenz von 244.14 Hz. Die Periodendauer ist 1s / 244.14 Hz = 4.1 ms. Wollen wir aber nur eine Auflösung von 265 Schritten pro Periode haben, ergibt sich eine Frequenz von 60.377,36 Hz mit einer Periodendauer von 16.5 µs.. Es gibt also eine Abhängigkeit zwischen der Auflösung und der Frequenz der PWM, die sich in folgender Formel beschreiben lässt:

 Hz = clk/resolution 

Jetzt schauen wir uns an, wie wir das Ganze anhand des Datenblattes umsetzen können. Als Aufgabe stellen wir uns, eine Frequenz von 20 KHz zu erzeugen. Sie soll das nervige Fiepen der Standard-PWM-Frequenz von 490 Hz vermeiden um einen DC-Motor geräuschlos betreiben zu können.

Timer haben verschiedene Modi.

WaveformGenerationModeBitDescription.PNG

Wir entscheiden uns für den Modus 14 Fast PWM mit ICRn als TOP.

Eingestellt wird er über die Bits WGMn0:3 die sich über die Register TCCRnA und TCCRnB verteilen.

TCCR1A.PNG TCCR1B.PNG

Da können wir uns auch gleich den Rest des Registers TCCR1A anschauen. Die bits COM1A0:1, COM1B0:1 und COM1C0:1 kontrollieren das Verhalten der Output Compare Pins OCnA, OCnB und OCnC (Stehen in den Pinoutdiagrammen) . Stehen die bits auf 0, arbeitet der Port normal und unsere anderen Einstellungen haben keinen Effekt. Wir wählen hier 1 0 für inverting. Alles weitere später.

COMnx0-1.PNG

Also pin OC1A (pin 11) auf inverting mode und am Ende WGM01:11.

TCCR1A = 0b11000010;

Und dann WGM12:13 und den prescaler auf 1 (kein prescaler).

TCCR1B = 0b00011001;

Das Timerregister TCNTn wird bei jedem Takt von BOTTOM 0 um den Wert 1 nach oben gezählt. Erreicht der Inhalt den Wert TOP, startet er wieder mit BOTTOM. Wie in der Tabelle zu sehen können wir TOP über das 16 bit Register ICRn festlegen. Damit legen wir unsere Auflösung, Frequenz und Periodendauer fest. Frequenz: 20.000 Hz Auflösung: 800 Takte (16.000.000 / 20.000) Periodendauer: 5 µs (1 / 20.000)

ICR1 = 800;

Der Duty Cycle wird über das Register OCRnx festgelegt.

OCR1A = 200;

Zu guter letzt können wir auch noch die Funktion pinMode(11, OUTPUT); über Register direkt einstellen. Die I/O-Ports werden in A, B, C, ... aufgeteilt. Das steht im Kapitel 13.4. Jeder Portregister fasst 8 pins zusammen. Das Register DDRx ist das Data Direction Register, im Falle von DDRB das für den Port B. Über die Pinbelegung sehen wir das der Pin 11 auch PB5 genannt wird. DDRB.PNG Also müssen wir das Bit DDB5 setzen.

DDRB = DDRB | B00100000;


Und hier noch mal der ganze Code:

DDRB = DDRB | B00100000; // pin 11 als OUTPUT konfigurieren
TCCR1A = 0b11000010;     // Pin OC1A frei schalten
TCCR1B = 0b00011001;     // Prescaler auf 01 setzen um ~31.000 Takte zu haben
ICR1 = 800;              // TOP auf 800 fest legen, als besteht jeder Periode aus 800 Schritten
OCR1A = 200;             // Dutycycle auf 200 von 800 Takte legen

Timer-Pins

Arduino Pro Mini

timer bit pin register
timer0 8 5 OC0B
timer0 8 6 OC0A
timer1 16 9 OC1A
timer1 16 10 OC1B
timer2 8 3 OC2B
timer2 8 11 OC2A

Arduino Mega2560

timer bit pin register
timer0 8 4 OC0B
timer0 8 13 OC0A
timer1 16 11 OC1A
timer1 16 12 OC1B
timer2 8 9 OC2B
timer2 8 10 OC2A
timer3 16 2 OC3B
timer3 16 3 OC3C
timer3 16 5 OC3A
timer4 16 6 OC4A
timer4 16 7 OC4B
timer4 16 8 OC4C
timer5 16 44 OC5A
timer5 16 45 OC5B
timer5 16 46 OC5C