Forum: Mikrocontroller und Digitale Elektronik Pseudo-PWM mit Interrupts


von Tim (Gast)


Lesenswert?

Guten Tag,

an meinem ATMega16 haben ich einen Ausgang, den ich über einen 
Variableninhalt steuern möchte.
Wenn der Variableninhalt z.B. 0xFF ist, so soll der Ausgang dauerhaft an 
sein. Bei einem 0x00 dauerhaft aus und bei einem 0x80 dementsprechend 
ca. 50% an.
Ich habe keine Idee wie ich die ISR gestalten müsste, damit ich dieses 
Resultat erhalte.

Hat da jemand eine Lösung für?

von K. S. (the_yrr)


Lesenswert?

ist noch ein Timer frei?
welche Frequenz soll es werden?
Was für eine ISR meinst du?

von Tim (Gast)


Lesenswert?

Ich habe noch alle Timer frei.
Bei der Frequenz habe ich so an 1kHz gedacht.

von STK500-Besitzer (Gast)


Lesenswert?

klingt nach einer Hausaufgabe.
Deine ISR wird regelmäßig aufgerufen (Frequenz darfst du dir 
ausrechnen).
In der ISR zählst du eine Veriable hoch.
Entspricht sie deinem Grenzwert, schaltest du den Ausgang um.
Irgendwann hat die Variable den oberen Grenzwert (Überlauf...) erreicht, 
dann schaltest du den Ausgang wieder.

Vorher noch die Abfrage, ob der Sollwert einem deiner beiden Grenzwerte 
entspricht, und entsprechend den Ausgang schalten.

von Georg M. (g_m)


Lesenswert?

Tim schrieb:
> Ich habe noch alle Timer frei.

Und warum soll das dann Pseudo-PWM sein?

von c-hater (Gast)


Lesenswert?

Georg M. schrieb:
> Tim schrieb:
>> Ich habe noch alle Timer frei.
>
> Und warum soll das dann Pseudo-PWM sein?

Naja, "Pseudo-PWM" ist es ja sowieso nicht, auch eine in Software 
realisierte PWM-Lösung ist natürlich einfach nur PWM und nix anderes.

Software PWM kann durchaus sinnvoll sein. Immer dann, wenn man viele 
PWM-Kanäle braucht. Und natürlich insbesondere dann, wenn man mehr 
PWM-Kanäle braucht, als die verfügbaren Timer anzubieten haben.

Oder aber auch, wenn man eine höhere Auflsung braucht, als die 
verfügbaren Timer anzubieten haben.

von K. S. (the_yrr)


Lesenswert?

STK500-Besitzer schrieb:
> klingt nach einer Hausaufgabe.

find ich auch, daher gibts weitere Tipps auch nur auf Nachfrage wenn ein 
Grundkozept steht.

Zwei Fragen hätte ich aber noch. Welche Sprache solls denn werden, und 
soll es eine Fast PWM (nur hochzählen) oder eine Phase Correct PWM (hoch 
und runterzählen) werden?

c-hater schrieb:
> Software PWM kann durchaus sinnvoll sein.

auf nem Mega16 mit allen Timern unbenutzt und nur 8 bit eher nicht 
wirklich, klingt zu sehr nach Hausaufgabe. Oder Anfänger mit 
halbfertigem Ansatz, dann bitte das wirkliche Problem schildern (was 
soll die PWM tun, wer ändert wann den Wert usw.) und nicht den gewählten 
Lösungsweg. Dann gibt es sehr viel Aussagekräftigere Hilfe.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

K. S. schrieb:

> auf nem Mega16 mit allen Timern unbenutzt und nur 8 bit eher nicht
> wirklich

Naja, der Kracher ist der Mega16 mit maximal 4 PWM-Kälen in Hardware 
(davon nur zwei in 16Bit-Auflösung) ja nun auch nicht wirklich. Da 
könnte durchaus mal der Wunsch nach einer Software-PWM aufpoppen...

> klingt zu sehr nach Hausaufgabe.

Wäre durchaus möglich. Aber ich habe ihm ja auch keinen Code geliefert, 
er muss sie also immer noch alleine erledigen ;o)

von Tim (Gast)


Lesenswert?

Hausaufgabe? Okay. Wie putzig :)

