Timer-Berechnung - Tutorial

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

Aufgrund technischer Veränderungen ist der Mailverkehr innerhalb des Forums (Private Nachrichten) nur noch eingeschränkt möglich. Die Einschränkung ist notwendig, um zusätzliche Betriebskosten für das Forum zu vermeiden. Näheres zu den Hintergründen im Thread "Aktuelles zum Forum".Wir bitten um Verständnis.

Hinweis kann nach Kenntnisnahme deaktiviert werden!

  • In diesem Tutorial geht es um die Berechnung der Timer.
    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.

    BASCOM-Quellcode: Timer (Preload direkt gesetzt)

    1. ' Dieses Programm soll 40kHz am PortB.1 erzeugen.
    2. ' Es verwendet den berechneten Preload-Wert von 56 in der ISR.
    3. ' Der Preload-Wert wird in der ISR direkt gesetzt.
    4. $Regfile = "m168def.dat"
    5. $Crystal = 8000000 ' externes Quarz
    6. FrqOut Alias PortB.1 ' Ausgang zur Frequenzkontrolle
    7. Config FrqOut = Output
    8. Config Timer0 = Timer , Prescale = 1
    9. On OVF0 ISR_Timer0_Overflow
    10. Enable OVF0
    11. Enable Interrupts
    12. Do
    13. NOP
    14. Loop
    15. ' ISR-Routine
    16. ISR_Timer0_Overflow:
    17. Timer0 = 56 ' Preload mit berechnetem Wert
    18. Set FrqOut ' Puls ausgeben
    19. NOP
    20. NOP
    21. NOP
    22. NOP
    23. NOP
    24. NOP
    25. Reset FrqOut
    26. Return
    Alles anzeigen



    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-Quellcode: Timer (Preload aufaddiert)

    1. ' Dieses Programm soll 40kHz am PortB.1 erzeugen.
    2. ' Es verwendet den berechneten Preload-Wert von 56 in der ISR.
    3. ' Der Preloadwert wird allerdings zum Zählerwert aufaddiert.
    4. $Regfile = "m168def.dat"
    5. $Crystal = 8000000 ' externes Quarz
    6. FrqOut Alias PortB.1 ' Ausgang zur Frequenzkontrolle
    7. Config FrqOut = Output
    8. Config Timer0 = Timer , Prescale = 1
    9. On OVF0 ISR_Timer0_Overflow
    10. Enable OVF0
    11. Enable Interrupts
    12. Do
    13. NOP
    14. Loop
    15. ' ISR-Routine
    16. ISR_Timer0_Overflow:
    17. Timer0 = Timer0 + 56 ' Preload mit berechnetem Wert wird aufaddiert
    18. Set FrqOut ' Puls ausgeben
    19. NOP
    20. NOP
    21. NOP
    22. NOP
    23. NOP
    24. NOP
    25. Reset FrqOut
    26. Return
    Alles anzeigen

    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-Quellcode: Timer im CTC-Mode

    1. ' Dieses Programm soll 40kHz am PortB.1 erzeugen.
    2. ' Timer0 im CTC-Mode
    3. $Regfile = "m168def.dat"
    4. $Crystal = 8000000 ' externes Quarz
    5. FrqOut Alias PortB.1 ' Ausgang zur Frequenzkontrolle
    6. Config FrqOut = Output
    7. Config Timer0 = Timer , Prescale = 1 , Clear_Timer = 1
    8. OCR0A = 200 - 1 ' Frequenz wird hier eingestellt
    9. On OC0A ISR_Timer0_OC0A ' OC0A-Interrupt konfigurieren
    10. Enable OC0A ' OC0A-Interrupt zulassen
    11. Enable Interrupts
    12. Do
    13. NOP
    14. Loop
    15. ' ISR-Routine
    16. ISR_Timer0_OC0A:
    17. ' Preload des Timers entfällt im CTC-Mode
    18. Set FrqOut ' Puls ausgeben
    19. NOP
    20. NOP
    21. NOP
    22. NOP
    23. NOP
    24. NOP
    25. Reset FrqOut
    26. Return
    Alles anzeigen

    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-Quellcode: Einfache PWM (Phase Correct)

    1. ' Generierung einer 8-Bit PWM
    2. $Regfile = "m168def.dat"
    3. $Crystal = 8000000
    4. ' PWM mit Timer2
    5. ' Frequenzausgabe an OC2A
    6. ' Der Pin wird automatisch als Ausgang konfiguriert.
    7. Config Timer2 = PWM , Prescale = 1 , Compare_A_PWM = Clear_Up
    8. OCR2A = 5 ' Tastverhältnis einstellen
    9. Do
    10. NOP
    11. Loop
    Alles anzeigen
    (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:

    BASCOM-Quellcode: Fast-PWM einfach

    1. ' Generierung einer 8-Bit PWM im Fast-PWM Mode
    2. $Regfile = "m168def.dat"
    3. $Crystal = 8000000
    4. ' PWM mit Timer2
    5. ' Frequenzausgabe an OC2A
    6. ' Der Pin wird automatisch als Ausgang konfiguriert.
    7. Config Timer2 = PWM , Prescale = 1 , Compare_A_PWM = Clear_Up , Clear_Timer = 1
    8. OCR2A = 5 ' Tastverhältnis einstellen
    9. Do
    10. NOP
    11. Loop
    Alles anzeigen
    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)

    Quellcode

    1. Systemtakt 8000000Hz
    2. Zählschritte = ---------------------- = ------------- = 500
    3. Vorteiler * Frequenz 1 * 16000Hz

    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.

    Quellcode

    1. Systemtakt 8000000Hz
    2. Zählschritte = ---------------------- = ------------- = 62,5
    3. Vorteiler * Frequenz 8 * 16000Hz

    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:

    Quellcode

    1. Systemtakt 4000000Hz
    2. Zählschritte = ---------------------- = ------------- = 250
    3. Vorteiler * Frequenz 1 * 16000Hz

    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-Quellcode: Fast-PWM mit fester Frequenz

    1. ' Generierung einer PWM mit festen Frequenz von 16kHz
    2. ' Timer-Mode 7, Fast-PWM
    3. $Regfile = "m168def.dat"
    4. $Crystal = 4000000 ' andere Takt!
    5. ' PWM mit Timer2
    6. ' Frequenzausgabe an OC2B
    7. ' Der Pin wird automatisch als Ausgang konfiguriert.
    8. Config Timer2 = PWM , Prescale = 1 , Compare_B_PWM = Clear_Up , Clear_Timer = 1 ' Fast-PWM
    9. Set TCCR2B.WGM22
    10. OCR2A = 250 - 1 ' 250 Schritte, Zählweise ab Null, daher -1 (0 - 249)
    11. OCR2B = 5 ' Tastverhältnis einstellen
    12. Do
    13. NOP
    14. Loop
    Alles anzeigen
    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.

    13.327 mal gelesen