Hallo ich bin fortgeschrittener Anfänger und habe mich jetzt durch die zahlreichen Tutorials zur Software-PWM gekämpft. Jedoch habe ich noch ein paar Fragen. Nochmal kurz ne Zusammenfassung: Also bei der Software PWM ist es ja so, dass im Interrupt des Timers ein Zähler jeweils inkrementiert wird. Weiter wir dieser Zählerstand mit dem des gewünschten PWM-Wertes verglichen und dementsprechend der Ausgang geschaltet. Mir ist jetzt nicht ganz klar wie dieser Ablauf mit folgenden Begriffen zusammenhängt: - PWM-Frequenz - PWM-Stufen - PWM-Auflösung weiter besteht ja die Möglichkeit den 8bit oder 16bit Timer zu verwenden. weche Rolle spielt dies für die Software-PWM? Des weiteren besteht die möglichkeit den Timer im normalen Modus zu betreiben und dann den CTC Modus. Spielt es eine Rolle ob ich meine Ausgänge im normalen modus im overflow schalte oder im CTC modus im Compare interupt? mir würde es helfen wenn ich hierzu einen kleinen Überblick bekommen könnte :) Hoffe es sind fürs erste nicht all zu viele Fragen
Bernd wrote: > Hallo > > ich bin fortgeschrittener Anfänger und habe mich jetzt durch die > zahlreichen Tutorials zur Software-PWM gekämpft. > Jedoch habe ich noch ein paar Fragen. > > Nochmal kurz ne Zusammenfassung: > > Also bei der Software PWM ist es ja so, dass im Interrupt des Timers ein > Zähler jeweils inkrementiert wird. > Weiter wir dieser Zählerstand mit dem des gewünschten PWM-Wertes > verglichen und dementsprechend der Ausgang geschaltet. > > Mir ist jetzt nicht ganz klar wie dieser Ablauf mit folgenden Begriffen > zusammenhängt: > > - PWM-Frequenz Darunter verstehe ich die Frequenz, die am PWM-Pin entsteht. > - PWM-Stufen Darunter verstehe ich die Anzahl der Stufen zwischen 0 und Maximum. > - PWM-Auflösung Darunter verstehe ich die Anzahl der Stufen zwischen 0 und Maximum, wenn diese einer Zweierpotenz entsprechen. Eine 6-Bit-PWM hat also 64 Stufen, eine 8-Bit-PWM 256 Stufen. > > weiter besteht ja die Möglichkeit den 8bit oder 16bit Timer zu > verwenden. > weche Rolle spielt dies für die Software-PWM? Der Timer (egal ob 8-Bit oder 16-Bit) sorgt für einen Interrupt in genau definierten Zeitabständen, also für den Aufruf der ISR in einem stabilen Takt. > Des weiteren besteht die möglichkeit den Timer im normalen Modus zu > betreiben und dann den CTC Modus. Im CTC-Modus wird der Zählumfang des Timers per Hardware begrenzt. Beim Erreichen des TOP-Wertes wird der Timer automatisch gelöscht. Das spart Programmcode (und auch etwas Zeit), blockiert aber die anderen Features des Timers. Ob CTC sinnvoll ist, entscheidet der Einzelfall, denn ein Controller soll meist noch ein paar Dinge mehr tun als nur eine PWM zu erzeugen. > > Spielt es eine Rolle ob ich meine Ausgänge im normalen modus im overflow > schalte oder im CTC modus im Compare interupt? Nein, erstmal nicht. Allerdings erreicht man nicht in jeder Timer-Betriebsart einen wirklich jitterfreien Takt. Ich bevorzuge (inzwischen) den Compare-Interrupt. Er erlaubt jitterfreien Betrieb bei gleichzeitiger Nutzung des zweiten Compare-Interrupts und des ICP-Interrupts. Das Festlegen des nächsten Interrupt-Termins erfolgt dabei durch Aufaddieren des Intervalls auf den aktuellen Stand des OC-Registers. Den CTC-Mode nehme ich nur, wenn ich die anderen Features des benutzten Timers nicht brauche, was nicht allzuoft vorkommt. > > mir würde es helfen wenn ich hierzu einen kleinen Überblick bekommen > könnte :) > > Hoffe es sind fürs erste nicht all zu viele Fragen Ich hoffe, ich konnte helfen. ...
Erstmal Danke, Ok ich breche das ganze jetzt mal von groß nach klein auf. die Frequenz legt fest wie häufig sich ein Duty-Cycle also das Tastverhältnis High-Low pro Sekunde wiederholt. __ __ ___| |___| |__ ... ^_______^ Duty-Cycle Hoffe das ist so richtig. Diese Frequenz wird im CTC bzw. normalen Modus des Timers, unabhängig ob 8bit oder 16 bit Timer, durch den Prescaler und/oder die entsprechende Wahl des OCxR Registers bestimmt. Dadurch entstehen die regelmäßigen Impulse -> ISR's Damit ist es aber noch kein PWM Signal. Der maximalwert, also 100% Duty-Cycle wird durch die Wahl des Timers definiert (8bit / 16bit)? Aber wo liegt jetzt genau der Unterschied zwischen PWM-Stufen und PWM Auflösung? Nochmal zum Timer-Modus: 1) Normal Hierbei ist es doch so, dass bei jedem Overflow Interupt ein Register hochgezählt wird und bei Überlauf rückgesetzt wird. 2) CTC Hierbei wird beim erreichen des Vergleichswertes ein Interupt ausgelöst. Der Overflow Interupt ist hierbei zu vernachlässigen? Wie bei Modus 1 wir auch innerhalb des Interuptes ein Zählregister erhöht. Wann wird dieses wieder auf Null gesetzt? Wieso muss ich innerhalb des Interuptes den Timer Compare Wert ändern? Kann der nicht konstant bleiben, weil ja dieser die PWM Frequenz bestimmt und diese auch gleich bleibt? Muss ich den OCx Pin bei Soft-PWM abschalten? bin da grad etwas verwirrt... Gibt es ein Beispiel für beide Modi, speziell Initialisierung und Interupthandling? Gruß
Bernd wrote: > Erstmal Danke, > > Ok ich breche das ganze jetzt mal von groß nach klein auf. > > die Frequenz legt fest wie häufig sich ein Duty-Cycle also das > Tastverhältnis High-Low pro Sekunde wiederholt. > _ ___ > ___| |___| |__ ... > ^_______^ > Duty-Cycle > > > Hoffe das ist so richtig. Kann man so sagen > Diese Frequenz wird im CTC bzw. normalen Modus > des Timers, unabhängig ob 8bit oder 16 bit Timer, durch den Prescaler > und/oder die entsprechende Wahl des OCxR Registers bestimmt. Dadurch > entstehen die regelmäßigen Impulse -> ISR's Ja > > Damit ist es aber noch kein PWM Signal. Richtig. Bis jetzt hast du nur einen regelmässigen Interrupt. Nicht mehr und nicht weniger. > > Der maximalwert, also 100% Duty-Cycle wird durch die Wahl des Timers > definiert (8bit / 16bit)? Jein. In den normalen Timermodi stimmt das. Im CTC Modus legst du ja selbst fest wie weit der Zähler zählen soll, bevor er wieder auf 0 zurückgesetzt werden soll. Das ist also nicht unbedingt eine 2-er Potenz. > > Aber wo liegt jetzt genau der Unterschied zwischen PWM-Stufen und PWM > Auflösung? Ich würde mal sagen: Es gibt keinen. Die beiden Wörter sind im weitesten Sinne synonym. Eine 8-Bit PWM (= Auflösung) hat naturgemäss 256 Stufen (=Stufen) > > Nochmal zum Timer-Modus: > > 1) Normal > Hierbei ist es doch so, dass bei jedem Overflow Interupt ein Register > hochgezählt wird und bei Überlauf rückgesetzt wird. Moment: reden wir jetzt von einer PWM oder vom Timer allgmein? Wenn wir vom Timer allgemein reden: nein. Es passiert einfach nur ein Overflow. Und an diesen Overflow kann man einen Software Interrupt klemmen, der alles mögliche machen kann. Zb. kann er ein Register hochzählen. > > 2) CTC > Hierbei wird beim erreichen des Vergleichswertes ein Interupt ausgelöst. > Der Overflow Interupt ist hierbei zu vernachlässigen? Der kann logischerweise nicht erreicht werden, weil der Zähler ja nicht bis zum Overflow zählt. > Wie bei Modus 1 wir auch innerhalb des Interuptes ein Zählregister > erhöht. > Wann wird dieses wieder auf Null gesetzt? Genau gleich wie beim Overflow Fall. Der einzige Unterschied zwischen Overflow Modus und CTC Modus besteht darin, dass im Overflow Modus der Timer bis zum Overflow zählt bevor er wieder auf 0 gehtund im CTC Modus sag ich dem Timer einen konkreten Zählerstand bei dem er auf 0 gesetzt werden soll. Bei einem 8 Bit Zähler tritt der Overflow Interrupt beim Zählerstand 256 (=0) auf, bei einem 16 Bit Zähler bei einem Zählerstand von 65536 (=0), während ich im CTC Modus einen Zählerstand, sagen wir mal 137 vorgeben kann, bei dem dann ein Interrupt auftritt (der dann aber ein Compare Match Interrupt ist) > Wieso muss ich innerhalb des Interuptes den Timer Compare Wert ändern? > Kann der nicht konstant bleiben, weil ja dieser die PWM Frequenz > bestimmt und diese auch gleich bleibt? Hannes hat schon etwas weiter gedacht und eine andere Variante einer Software PWM im Kopf als die an die du denkst.
> Hannes hat schon etwas weiter gedacht und eine andere Variante > einer Software PWM im Kopf als die an die du denkst. Eher eine andere Variante der effizienten Ressourcen-Nutzung des 16-Bit-Timers. ;-) Mit der eigentlichen Software-PWM hat das noch nichts zu tun, nur mit der Bereitstellung eines Interrupt-Taktes. Bernd, ich habe die Vermutung, dass Du Hardware-PWM und Software-PWM noch etwas durcheinander bringst. Bei Software-PWM erzeugst Du mittels eines Timers einen zyklischen Interrupt der nix anderes tut, als Deine (selbst zu schreibende) ISR (Interrupt-Service-Routine) aufzurufen. Mehr tut der Timer nicht, alles andere ist Deine Aufgabe. Damit der Timer das machen kann, gibt es verschiedene Betriebsarten. Der Timer kann aufwärts zählen und bei Überlauf den Interrupt auslösen. In der ISR muss der Timer auf den Startwert voreingestellt werden. Da der Interrupt zum Aufruf nicht immer exakt dieselbe Zeit braucht, können Fehler beim Voreinstellen entstehen. Diese kann man zwar minimieren, indem man den Voreinstellwert auf den tatsächlichen Timerwert aufaddiert, aber das Gelbe vom Ei ist das immer noch nicht. Meine älteren Programme nutzen diese Betriebsart, damals wusste ich es noch nicht besser. Der Timer kann aufwärts zählen und bei Compare-Match einen Interrupt auslösen. Im CTC-Mode wird dabei der Timer automatisch auf 0 gesetzt. Die Interrupt-Folge ist daher sehr exakt. Allerdings verhindert dieser CTC-Mode das Benutzen des zweiten OC-Interrupts und des ICP-Interrupts (Impulsbreitenmessung). Also verzichtet man (ich) gern auf den CTC-Mode und setzt den nächsten OC-Interrupt-Termin "von Hand". Dazu lese ich den Vergleichswert aus dem Compare-Register aus (das ist der "Termin", der diesen Interrupt ausgelöst hat), addiere das Intervall (die Anzahl Takte bis zum nächsten gewünschten Interrupt) dazu und schreibe den neuen Termin in das OC-Register zurück. Da sich der Inhalt des OC-Registers durch das Hochzählen des Timers NICHT verändert, spielt es (in gewissen Grenzen) keine Rolle, wie schnell der Interrupt die ISR aufrufen kann, es entstehen keine Verzögerungsfehler. Der Trumpf dieser Methode ist, dass der Zählerstand des Timers niemals per Software (oder Hardware) manipuliert wird, der Timer also immer im Kreis läuft. Dadurch ist es möglich, mit beiden OC-Interrupts desselben Timers unterschiedliche Interrupt-Frequenzen zu erzeugen und den Timer auch noch als Zeitstempel für den ICP-Interrupt zum Ausmessen eines ankommenden Impulses zu nutzen. Aber bis jetzt haben wir nur eine korrekte Folge von ISR-Aufrufen, mit Software-PWM hat das noch nix zu tun. Diese erreicht man, wenn man einen Zähler (PWM-Treppenzähler) hochzählt und dabei mit dem PWM-Wert (gewünschter Tastgrad) und dem PWM-Zählumfang (PWM-Stufen) vergleicht. Bei Erreichen des PWM-Zählumfangs wird der Zähler auf 0 gestellt (damit sind auch Zählumfänge erreichbar, die keine Zweierpotenzen sind) und der (die) Ausgang (Ausgänge) eingeschaltet. Bei Erreichen des Tastgradwertes wird der entsprechende Ausgang wieder ausgeschaltet. Ein Beispiel mit 8 PWMs findest Du hier: Beitrag "MENÜ-STEUERUNG" Es arbeitet aber noch mit Überlauf-Interrupt, das Beispiel ist ja schon recht alt. Beitrag "Re: Software PWM 8-fach" Beitrag "Software PWM auf 8 Kanälen" ...
nun nochmals danke, das hat mir schon geholfen. @Hannes Seh ich es dann richtig, dass eigentlich der CTC Modus wegen dem genauen Timing und der Jittereigenschaft zu bevorzugen ist? Um eine einfache PWM im CTC Modus zu erzeugen würde ich also wie folgt vorgehen. 1) Timer im CTC-Modus einstellen (OCx-Pin ausschalten) 2) Compare Register einmalig einstellen (Formel Datenblatt) 3) im Compare ISR ein Zählregister auf null setzen 4) Zählregister mit gewünschtem PWM-Wert vergleichen 5) Ausgang/Ausgänge ein-/auschalten 6) Zählregister inkrementieren 7) ISR verlassen und auf neuen Compare warten Hoffe das stimmt so, dann würde ich mal einen ersten Programmierversuch starten. Ob die Routine innerhalb der ISR effektiv ist, naja laut Tutorials gibts da glaub noch was besseres, aber fürs erste sollte des doch so funktionieren. Übrigens ich werde den Mega8 mit 16MHz verwenden und eine PWM-Frequenz von rund 120Hz einsetzen. Weiterhin programmiere ich in C.
Bernd wrote: > Seh ich es dann richtig, dass eigentlich der CTC Modus wegen dem genauen > Timing und der Jittereigenschaft zu bevorzugen ist? Nein. Ist völlig wurscht. Ob du den Timer im Overflow einen Interrupt auslösen lässt oder im Compare Match ist piep-schnurz-egal. Der einzige Unterschied: Mit dem Overflow bist du darauf festgenagelt dass der Timer einmal runumzählen muss, ein 8 Bit Timer also bis 256, ein 16 Bit Timer bis 65536 zählt, bis du einen Interrupt kriegst, während du im CTC Modus einen Wert vorgeben kannst, bis zu dem der Timer zählt. Aber letztendlich münden beide Methoden beim gleichen Ergebnis: taktgenau wird alle x-Takte ein Interrupt ausgelöst. Was anderes ist es, wenn man den Timer vorladen will: Niemand sagt ja, dass ich den Timer bei einem Overflow immer wieder bei 0 starten lassen muss. Der Timer macht das von alleine so. Aber ich kann ja auch in der ISR einen neuen Wert in das Timer Register laden, von dem aus der Timer weiterzählt. Wenn also bei einem 8-Bit Timer ein Overflow auftritt und ich in der ISR dann 155 in das Timer Register lade, dann zählt der Timer von 155 weiter bis zum nächsten Overflow bei 256. Dafür muss er den Timer aber nur 100 mal erhöhen und nicht 256 mal. Ich kriege also alle 100 Timerticks einen Interrupt. Nur: wie Hannes schon gesagt hat: Das gehtnicht besonders exakt, weil ja vom Auftreten des Overflow Interrupts bis zum neu setzen des Timer Registers auch Zeit vergeht und diese Zeitdauer nicht taktgenau konstant ist. > > Um eine einfache PWM im CTC Modus zu erzeugen würde ich also wie folgt > vorgehen. > 1) Timer im CTC-Modus einstellen (OCx-Pin ausschalten) Ja > 2) Compare Register einmalig einstellen (Formel Datenblatt) Ja > 3) im Compare ISR ein Zählregister auf null setzen Aber nur dann, wenn dein Zählregister seinen Maximalwert erreicht hat. > 4) Zählregister mit gewünschtem PWM-Wert vergleichen Ja > 5) Ausgang/Ausgänge ein-/auschalten Ja > 6) Zählregister inkrementieren Wird mit Punkt 3) kombiniert > 7) ISR verlassen und auf neuen Compare warten Ja Punkt 3) und Punkt 6) werden kombiniert ISR ( .... ) { Zaehler++; if( Zaehler == 64 ) Zaehler = 0; ... Jetzt hast du ein Zaehlregister welches immer von 0 bis 63 zaehlt. Das ist dein PWM Counter. Ist der vorgegebene PWM Wert darunter, wird der Ausgang eingeschaltet, ist er darüber wird der Ausgang ausgeschaltet
1 | // zum Beispiel: PWM am PORTB und dort an PB1
|
2 | #define PWM_PORT PORTB
|
3 | #define PWM_PIN PB1
|
4 | |
5 | volatile uint8_t PWMWert; // der Wert hier drinn regelt das |
6 | // PWM Verhaeltnis. Wertebereich: 0 .. 63
|
7 | uint8_t Zaehler; |
8 | |
9 | ISR ( .... ) |
10 | {
|
11 | Zaehler++; |
12 | if( Zaehler == 64 ) |
13 | Zaehler = 0; |
14 | |
15 | if( PWMWert > Zaehler ) |
16 | PWM_PORT &= ~( 1 << PWM_PIN ); // ausschalten |
17 | else
|
18 | PWM_PORT|= ( 1 << PWM_PIN ); // einschalten |
19 | }
|
> 2) Compare Register einmalig einstellen (Formel Datenblatt) Formeln sind da so 'ne Sache. Man sollte sie nur anwenden, wenn man sie (also die zugehörigen Zusammenhänge) auch versteht. Versteht man sie nicht, wendet man die Formel schonmal falsch an, versteht man die Zusammenhänge, dann reicht meist der Dreisatz aus... Ich bin daher kein Freund von "Formel-Lotto" ;-) > Weiterhin programmiere ich in C. Nunja, damit bin ich raus, denn ich programmiere nicht in C. Ist mir zu kryptisch. ...
@Hannes Nun ich habe nochmal das Datenblatt des Mega 8 bekniet. Da ist ja eben ne Formel für den Waveform Generator drin. Allerdings glaub ich jetzt auch dass die nur was bringt wenn man die wirklich versteht g Ok ich versuche mir dann selber mal die formel für meine Wunsch-PWM-Frequenz zu erstellen. F_PWM = F_CPU/(Prescaler*PWM_Stufen*OCRn) Ist das korrekt?
Bernd wrote: > Ok ich versuche mir dann selber mal die formel für meine > Wunsch-PWM-Frequenz zu erstellen. > > F_PWM = F_CPU/(Prescaler*PWM_Stufen*OCRn) > > Ist das korrekt? Probiers einfach aus. Ist ja nicht so, dass du den Untergang des besiedelten Abendlandes riskierst wenn die Formel falsch ist.
Bernd wrote: > @Hannes > > Nun ich habe nochmal das Datenblatt des Mega 8 bekniet. > Da ist ja eben ne Formel für den Waveform Generator drin. > > Allerdings glaub ich jetzt auch dass die nur was bringt wenn man die > wirklich versteht *g* > > Ok ich versuche mir dann selber mal die formel für meine > Wunsch-PWM-Frequenz zu erstellen. > > F_PWM = F_CPU/(Prescaler*PWM_Stufen*OCRn) > > Ist das korrekt? Das kommt schon hin. Wobei ich das ungern zusammenfasse, da mich neben der PWM-Frequenz auch die ISR-Frequenz interessiert, denn es bietet sich an, sie für andere zeitbestimmende Dinge mitzunutzen. Ich gehe da eben etwas praktischer ran, nicht ganz so abstrakt-wissenschaftlich. ...
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.