Also wie berechnet man die Werte, um den Timer auf eine bestimmte Frequenz einzustellen.
Wie kann man eine PWM mit einer anderen Auflösung als 8, 9 oder 10 Bit erstellen,
und wie kann man eine bestimmte PWM-Frequenz festlegen?
Dabei wird Wert auf Verständlichkeit gelegt, so dass auch Einsteiger damit was anfangen können.
Tutorial Timer-Berechnung
(Oder: Timer-Berechnung verständlich erklärt)
Inhalt 1. Einleitung
1.1 Vorteiler
1.2 Timer allgemein
2. Timer Berechnung
2.1 Berechnung Timer im Normal-Mode
2.2 Timer-Frequenzen einstellen
2.2.1 Timer-Berechnung mit Preload (Zählerwert vorladen)
2.2.2 Timer-Berechnung im CTC Mode
3. Pulsweitenmodulation
3.1 Einfache 8-PWM
3.2 Einfache 8-Bit PWM im Fast-PWM Mode
4. PWM Spezialfälle
4.1 PWM mit fester Auflösung
4.2 PWM mit fixer Frequenz
1. Einleitung
Es gibt immer wieder Situationen, in denen man einen Timer berechnen muss.
Sei es um eine genaue Zeitbasis zu erhalten, eine genaue PWM-Frequenz zu erhalten,
einen Zeittakt wie 1s oder 0,01 Sekunden zu erhalten und vieles mehr.
Allem zugrunde liegt die Berechnung des Timers. Und genau darum geht es hier.
Zunächst einige notwendige Grundlagen, die man verstanden haben sollte, damit man nicht
blind auf irgendwelche Tools vertrauen muss. Sondern selbst den Timer berechnen kann,
damit auch die gewünschte Frequenz heraus kommt.
1.1 Vorteiler
Jedem Timer vorgeschaltet ist ein Vorteiler (engl. Prescaler), der den Systemtakt teilt.
Das was den Vorteiler verlässt ist der Takt für den Timer selber. Die Teilerfaktoren des
Vorteilers sind vorgegeben (siehe Datenblatt des Controllers) und können nur bestimmte
Werte erhalten. Die möglichen Teilerfaktoren sind oft 1, 8, 64, 512 und 1024.
Bei Teilerfaktor 0 bekommt der Timer keinen Takt vom Prescaler. Der Timer steht also.
Auf den Vorteiler hat man mit dem folgenden Befehl Einfluss:
Config Timer = Timer, Prescale = xxx
Beispiel:
System-Takt ist 16MHz und Vorteiler auf 64 eingestellt, dann ergibt das
250000Hz (16000000Hz / 64 = 250000Hz), die der Timer bekommt.
1.2 Timer allgemein
Ein Timer ist nichts anderes als ein Zähler mit einer bestimmten Bitbreite.
Jeder Controller hat einen oder mehrere dieser Zähler integriert. Bekommt der Zähler
vom Vorteiler einen Takt, zählt er um eins weiter.
Die Zähler sind in 8-Bit breite oder 16-Bit breite ausgeführt.
Daraus ergeben sich verschiedene Zählbereiche.
Ein Timer mit 8 Bit kann bis 28, also bis 256 Zählen. Die Zählerwerte beginnen jedoch ab Null,
Daher können Zählerwerte von 0 bis 255 auftreten.
Der 16-Bit Timer kann bis 216, also bis 65536 Zählen. Auch hier beginnt der Zähler bei 0.
So ergeben sich hier Zählerwerte von 0 bis 65535.
Läuft der Zähler im normalen Modus, zählt dieser mit Null beginnend aufwärts bis zu höchsten Wert.
Dann läuft der Zähler über, bedeutet er beginnt wieder mit 0. Das wiederholt sich dann immer wieder.
2. Timer Berechnungen
2.1 Berechnung Timer im Normal-Mode
Eigentlich muss man hier nichts groß berechnen. Aber möchte man nun wissen,
mit welcher Frequenz der Timer überläuft, kann man das berechnen.
Frequenz Überlauf = Systemtakt / Vorteiler / WertebereichZähler
Beispiel:
Systemtakt sei 8MHz, der Vorteiler steht auf 1 und wir verwenden einen 8-Bit Timer.
$Crystal = 8000000
Config Timer0 = Timer , Prescale = 1 ' 8-Bit Timer
Lösung:
Der Timer bekommt den vollen Systemtakt, also 8MHz, da der Vorteiler auf 1 steht.
Der Timer hat 8-Bit und kann daher 256 Zählerwerte aufnehmen. Deshalb ergibt sich eine
Überlauffrequenz von:
Frequenz Überlauf = 8000000 / 1 / 256 = 31250Hz
Bei einem Timer-Überlauf kann man ein Interrupt (OVFn-Interrupt) auslösen lassen, wenn das entsprechend
konfiguriert wird. Auf diese Weise kann man eine Interrupt-Service-Routine (ISR) aufrufen lassen,
die dann 31250 mal in der Sekunde aufgerufen würde.
2.2 Timer-Frequenzen einstellen
Wenn nun aber nicht 31250Hz, sondern 40kHz gewünscht sind, was dann?
Anderes Quarz nehmen? Das kann man in Einzelfällen machen, sofern es ein Quarz mit der notwendigen
Frequenz gibt und der Controller diesen Takt noch verarbeiten kann. Der Takt wirkt aber auf das ganze
System, daher sollte man sich diesen Schritt 2x überlegen. Im Übrigen ist das auch nicht die übliche
Vorgehensweise.
Vielmehr geht man dazu über, den Zählerstand zu manipulieren, um die gewünschte Frequenz zu erreichen.
Hierfür gibt es 2 Möglichkeiten:
1. Der Zählerstand wird im OVF-Interrupt (ISR) manipuliert, indem der Zählerstand vorgeladen wird.
2. Man konfiguriert den Timer im CTC-Modus, der Timer setzt sich dann selber auf 0 bei Erreichen
eines Compare-Werts (Vergleichswert).
2.2.1 Timer-Berechnung mit Preload (Zählerwert vorladen)
Bei der Preload-Variante muss der Wert berechnet werden, der in der ISR in den Timer geladen werden
muss. Dadurch beginnt der Timer nicht ab 0 zu zählen, sondern ab einem höheren Wert. Dies bedeutet
wiederum, dass der Timer nicht nach 256 Takten (bei 8 Bit Timer) überläuft, sondern schon früher.
Einen Nachteil vorweg: Die Frequenz ist sehr ungenau.
Wie berechnet man diesen Wert nun.
Beispiel:
Gewünscht sei eine ISR-Frequenz von 40kHz, Systemtakt ist 8MHz und wir verwenden Timer0.
$Crystal = 8000000
Config Timer1 = Timer , Prescaler = 1
Wenn der Timer wie oben konfiguriert wird, erhalten wir eine Überlauffrequenz ohne Preload von:
Frequenz Überlauf = 8000000 / 1 / 256 = 31250Hz
Durch welchen Wert muss nun der Timer teilen, damit wir 40kHz heraus bekommen?
Also 8000000Hz / Zählerwert = 40000Hz ?
Teilt man den Timer-Takt durch die gewünschte Frequenz, erhält man den Wert, wie viele Zählschritte
der Timer machen darf, bevor dieser überläuft.
Also 8000000 / 40000 = 200
Der Timer darf also nur 200 Zählschritte machen, dann muss er überlaufen. Überlaufen tut der
Zähler aber nicht bei 255, sondern bei 256, was ja 0 ist.
Man muss also von der Anzahl möglicher Zählerwerte die 200 abziehen und erhält so den Wert,
der in der ISR vorgeladen werden muss.
Also 256 - 200 = 56
Viele Onlinetools berechnen genau diesen Wert.
Schreibt man sein Programm nun wie folgt, erlebt man eine Überraschung, wenn man die Frequenz überprüft.
Display All
Am PortB.1 wird ein kurzer Puls von ca. 1µs bei jedem Aufruf der ISR ausgegeben. Theoretisch
müssten jetzt hier genau 40kHz anliegen.
Mit dem Oszilloskop gemessen liegen aber tatsächlich nur 30,3kHz an.
01 - Preload_direkt.jpg
Wie man an der Frequenzanzeige im Oszillogramm oben rechts erkennen kann, wird die gewünschte
Frequenz bei weitem nicht erreicht.
Woher kommt diese Abweichung?
Genau genommen wird der Interrupt getriggert in dem Moment wenn der Timer von 255 auf 0 springt.
Der Controller speichert dann aber zuerst die Rücksprungadresse auf dem Stack, dann springt er
in die ISR und sichert dort erst mal diese Register: R0-R5, R7,R10,R11 and R16-R31.
Das geschieht alles im Hintergrund, ohne dass der Programmierer etwas davon mitbekommt.
Das benötigt dann erst mal einige Takte Laufzeit. Erst dann kommt der 1. Befehl in der ISR.
Timer0 = 56 ' Timer vorladen.
Wenn wir jetzt den Timer vorladen ist der aber nicht mehr auf Null. So ergibt sich ein Fehler,
der sich in der zu geringen Frequenz wieder spiegelt.
Man kann das Verhalten deutlich verbessern, wenn man zum Zeitpunkt an dem der Preload erfolgen
soll, einfach den Preload-Wert zum aktuellen Zählerstand aufaddiert.
Hierzu wird die Zeile "Timer0 = 56" in der ISR geändert zu "Timer0 = Timer0 + 56" Dadurch wird die
Laufzeit weitestgehend kompensiert.
Das folgende Programm enthält die Änderung.
Display All
Wieder mit dem Oszilloskop gemessen ergibt sich nun immerhin 39,41kHz. Ist schon deutlich besser
als den Preload-Wert direkt zu setzen. Dennoch ist die Abweichung signifikant.
02 - Preload_aufaddiert.jpg
Wie am Oszillogramm zu sehen ist (oben rechts), wird die gewünschte Frequenz noch immer nicht
genau erreicht. Die Abweichung zur Wunschfrequenz ist mit 1,475% beträchtlich.
Um nun genau die Frequenz hinzubekommen braucht man einen Frequenzzähler oder ein Oszilloskop.
Man müsste jetzt den berechneten Preload-Wert soweit erhöhen, bis die Frequenz stimmt.
Viele Hobby-Baster besitzen aber solche Messgeräte nicht. Ist hier also Ende der Fahnenstange?
Nein, zum Glück nicht. Hierfür gibt es den CTC-Mode.
2.2.2 Timer-Berechnung im CTC Mode
Im CTC (Clear Timer on Comparematch) Modus wird der Zähler automatisch auf 0 gesetzt, sobald
dieser einen bestimmten Wert erreicht. Dadurch entstehen keine Laufzeiten mehr die kompensiert
werden müssten. Diese Möglichkeit stellt die genaueste Variante bereit, eine bestimmte
Frequenz einzustellen. Das bekommt man auch ohne Frequenzzähler/Oszilloskop exakt hin.
Vorteil: Die Frequenz kann ohne Nachmessen exakt eingestellt werden.
Nachteil: Der Timer muss den CTC-Mode unterstützen (Das kann meist Timer1 u. Timer2,
teilweise auch Timer0. Das ist Controller-abhängig).
Die Berechnung selbst ist eigentlich gleich zur Preload-Methode.
Allerdings mit einem Unterschied:
Wir zählen ab Null bis zu einem bestimmten Wert, und nicht ab einem bestimmten Wert bis Überlauf.
Gleiches Beispiel wie oben (kleine Wiederholung):
Gewünscht sei eine ISR-Frequenz von 40kHz, Systemtakt ist 8MHz und wir verwenden Timer0.
$Crystal = 8000000
Config Timer1 = Timer, Prescaler = 1
Wenn der Timer wie oben konfiguriert wird, erhalten wir eine Überlauffrequenz ohne Preload von:
Frequenz Überlauf = 8000000 / 1 / 256 = 31250Hz
Durch welchen Wert muss nun der Timer Teilen, damit wir 40kHz heraus bekommen?
Also 8000000Hz / Zählschritte = 40000Hz ?
Teilt man den Timer-Takt durch die gewünschte Frequenz, erhält man den Wert, wie viele Zählschritte
der Timer machen darf.
Also 8000000Hz / 40000Hz = 200
Der Timer muss also nach 200 Takten wieder auf 0 gehen. Da der Timer aber ab Null zählt, müssen
wir 1 abziehen. Anzahl Zählerwerte sind 200, Mögliche Zählerwerte 0 - 199. Top-Wert ist somit 199.
Der CTC-Mode sieht vor, das der Top-Wert des Zählers durch das Register OCRnA definiert wird.
Also müssen wir dort den Wert 200-1 (199) reinschreiben. Damit der Zähler dann auch zurückgesetzt wird,
wenn der Top-Wert überschritten wird, muss der Timer als CTC-Timer konfiguriert werden.
Hört sich kompliziert an? - Isses aber gar nicht!
Die Konfiguration sieht nun so aus:
Config Timer0 = Timer , Clear_Timer = 1 ' Clear_Timer = 1 sorgt für das Rücksetzen bei Überlauf des Top-Wertes
OCR0A = 200 - 1 ' Frequenz wird hier eingestellt
Der verwendete Controller Mega168 beherrscht für alle 3 Timer den CTC Mode.
Beim Mega8 als Beispiel müsste man auf Timer 1 oder 2 ausweichen.
Das folgende Programm-Beispiel Zeigt nun den CTC-Mode in Aktion.
Da im CTC-Mode kein Overflow-Interrupt mehr ausgelöst wird, sondern ein OutputCompareMatch-Interrupt,
muss dies bei der Konfiguration der ISR berücksichtigt werden.
Display All
In der ISR ist kein Vorladen mehr notwendig. Anstelle des Vorladens tritt das OCnA-Register.
Anstelle von OVF-Interrupt tritt OCnA-Interrupt.
Die gemessene Frequenz mit dem Oszilloskop zeigt nun 40002Hz an. Die gewünschte Frequenz wurde also korrekt erreicht.
Von der Software her wäre das jetzt perfekt.
03 - CTC-Mode.jpg
3. Pulsweitenmodulation
Das Programmbeispiel aus Abschnitt "2.22 Timerberechnung im CTC-Mode" kann man natürlich auch
mit Hardware-PWM realisieren. Der Puls würde dann per Hardware im Hintergrund erzeugt. Die ISR würde
wegfallen, womit für die Pulserzeugung keine Rechenleistung mehr erforderlich ist.
Dazu aber später mehr.
Die Pulsweiten-Modulation (kurz PWM) ist sehr vielseitig einsetzbar. Damit kann
- Leistung gesteuert werden (z.B. LED-Dimmen)
- Pulserzeugung mit variablem Tastgrad
- Frequenzgenerierung (Zeitbasen)
- Digital-Analog-Wandler
und vieles mehr erzeugt werden.
Um eine PWM zu erzeugen gibt es in Bascom einige Konfigurationsvarianten.
Alle haben gemein, dass sie sich auf 8, 9 und auf 10 Bit PWM beschränken.
Zumindest ist mir nicht bekannt, wie ich mit der Bascom-Konfiguration eine 5 oder 6-Bit PWM
konfigurieren kann, oder wie ich eine PWM-Frequenz von z.B. genau 40kHz erhalte.
3.1 Einfache 8-PWM
Um eine einfache 8-Bit PWM zu generieren kann man folgendes Programm schreiben:
Display All
(Zur Abwechslung verwenden wir hier mal Timer 2)
Der Zähler ist hierbei im normalen PWM-Mode (Phase Correct). Bedeutet, der Zähler
zählt von 0 zum Maximum und dann wieder zurück bis 0. Dann beginnt das von neuem.
Also 0 bis 255, dann 254 bis 1, dann wieder von vorne (ab 0).
Achtung: Der Zähler durchläuft im Phase Correct Mode insgesamt 510 Zählschritte, nicht 512!
Sobald der Zählerwert beim Aufwärts-Zählen den Wert von OCR2A erreicht,
wird der Pin gelöscht (LOW, daher ist in der Konfiguration "Compare_A_PWM = Clear" angegeben).
Beim Runterzählen wird der Pin wieder gesetzt.
Es ergibt sich so eine PWM-Frequenz von 15686Hz bei 8MHz Takt und Prescaler 1.
Wie berechnet man das.
Wir erinnern uns. Systemtakt / Vorteiler ergibt den Takt, den der Timer bekommt.
Dieser hat 8 Bit (256 Zählschritte) und zählt einmal rauf und dann runter.
Das ergibt 510 Zählschritte.
Die Frequenz ergibt sich somit wie folgt:
PWM-Frequenz = Systemtakt / Vorteiler / Zählschritte
PWM_Frequenz = 8000000Hz / 1 / 510 = 15686Hz
Das Register OCR2A gibt hierbei das Tastverhältnis an.
3.2 Einfache 8-Bit PWM im Fast-PWM Mode
Fast-PWM ist schnell erklärt. Hierbei wird der Timer nur aufwärts gezählt. Erreicht der das Maximum,
beginnt er wieder von Null an. Der Timer umfasst damit 256 Zählschritte.
Um Fast-PWM einzuschalten, muss man in der Konfiguration angeben,
dass der Timer gelöscht werden soll, wenn der Top-Wert erreicht wird.
Das Erreicht man z.B. mit der Angabe:
Config Timer_n = PWM, ...,Clear_Timer = 1
Hier der Code:
Display All
Bei dem obigen Beispiel zählt der Timer nur 1x durch. Wir haben hier also 0 bis 255, insgesamt 256 Zählwerte.
Die Berechnung ergibt sich wie folgt:
PWM-Frequenz = Systemtakt / Vorteiler / Zählschritte
PWM-Frequenz = 8000000 / 1 / 256 = 31250
4. PWM Spezialfälle
Mit Spezialfälle ist gemeint, dass wir nicht ein 8-, 9- oder 10-Bit PWM generieren, sondern
- eine 4-Bit, 5-Bit oder 6-Bit als Beispiel.
- Oder eine PWM, die sich nicht an einer Bitgrenze orientiert, z.B. 100 Stufen anstatt 256 aufweist.
- oder eine PWM mit einer bestimmten Frequenz
4.1 PWM mit fester Auflösung
Angenommen wir möchten eine PWM, die den Einstellbereich von 0% bis 100% abdeckt.
D.h. mit den Werten 0 bis 100 möchten wir ein Tastverhältnis von 0% bis 100% erreichen,
dann brauchen wir einen Timer, der von 0 bis 100 zählt. Das sind dann 101 Zählschritte
Das erreichen wir nur, wenn Wert 100 der höchste Wert ist, bei 101 muss der Zähler wieder auf Null
zurück gehen.
Wenn man im Datenblatt schaut unter "Modes of Operation" bei dem Timer (hier Timer 2 vom Mega168),
dann gibt es dort folgende Tabellen.
Modes of Operation Timer2.PNG
Die Tabelle zeigt, welche Mode's der Timer beherrscht.
Wir möchten einen Timer-Mode, der PWM ausgibt, und bei dem ich selbst den höchsten Zählerwert
bestimmen kann.
In der Tabelle gibt es den Mode 5 und Mode 7, die in Frage kämen. Der Top-Wert wird durch das Register
OCRnA bestimmt. Weiterhin müssen die WGM-Bits korrekt gesetzt werden, je nachdem welchem Mode man möchte.
Zu beachten ist auch, dass die Bits COM2A1, COM2A2, COM2B1 und COM2B2 richtig gesetzt werden.
Output Compare Mode Timer2.PNG
Meines Wissens gibt es dafür keine Konfiguration-Variante per Config Timer.
Hier sollte man den Config Timer nur zur Basis-Konfiguration des Timers verwenden und den Rest
per Hand konfigurieren. So ist meine Vorgehensweise.
Ein Weg ist, z.B. den Timer mal wie folgt zu Konfigurieren:
Config Timer2 = Timer, Prescale = 1, Clear_Timer = 1
Damit hat man schon mal den CTC-Mode für die Frequenz generiert.
Oder man konfiguriert eine 8-Bit PWM (Fast-PWM) wie im Code-Beispiel unten.
Jetzt muss man nur noch die fehlenden WGM-Bits und die COM2An und COM2Bn Bits ergänzen.
Kontrollieren kann man das mit dem Simulator.
Alternativ kann man auch die Register von Hand setzen. Dann muss man nur die Register
TCCR2A und TCCR2B (bei Timer 2) setzen. Mit OCR2A wird die Frequenz eingestellt und
mit OCR2B das Tastverhältnis.
Da OCR2A die Frequenz bestimmt, kann man an dem Pin OC2A keine PWM generieren. Man muss also auf
OC2B ausweichen. OC2A-Pin kann aber normal als IO-Pin verwendet werden.
Der Timer wird zunächst als normaler PWM konfiguriert, Clear_Timer = 1 bewirkt, dass
es ein FAST-PWM wird.
Die PWM-Frequnz ergibt sich wie immer aus
PWM-Frequenz = Systemtakt / Vorteiler / Zählschritte
Zählschritte ist hierbei aber 101 (Zählerwerte 0 bis 100 = 101 Zählschritte)!
Daraus ergibt sich die Frequenz
PWM-Frequenz = 8000000Hz / 1 / 101 = 79208Hz
04 - Fast-PWM_Auflösung_101.jpg
Das Oszillogramm zeigt das Signal auf mit der resultierenden Frequenz.
Ist einem die PWM-Frequenz zu hoch, kann man nun durch weglassen von Clear_Timer = 1
in den Phase Correct PWM Mode wechseln. (Timer Mode 5) Dadurch halbiert sich die
PWM-Frequenz etwa. auf die Hälfte.
Achtung: Phase Correct Mode. Rauf zählen und runter: 0 bis 100, 99, 98 bis 1, sind 200 Zählschritte.
PWM-Frequenz = Systemtakt / Vorteiler / Zählwerte = 8000000Hz / 1 / 200 = 40000Hz
Ist auch diese Frequenz zu hoch kann man den nächsten Prescaler verwenden, wieder einmal mit
Clear_Timer = 1 und einmal ohne.
Zu guter Letzt kann man die Frequenz noch durch den Quarz selbst beeinflussen.
Mehr Möglichkeiten die Frequenz zu beeinflussen ist hier nicht möglich (Ausnahme andres Quarz).
Damit sind wir dann schon bei einem neuen Sonderfall, bei dem die PWM-Frequenz festgelegt wird
und sich daraus die Auflösung der PWM ergibt.
Mit der Festlegung des höchsten Zählerwerts bzw. der Anzahl der Zählerwerte kann man die Auflösung bestimmen.
Möchte man eine 4-Bit PWM, also 16 Zählwerte, muss der Top-Wert logisch 15 sein.
Gleiches mit 5-Bit PWM, das sind 32 Zählschritte, bei 6-Bit 64 Zählschritte.
4.2 PWM mit fixer Frequenz
Das Pendant zur PWM mit fester Auflösung ist die PWM mit fixer Frequenz.
Auch hierbei gibt es Einschränkungen bezüglich der PWM-Auflösung.
Wieder ein Beispiel.
Wir möchten eine PWM-Frequenz von 16kHz erreichen bei einem Systemtakt von 8MHz.
Logischerweise müssen wir nun mit Prescaler und Zählerauflösung (Anzahl Zählschritte)
jonglieren, um dies zu erreichen.
1. Rechnung mit Prescaler = 1
Bekannte Formel:
PWM-Frequenz = Systemtakt / Vorteiler / Zählschritte
Zählschritte ist der Wert bei dem der Zähler überläuft.
Wir stellen die Formel um auf Zählerschritte (Auflösung)
Der Zähler müsste in dem Fall bis 500 zählen können. Timer1 kann das, Timer2 nicht.Was tun? Auf Timer1 gehen? - Ist eine Möglichkeit.
2. Rechnung mit Prescaler = 8
Man kann aber mal schauen, was mit Prescaler 8 heraus kommt.
Der Zähler müsste nun bei 62,5 auf 0 springen. Entweder man entscheidet sich für 62 oder für 63.Wenn die Frequenz nun genau auf 16000Hz liegen muss, sollten wir ein anderen Systemtakt ausprobieren.
3. Rechnung mit Quarz = 4MHz und Prescaler 1
Nehmen wir mal ein 4MHz Quarz, dann ergibt sich mit Prescaler 1 folgendes:
Das geht sauber auf. Damit können nun exakt die 16kHz erreicht werden.
Da der Zähler bei 250 Überläuft, können folglich Werte von 0 - 249 dem OC2B-Register als
Tastgrade zugewiesen werden. Die Auflösung wäre nun in 250 Stufen (0 - 249).
Natürlich soll das auch ausprobiert werden.
Dazu wurde das Programm so geändert:
Display All
Es ist immer wieder schon zu sehen, wenn Theorie und Praxis zusammen passen.
Hier das Oszillogramm von obigem Programm. Die 16kHz werden exakt erreicht.
05 - Fast-PWM_Frequenz_16kHz.jpg
An dieser Stelle möchte ich meine Ausführungen zur Timer-Berechnung abschließen.
Ich hoffe ich konnte einige Berechnungs-Grundlagen vermitteln.
Sollten Fehler in diesem Tutorial sein, bitte PN an mich.
Mitch64.
Edit
01.01.2021 Option Clear_Timer in den Timer-Konfigurationen mit Unterstrich versehen. Der Code-Explorer in Bascom bemängelt das.
(Oder: Timer-Berechnung verständlich erklärt)
Inhalt 1. Einleitung
1.1 Vorteiler
1.2 Timer allgemein
2. Timer Berechnung
2.1 Berechnung Timer im Normal-Mode
2.2 Timer-Frequenzen einstellen
2.2.1 Timer-Berechnung mit Preload (Zählerwert vorladen)
2.2.2 Timer-Berechnung im CTC Mode
3. Pulsweitenmodulation
3.1 Einfache 8-PWM
3.2 Einfache 8-Bit PWM im Fast-PWM Mode
4. PWM Spezialfälle
4.1 PWM mit fester Auflösung
4.2 PWM mit fixer Frequenz
1. Einleitung
Es gibt immer wieder Situationen, in denen man einen Timer berechnen muss.
Sei es um eine genaue Zeitbasis zu erhalten, eine genaue PWM-Frequenz zu erhalten,
einen Zeittakt wie 1s oder 0,01 Sekunden zu erhalten und vieles mehr.
Allem zugrunde liegt die Berechnung des Timers. Und genau darum geht es hier.
Zunächst einige notwendige Grundlagen, die man verstanden haben sollte, damit man nicht
blind auf irgendwelche Tools vertrauen muss. Sondern selbst den Timer berechnen kann,
damit auch die gewünschte Frequenz heraus kommt.
1.1 Vorteiler
Jedem Timer vorgeschaltet ist ein Vorteiler (engl. Prescaler), der den Systemtakt teilt.
Das was den Vorteiler verlässt ist der Takt für den Timer selber. Die Teilerfaktoren des
Vorteilers sind vorgegeben (siehe Datenblatt des Controllers) und können nur bestimmte
Werte erhalten. Die möglichen Teilerfaktoren sind oft 1, 8, 64, 512 und 1024.
Bei Teilerfaktor 0 bekommt der Timer keinen Takt vom Prescaler. Der Timer steht also.
Auf den Vorteiler hat man mit dem folgenden Befehl Einfluss:
Config Timer = Timer, Prescale = xxx
Beispiel:
System-Takt ist 16MHz und Vorteiler auf 64 eingestellt, dann ergibt das
250000Hz (16000000Hz / 64 = 250000Hz), die der Timer bekommt.
1.2 Timer allgemein
Ein Timer ist nichts anderes als ein Zähler mit einer bestimmten Bitbreite.
Jeder Controller hat einen oder mehrere dieser Zähler integriert. Bekommt der Zähler
vom Vorteiler einen Takt, zählt er um eins weiter.
Die Zähler sind in 8-Bit breite oder 16-Bit breite ausgeführt.
Daraus ergeben sich verschiedene Zählbereiche.
Ein Timer mit 8 Bit kann bis 28, also bis 256 Zählen. Die Zählerwerte beginnen jedoch ab Null,
Daher können Zählerwerte von 0 bis 255 auftreten.
Der 16-Bit Timer kann bis 216, also bis 65536 Zählen. Auch hier beginnt der Zähler bei 0.
So ergeben sich hier Zählerwerte von 0 bis 65535.
Läuft der Zähler im normalen Modus, zählt dieser mit Null beginnend aufwärts bis zu höchsten Wert.
Dann läuft der Zähler über, bedeutet er beginnt wieder mit 0. Das wiederholt sich dann immer wieder.
2. Timer Berechnungen
2.1 Berechnung Timer im Normal-Mode
Eigentlich muss man hier nichts groß berechnen. Aber möchte man nun wissen,
mit welcher Frequenz der Timer überläuft, kann man das berechnen.
Frequenz Überlauf = Systemtakt / Vorteiler / WertebereichZähler
Beispiel:
Systemtakt sei 8MHz, der Vorteiler steht auf 1 und wir verwenden einen 8-Bit Timer.
$Crystal = 8000000
Config Timer0 = Timer , Prescale = 1 ' 8-Bit Timer
Lösung:
Der Timer bekommt den vollen Systemtakt, also 8MHz, da der Vorteiler auf 1 steht.
Der Timer hat 8-Bit und kann daher 256 Zählerwerte aufnehmen. Deshalb ergibt sich eine
Überlauffrequenz von:
Frequenz Überlauf = 8000000 / 1 / 256 = 31250Hz
Bei einem Timer-Überlauf kann man ein Interrupt (OVFn-Interrupt) auslösen lassen, wenn das entsprechend
konfiguriert wird. Auf diese Weise kann man eine Interrupt-Service-Routine (ISR) aufrufen lassen,
die dann 31250 mal in der Sekunde aufgerufen würde.
2.2 Timer-Frequenzen einstellen
Wenn nun aber nicht 31250Hz, sondern 40kHz gewünscht sind, was dann?
Anderes Quarz nehmen? Das kann man in Einzelfällen machen, sofern es ein Quarz mit der notwendigen
Frequenz gibt und der Controller diesen Takt noch verarbeiten kann. Der Takt wirkt aber auf das ganze
System, daher sollte man sich diesen Schritt 2x überlegen. Im Übrigen ist das auch nicht die übliche
Vorgehensweise.
Vielmehr geht man dazu über, den Zählerstand zu manipulieren, um die gewünschte Frequenz zu erreichen.
Hierfür gibt es 2 Möglichkeiten:
1. Der Zählerstand wird im OVF-Interrupt (ISR) manipuliert, indem der Zählerstand vorgeladen wird.
2. Man konfiguriert den Timer im CTC-Modus, der Timer setzt sich dann selber auf 0 bei Erreichen
eines Compare-Werts (Vergleichswert).
2.2.1 Timer-Berechnung mit Preload (Zählerwert vorladen)
Bei der Preload-Variante muss der Wert berechnet werden, der in der ISR in den Timer geladen werden
muss. Dadurch beginnt der Timer nicht ab 0 zu zählen, sondern ab einem höheren Wert. Dies bedeutet
wiederum, dass der Timer nicht nach 256 Takten (bei 8 Bit Timer) überläuft, sondern schon früher.
Einen Nachteil vorweg: Die Frequenz ist sehr ungenau.
Wie berechnet man diesen Wert nun.
Beispiel:
Gewünscht sei eine ISR-Frequenz von 40kHz, Systemtakt ist 8MHz und wir verwenden Timer0.
$Crystal = 8000000
Config Timer1 = Timer , Prescaler = 1
Wenn der Timer wie oben konfiguriert wird, erhalten wir eine Überlauffrequenz ohne Preload von:
Frequenz Überlauf = 8000000 / 1 / 256 = 31250Hz
Durch welchen Wert muss nun der Timer teilen, damit wir 40kHz heraus bekommen?
Also 8000000Hz / Zählerwert = 40000Hz ?
Teilt man den Timer-Takt durch die gewünschte Frequenz, erhält man den Wert, wie viele Zählschritte
der Timer machen darf, bevor dieser überläuft.
Also 8000000 / 40000 = 200
Der Timer darf also nur 200 Zählschritte machen, dann muss er überlaufen. Überlaufen tut der
Zähler aber nicht bei 255, sondern bei 256, was ja 0 ist.
Man muss also von der Anzahl möglicher Zählerwerte die 200 abziehen und erhält so den Wert,
der in der ISR vorgeladen werden muss.
Also 256 - 200 = 56
Viele Onlinetools berechnen genau diesen Wert.
Schreibt man sein Programm nun wie folgt, erlebt man eine Überraschung, wenn man die Frequenz überprüft.
BASCOM Source Code: Timer (Preload direkt gesetzt)
- ' Dieses Programm soll 40kHz am PortB.1 erzeugen.
- ' Es verwendet den berechneten Preload-Wert von 56 in der ISR.
- ' Der Preload-Wert wird in der ISR direkt gesetzt.
- $Regfile = "m168def.dat"
- $Crystal = 8000000 ' externes Quarz
- FrqOut Alias PortB.1 ' Ausgang zur Frequenzkontrolle
- Config FrqOut = Output
- Config Timer0 = Timer , Prescale = 1
- On OVF0 ISR_Timer0_Overflow
- Enable OVF0
- Enable Interrupts
- Do
- NOP
- Loop
- ' ISR-Routine
- ISR_Timer0_Overflow:
- Timer0 = 56 ' Preload mit berechnetem Wert
- Set FrqOut ' Puls ausgeben
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- Reset FrqOut
- Return
Am PortB.1 wird ein kurzer Puls von ca. 1µs bei jedem Aufruf der ISR ausgegeben. Theoretisch
müssten jetzt hier genau 40kHz anliegen.
Mit dem Oszilloskop gemessen liegen aber tatsächlich nur 30,3kHz an.
01 - Preload_direkt.jpg
Wie man an der Frequenzanzeige im Oszillogramm oben rechts erkennen kann, wird die gewünschte
Frequenz bei weitem nicht erreicht.
Woher kommt diese Abweichung?
Genau genommen wird der Interrupt getriggert in dem Moment wenn der Timer von 255 auf 0 springt.
Der Controller speichert dann aber zuerst die Rücksprungadresse auf dem Stack, dann springt er
in die ISR und sichert dort erst mal diese Register: R0-R5, R7,R10,R11 and R16-R31.
Das geschieht alles im Hintergrund, ohne dass der Programmierer etwas davon mitbekommt.
Das benötigt dann erst mal einige Takte Laufzeit. Erst dann kommt der 1. Befehl in der ISR.
Timer0 = 56 ' Timer vorladen.
Wenn wir jetzt den Timer vorladen ist der aber nicht mehr auf Null. So ergibt sich ein Fehler,
der sich in der zu geringen Frequenz wieder spiegelt.
Man kann das Verhalten deutlich verbessern, wenn man zum Zeitpunkt an dem der Preload erfolgen
soll, einfach den Preload-Wert zum aktuellen Zählerstand aufaddiert.
Hierzu wird die Zeile "Timer0 = 56" in der ISR geändert zu "Timer0 = Timer0 + 56" Dadurch wird die
Laufzeit weitestgehend kompensiert.
Das folgende Programm enthält die Änderung.
BASCOM Source Code: Timer (Preload aufaddiert)
- ' Dieses Programm soll 40kHz am PortB.1 erzeugen.
- ' Es verwendet den berechneten Preload-Wert von 56 in der ISR.
- ' Der Preloadwert wird allerdings zum Zählerwert aufaddiert.
- $Regfile = "m168def.dat"
- $Crystal = 8000000 ' externes Quarz
- FrqOut Alias PortB.1 ' Ausgang zur Frequenzkontrolle
- Config FrqOut = Output
- Config Timer0 = Timer , Prescale = 1
- On OVF0 ISR_Timer0_Overflow
- Enable OVF0
- Enable Interrupts
- Do
- NOP
- Loop
- ' ISR-Routine
- ISR_Timer0_Overflow:
- Timer0 = Timer0 + 56 ' Preload mit berechnetem Wert wird aufaddiert
- Set FrqOut ' Puls ausgeben
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- Reset FrqOut
- Return
Wieder mit dem Oszilloskop gemessen ergibt sich nun immerhin 39,41kHz. Ist schon deutlich besser
als den Preload-Wert direkt zu setzen. Dennoch ist die Abweichung signifikant.
02 - Preload_aufaddiert.jpg
Wie am Oszillogramm zu sehen ist (oben rechts), wird die gewünschte Frequenz noch immer nicht
genau erreicht. Die Abweichung zur Wunschfrequenz ist mit 1,475% beträchtlich.
Um nun genau die Frequenz hinzubekommen braucht man einen Frequenzzähler oder ein Oszilloskop.
Man müsste jetzt den berechneten Preload-Wert soweit erhöhen, bis die Frequenz stimmt.
Viele Hobby-Baster besitzen aber solche Messgeräte nicht. Ist hier also Ende der Fahnenstange?
Nein, zum Glück nicht. Hierfür gibt es den CTC-Mode.
2.2.2 Timer-Berechnung im CTC Mode
Im CTC (Clear Timer on Comparematch) Modus wird der Zähler automatisch auf 0 gesetzt, sobald
dieser einen bestimmten Wert erreicht. Dadurch entstehen keine Laufzeiten mehr die kompensiert
werden müssten. Diese Möglichkeit stellt die genaueste Variante bereit, eine bestimmte
Frequenz einzustellen. Das bekommt man auch ohne Frequenzzähler/Oszilloskop exakt hin.
Vorteil: Die Frequenz kann ohne Nachmessen exakt eingestellt werden.
Nachteil: Der Timer muss den CTC-Mode unterstützen (Das kann meist Timer1 u. Timer2,
teilweise auch Timer0. Das ist Controller-abhängig).
Die Berechnung selbst ist eigentlich gleich zur Preload-Methode.
Allerdings mit einem Unterschied:
Wir zählen ab Null bis zu einem bestimmten Wert, und nicht ab einem bestimmten Wert bis Überlauf.
Gleiches Beispiel wie oben (kleine Wiederholung):
Gewünscht sei eine ISR-Frequenz von 40kHz, Systemtakt ist 8MHz und wir verwenden Timer0.
$Crystal = 8000000
Config Timer1 = Timer, Prescaler = 1
Wenn der Timer wie oben konfiguriert wird, erhalten wir eine Überlauffrequenz ohne Preload von:
Frequenz Überlauf = 8000000 / 1 / 256 = 31250Hz
Durch welchen Wert muss nun der Timer Teilen, damit wir 40kHz heraus bekommen?
Also 8000000Hz / Zählschritte = 40000Hz ?
Teilt man den Timer-Takt durch die gewünschte Frequenz, erhält man den Wert, wie viele Zählschritte
der Timer machen darf.
Also 8000000Hz / 40000Hz = 200
Der Timer muss also nach 200 Takten wieder auf 0 gehen. Da der Timer aber ab Null zählt, müssen
wir 1 abziehen. Anzahl Zählerwerte sind 200, Mögliche Zählerwerte 0 - 199. Top-Wert ist somit 199.
Der CTC-Mode sieht vor, das der Top-Wert des Zählers durch das Register OCRnA definiert wird.
Also müssen wir dort den Wert 200-1 (199) reinschreiben. Damit der Zähler dann auch zurückgesetzt wird,
wenn der Top-Wert überschritten wird, muss der Timer als CTC-Timer konfiguriert werden.
Hört sich kompliziert an? - Isses aber gar nicht!
Die Konfiguration sieht nun so aus:
Config Timer0 = Timer , Clear_Timer = 1 ' Clear_Timer = 1 sorgt für das Rücksetzen bei Überlauf des Top-Wertes
OCR0A = 200 - 1 ' Frequenz wird hier eingestellt
Der verwendete Controller Mega168 beherrscht für alle 3 Timer den CTC Mode.
Beim Mega8 als Beispiel müsste man auf Timer 1 oder 2 ausweichen.
Das folgende Programm-Beispiel Zeigt nun den CTC-Mode in Aktion.
Da im CTC-Mode kein Overflow-Interrupt mehr ausgelöst wird, sondern ein OutputCompareMatch-Interrupt,
muss dies bei der Konfiguration der ISR berücksichtigt werden.
BASCOM Source Code: Timer im CTC-Mode
- ' Dieses Programm soll 40kHz am PortB.1 erzeugen.
- ' Timer0 im CTC-Mode
- $Regfile = "m168def.dat"
- $Crystal = 8000000 ' externes Quarz
- FrqOut Alias PortB.1 ' Ausgang zur Frequenzkontrolle
- Config FrqOut = Output
- Config Timer0 = Timer , Prescale = 1 , Clear_Timer = 1
- OCR0A = 200 - 1 ' Frequenz wird hier eingestellt
- On OC0A ISR_Timer0_OC0A ' OC0A-Interrupt konfigurieren
- Enable OC0A ' OC0A-Interrupt zulassen
- Enable Interrupts
- Do
- NOP
- Loop
- ' ISR-Routine
- ISR_Timer0_OC0A:
- ' Preload des Timers entfällt im CTC-Mode
- Set FrqOut ' Puls ausgeben
- NOP
- NOP
- NOP
- NOP
- NOP
- NOP
- Reset FrqOut
- Return
In der ISR ist kein Vorladen mehr notwendig. Anstelle des Vorladens tritt das OCnA-Register.
Anstelle von OVF-Interrupt tritt OCnA-Interrupt.
Die gemessene Frequenz mit dem Oszilloskop zeigt nun 40002Hz an. Die gewünschte Frequenz wurde also korrekt erreicht.
Von der Software her wäre das jetzt perfekt.
03 - CTC-Mode.jpg
3. Pulsweitenmodulation
Das Programmbeispiel aus Abschnitt "2.22 Timerberechnung im CTC-Mode" kann man natürlich auch
mit Hardware-PWM realisieren. Der Puls würde dann per Hardware im Hintergrund erzeugt. Die ISR würde
wegfallen, womit für die Pulserzeugung keine Rechenleistung mehr erforderlich ist.
Dazu aber später mehr.
Die Pulsweiten-Modulation (kurz PWM) ist sehr vielseitig einsetzbar. Damit kann
- Leistung gesteuert werden (z.B. LED-Dimmen)
- Pulserzeugung mit variablem Tastgrad
- Frequenzgenerierung (Zeitbasen)
- Digital-Analog-Wandler
und vieles mehr erzeugt werden.
Um eine PWM zu erzeugen gibt es in Bascom einige Konfigurationsvarianten.
Alle haben gemein, dass sie sich auf 8, 9 und auf 10 Bit PWM beschränken.
Zumindest ist mir nicht bekannt, wie ich mit der Bascom-Konfiguration eine 5 oder 6-Bit PWM
konfigurieren kann, oder wie ich eine PWM-Frequenz von z.B. genau 40kHz erhalte.
3.1 Einfache 8-PWM
Um eine einfache 8-Bit PWM zu generieren kann man folgendes Programm schreiben:
BASCOM Source Code: Einfache PWM (Phase Correct)
Der Zähler ist hierbei im normalen PWM-Mode (Phase Correct). Bedeutet, der Zähler
zählt von 0 zum Maximum und dann wieder zurück bis 0. Dann beginnt das von neuem.
Also 0 bis 255, dann 254 bis 1, dann wieder von vorne (ab 0).
Achtung: Der Zähler durchläuft im Phase Correct Mode insgesamt 510 Zählschritte, nicht 512!
Sobald der Zählerwert beim Aufwärts-Zählen den Wert von OCR2A erreicht,
wird der Pin gelöscht (LOW, daher ist in der Konfiguration "Compare_A_PWM = Clear" angegeben).
Beim Runterzählen wird der Pin wieder gesetzt.
Es ergibt sich so eine PWM-Frequenz von 15686Hz bei 8MHz Takt und Prescaler 1.
Wie berechnet man das.
Wir erinnern uns. Systemtakt / Vorteiler ergibt den Takt, den der Timer bekommt.
Dieser hat 8 Bit (256 Zählschritte) und zählt einmal rauf und dann runter.
Das ergibt 510 Zählschritte.
Die Frequenz ergibt sich somit wie folgt:
PWM-Frequenz = Systemtakt / Vorteiler / Zählschritte
PWM_Frequenz = 8000000Hz / 1 / 510 = 15686Hz
Das Register OCR2A gibt hierbei das Tastverhältnis an.
3.2 Einfache 8-Bit PWM im Fast-PWM Mode
Fast-PWM ist schnell erklärt. Hierbei wird der Timer nur aufwärts gezählt. Erreicht der das Maximum,
beginnt er wieder von Null an. Der Timer umfasst damit 256 Zählschritte.
Um Fast-PWM einzuschalten, muss man in der Konfiguration angeben,
dass der Timer gelöscht werden soll, wenn der Top-Wert erreicht wird.
Das Erreicht man z.B. mit der Angabe:
Config Timer_n = PWM, ...,Clear_Timer = 1
Hier der Code:
BASCOM Source Code: Fast-PWM einfach
- ' Generierung einer 8-Bit PWM im Fast-PWM Mode
- $Regfile = "m168def.dat"
- $Crystal = 8000000
- ' PWM mit Timer2
- ' Frequenzausgabe an OC2A
- ' Der Pin wird automatisch als Ausgang konfiguriert.
- Config Timer2 = PWM , Prescale = 1 , Compare_A_PWM = Clear_Up , Clear_Timer = 1
- OCR2A = 5 ' Tastverhältnis einstellen
- Do
- NOP
- Loop
Die Berechnung ergibt sich wie folgt:
PWM-Frequenz = Systemtakt / Vorteiler / Zählschritte
PWM-Frequenz = 8000000 / 1 / 256 = 31250
4. PWM Spezialfälle
Mit Spezialfälle ist gemeint, dass wir nicht ein 8-, 9- oder 10-Bit PWM generieren, sondern
- eine 4-Bit, 5-Bit oder 6-Bit als Beispiel.
- Oder eine PWM, die sich nicht an einer Bitgrenze orientiert, z.B. 100 Stufen anstatt 256 aufweist.
- oder eine PWM mit einer bestimmten Frequenz
4.1 PWM mit fester Auflösung
Angenommen wir möchten eine PWM, die den Einstellbereich von 0% bis 100% abdeckt.
D.h. mit den Werten 0 bis 100 möchten wir ein Tastverhältnis von 0% bis 100% erreichen,
dann brauchen wir einen Timer, der von 0 bis 100 zählt. Das sind dann 101 Zählschritte
Das erreichen wir nur, wenn Wert 100 der höchste Wert ist, bei 101 muss der Zähler wieder auf Null
zurück gehen.
Wenn man im Datenblatt schaut unter "Modes of Operation" bei dem Timer (hier Timer 2 vom Mega168),
dann gibt es dort folgende Tabellen.
Modes of Operation Timer2.PNG
Die Tabelle zeigt, welche Mode's der Timer beherrscht.
Wir möchten einen Timer-Mode, der PWM ausgibt, und bei dem ich selbst den höchsten Zählerwert
bestimmen kann.
In der Tabelle gibt es den Mode 5 und Mode 7, die in Frage kämen. Der Top-Wert wird durch das Register
OCRnA bestimmt. Weiterhin müssen die WGM-Bits korrekt gesetzt werden, je nachdem welchem Mode man möchte.
Zu beachten ist auch, dass die Bits COM2A1, COM2A2, COM2B1 und COM2B2 richtig gesetzt werden.
Output Compare Mode Timer2.PNG
Meines Wissens gibt es dafür keine Konfiguration-Variante per Config Timer.
Hier sollte man den Config Timer nur zur Basis-Konfiguration des Timers verwenden und den Rest
per Hand konfigurieren. So ist meine Vorgehensweise.
Ein Weg ist, z.B. den Timer mal wie folgt zu Konfigurieren:
Config Timer2 = Timer, Prescale = 1, Clear_Timer = 1
Damit hat man schon mal den CTC-Mode für die Frequenz generiert.
Oder man konfiguriert eine 8-Bit PWM (Fast-PWM) wie im Code-Beispiel unten.
Jetzt muss man nur noch die fehlenden WGM-Bits und die COM2An und COM2Bn Bits ergänzen.
Kontrollieren kann man das mit dem Simulator.
Alternativ kann man auch die Register von Hand setzen. Dann muss man nur die Register
TCCR2A und TCCR2B (bei Timer 2) setzen. Mit OCR2A wird die Frequenz eingestellt und
mit OCR2B das Tastverhältnis.
Da OCR2A die Frequenz bestimmt, kann man an dem Pin OC2A keine PWM generieren. Man muss also auf
OC2B ausweichen. OC2A-Pin kann aber normal als IO-Pin verwendet werden.
Der Timer wird zunächst als normaler PWM konfiguriert, Clear_Timer = 1 bewirkt, dass
es ein FAST-PWM wird.
Die PWM-Frequnz ergibt sich wie immer aus
PWM-Frequenz = Systemtakt / Vorteiler / Zählschritte
Zählschritte ist hierbei aber 101 (Zählerwerte 0 bis 100 = 101 Zählschritte)!
Daraus ergibt sich die Frequenz
PWM-Frequenz = 8000000Hz / 1 / 101 = 79208Hz
04 - Fast-PWM_Auflösung_101.jpg
Das Oszillogramm zeigt das Signal auf mit der resultierenden Frequenz.
Ist einem die PWM-Frequenz zu hoch, kann man nun durch weglassen von Clear_Timer = 1
in den Phase Correct PWM Mode wechseln. (Timer Mode 5) Dadurch halbiert sich die
PWM-Frequenz etwa. auf die Hälfte.
Achtung: Phase Correct Mode. Rauf zählen und runter: 0 bis 100, 99, 98 bis 1, sind 200 Zählschritte.
PWM-Frequenz = Systemtakt / Vorteiler / Zählwerte = 8000000Hz / 1 / 200 = 40000Hz
Ist auch diese Frequenz zu hoch kann man den nächsten Prescaler verwenden, wieder einmal mit
Clear_Timer = 1 und einmal ohne.
Zu guter Letzt kann man die Frequenz noch durch den Quarz selbst beeinflussen.
Mehr Möglichkeiten die Frequenz zu beeinflussen ist hier nicht möglich (Ausnahme andres Quarz).
Damit sind wir dann schon bei einem neuen Sonderfall, bei dem die PWM-Frequenz festgelegt wird
und sich daraus die Auflösung der PWM ergibt.
Mit der Festlegung des höchsten Zählerwerts bzw. der Anzahl der Zählerwerte kann man die Auflösung bestimmen.
Möchte man eine 4-Bit PWM, also 16 Zählwerte, muss der Top-Wert logisch 15 sein.
Gleiches mit 5-Bit PWM, das sind 32 Zählschritte, bei 6-Bit 64 Zählschritte.
4.2 PWM mit fixer Frequenz
Das Pendant zur PWM mit fester Auflösung ist die PWM mit fixer Frequenz.
Auch hierbei gibt es Einschränkungen bezüglich der PWM-Auflösung.
Wieder ein Beispiel.
Wir möchten eine PWM-Frequenz von 16kHz erreichen bei einem Systemtakt von 8MHz.
Logischerweise müssen wir nun mit Prescaler und Zählerauflösung (Anzahl Zählschritte)
jonglieren, um dies zu erreichen.
1. Rechnung mit Prescaler = 1
Bekannte Formel:
PWM-Frequenz = Systemtakt / Vorteiler / Zählschritte
Zählschritte ist der Wert bei dem der Zähler überläuft.
Wir stellen die Formel um auf Zählerschritte (Auflösung)
Der Zähler müsste in dem Fall bis 500 zählen können. Timer1 kann das, Timer2 nicht.Was tun? Auf Timer1 gehen? - Ist eine Möglichkeit.
2. Rechnung mit Prescaler = 8
Man kann aber mal schauen, was mit Prescaler 8 heraus kommt.
Der Zähler müsste nun bei 62,5 auf 0 springen. Entweder man entscheidet sich für 62 oder für 63.Wenn die Frequenz nun genau auf 16000Hz liegen muss, sollten wir ein anderen Systemtakt ausprobieren.
3. Rechnung mit Quarz = 4MHz und Prescaler 1
Nehmen wir mal ein 4MHz Quarz, dann ergibt sich mit Prescaler 1 folgendes:
Das geht sauber auf. Damit können nun exakt die 16kHz erreicht werden.
Da der Zähler bei 250 Überläuft, können folglich Werte von 0 - 249 dem OC2B-Register als
Tastgrade zugewiesen werden. Die Auflösung wäre nun in 250 Stufen (0 - 249).
Natürlich soll das auch ausprobiert werden.
Dazu wurde das Programm so geändert:
BASCOM Source Code: Fast-PWM mit fester Frequenz
- ' Generierung einer PWM mit festen Frequenz von 16kHz
- ' Timer-Mode 7, Fast-PWM
- $Regfile = "m168def.dat"
- $Crystal = 4000000 ' andere Takt!
- ' PWM mit Timer2
- ' Frequenzausgabe an OC2B
- ' Der Pin wird automatisch als Ausgang konfiguriert.
- Config Timer2 = PWM , Prescale = 1 , Compare_B_PWM = Clear_Up , Clear_Timer = 1 ' Fast-PWM
- Set TCCR2B.WGM22
- OCR2A = 250 - 1 ' 250 Schritte, Zählweise ab Null, daher -1 (0 - 249)
- OCR2B = 5 ' Tastverhältnis einstellen
- Do
- NOP
- Loop
Hier das Oszillogramm von obigem Programm. Die 16kHz werden exakt erreicht.
05 - Fast-PWM_Frequenz_16kHz.jpg
An dieser Stelle möchte ich meine Ausführungen zur Timer-Berechnung abschließen.
Ich hoffe ich konnte einige Berechnungs-Grundlagen vermitteln.
Sollten Fehler in diesem Tutorial sein, bitte PN an mich.
Mitch64.
Edit
01.01.2021 Option Clear_Timer in den Timer-Konfigurationen mit Unterstrich versehen. Der Code-Explorer in Bascom bemängelt das.
18,096 times viewed