Forum: Mikrocontroller und Digitale Elektronik Soft-PWM mit Timer richtiger Modus?


von Bernd (Gast)


Lesenswert?

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

von Hannes L. (hannes)


Lesenswert?

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.

...

von Bernd (Gast)


Lesenswert?

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ß

von Karl H. (kbuchegg)


Lesenswert?

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.

von Hannes L. (hannes)


Lesenswert?

> 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"

...

von Bernd (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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
}

von Hannes L. (hannes)


Lesenswert?

> 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.

...

von Bernd (Gast)


Lesenswert?

@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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Hannes L. (hannes)


Lesenswert?

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
Noch kein Account? Hier anmelden.