Ich habe mir tatsächlich auch schon etwas überlegt, aber das macht 
meiner Meinung nach eher weniger Sinn, weshalb ich auf das posten 
verzichtet hatte.
1
volatile uint8_t percent = 40 * 255 / 100;  // => 40% an, 60% aus
2
ISR(TIMER0_OVF_vect) 
3
{
4
  static uint8_t cnt = 0;
5
  
6
  if(cnt >= percent)  PORTA &= ~(1 << PA7);
7
  else         PORTA |=  (1 << PA7);
8
9
  cnt++;
10
}

Mir gefällt an dieser Lösung aber nicht, dass im jedem Aufruf auch die 
Bedingung überprüft wird. Gibt es dafür eine elegantere Lösung?

von STK500-Besitzer (Gast)


Lesenswert?

Tim schrieb:
> Gibt es dafür eine elegantere Lösung?

Ja, mit einem Timer. Der macht nichts anderes.

von Joe F. (easylife)


Lesenswert?

Tim schrieb:
> Mir gefällt an dieser Lösung aber nicht, dass im jedem Aufruf auch die
> Bedingung überprüft wird. Gibt es dafür eine elegantere Lösung?

Die Bedingung zu überprüfen würde mich weniger stören, als jedes mal den 
Port zu updaten.
Ausserdem musst du noch einen Spezialfall (entweder Dauer-low oder 
Dauer-high) behandeln.

Vorschlag:
1
volatile uint8_t pwm_duty = 102;  // 40% an, 60% aus
2
3
ISR(TIMER0_OVF_vect) 
4
{
5
  static uint8_t cnt = 0;
6
7
  if (cnt == 0)
8
  {
9
    if (pwm_duty > 0)
10
      PORTA |=  (1 << PA7); // low->high
11
    else
12
      PORTA &= ~(1 << PA7); // stay low
13
  }
14
  else if (cnt == pwm_duty)
15
      PORTA &= ~(1 << PA7); // high->low
16
17
  cnt++;
18
}

von c-hater (Gast)


Lesenswert?

Tim schrieb:

> Mir gefällt an dieser Lösung aber nicht, dass im jedem Aufruf auch die
> Bedingung überprüft wird. Gibt es dafür eine elegantere Lösung?

Etliche. Praktisch alle davon wurden bereits hier oder in "Projekte und 
Code" gezeigt. Das Grundprinzip bleibt allerdings immer das Gleiche. Die 
verschiedenen Implementierungen unterscheiden sich nur darin, an welcher 
Stelle die Bedingung geprüft wird und wie deutlich das für einen 
Programmier-Laien noch erkennbar ist, dass da irgendwo was geprüft wird.

Die Prüfung an sich ist aber völlig unverzichtbar. Das liegt in der 
Natur des Problems...

von K. S. (the_yrr)


Lesenswert?

Tim schrieb:
> Mir gefällt an dieser Lösung aber nicht, dass im jedem Aufruf auch die
> Bedingung überprüft wird. Gibt es dafür eine elegantere Lösung?

naja, für nur einen 1 Kanal PWM nur bedingt:

- du nimmst einen Timer mit Overflow sowie Compare Match Interrupt, in 
einem setzt du den Ausgang, im anderen löscht du den Ausgang wieder. ist 
dann aber eine Hardware PWM mit Umwegen. Vorteil ist es funktioniert 
auch mit mehreren PWM Kanälen, Beispiel weiter unten hier: 
https://www.mikrocontroller.net/articles/Soft-PWM

- du lässt es so wie es ist, der Overhead um die ISR funktion auzurufen 
ist wahrscheinlich eh länger als die ISR selber.

- Du speicherst bei Änderung der PWM 256 Werte in einem Array, und 
schiebst die dann in der ISR nur raus, ist aber Aufwendiger und 
ineffizienter als Testen. Weiterhin musst du die Aktualisierung dieses 
Arrays synchronisieren, sonst bekommst du Glitches (und wenn du alle 
interrupts währenddessen einfach anhältst kannst du auch Glitches 
bekommen)

c-hater schrieb:
> Die Prüfung an sich ist aber völlig unverzichtbar. Das liegt in der
> Natur des Problems...
da kommst du nicht drum rum

bei 1kHz PWM und 8bit brauchst du einen entsprechend oft aufgerufenen 
Interrupt, da bleibt echt kaum Zeit übrig. Rechne mal selber nach, 
vergiss nicht die Zyklen für JMP/RETI und Register sichern, das wird 
schon eng. Guck mal in die Listing Files vom GCC (wenn du den 
Verwendest), dann siehst du wie lang die ISR wirklich ist. Daher würde 
ich zu dem Ansatz mit Timer raten.

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.