Forum: Mikrocontroller und Digitale Elektronik 89S8252 PWM mit Timer generieren


von Thomas F. (tommy_fux)


Lesenswert?

Hallo an Alle,
ich bin neu in diesem Forum und programmiere auf einem Atmel 89S8252 in
Assembler.(bin noch Anfänger)
Ich möchte eine PWM generieren mit Hilfe von Timer0 und Timer1.
- beide Timer laufen im Betriebs-Modus2
- Timer0 wird mit 0 nachgeladen
- in der INT von Timer0 wird TH1 z.b. mit 128 vorgeladen,das
  Timerrunbit von Timer1 gesetzt und mein Portpin (der die PWM
  ausgibt)
                        mov   TH1,PWM_Value
          setb  TR1
          setb  PWM_Out

- in der INT von Timer1 wird das Timerrunbit von Timer1 und der
  Portpin für die PWM gelöscht

                        clr  TR1
      clr  PWM_Out

Das ganze funktioniert super so lange ich TH1 mit einem Wert von 255-15
vorlade. Bei Werten von 14-0 habe ich nicht nur kurze Ausschaltimpulse
sondern auch lange dazwischen. z.B. 3x kurz ok und dann aber 1x lang
dann wieder 3x kurz (ganz symetrisch).
Bei anderen Werten zwischen 0-14 kommt ein völlig vermatschtes Signal
am Portpin an.
Wieso ist das so?
Gruß Tommy

von Cri Gri (Gast)


Lesenswert?

hab auch interesse an diesem Beitrag!

von Ralf (Gast)


Lesenswert?

Ich könnte mir vorstellen, dass bei 0-14 deswegen Müll rauskommt, weil
dann der Timer-Interrupt schneller kommt als die Interrupt-Routine
dauert. Das heisst, die Zeit zum Abarbeiten der Interrupt-Routine ist
größer als der eingestellte Timer-Interrupt. Das könnte einen
Stack-Überlauf bewirken.

Setzt du im Timer1-Interrupt auch das TR0-Bit? Oder läuft ein Timer
ständig?

Warum machst du das mit zwei Timern? Nimm doch nur einen Timer und zwei
1-Byte-Variablen. Eine Variable ist die ON-Zeit, die andere die
OFF-Zeit. Welche Variable du ins Reload-Register lädst, kannst du
abhängig machen vom aktuellen Zustand des Ausgangs-Pins.
Die Summe beider Variablen ist logischerweise die Frequenz der PWM.

Vorteil dieser Art wäre meiner Meinung nach,dass du einen Timer sparst,
und dass du einen größeren Bereich abdecken kannst.

Ralf

von Jack B. (jackbraun)


Lesenswert?

Das ganze funktioniert nur so lange, wie der T1-Int. früher als der
von Timer0 kommt. Beim Überlauf von T0 werden in der ISR 4 Befehle
ausgeführt: mov TH1, PWM_value (2 Zyklen)
            setb TR1           (1)
            setb PWM-out       (1)
            Reti               (2)
Währenddessen ist Timer0 aber schon bei 6 --> wenn TH1 mit einem hohen
Wert geladen wird, kommt Timer1 zu spät.

von Jack B. (jackbraun)


Lesenswert?

>wenn TH1 mit einem hohen Wert geladen wird
muß natürlich "mit einem niedrigen Wert" heißen

von Ralf (Gast)


Lesenswert?

@Jack:

Deswegen mein Vorschlag, nur einen Timer mit zwei verschiedenen
Variablen zu verwenden...

Ralf

von Jack B. (jackbraun)


Lesenswert?

@Ralf:

Deinen Beitrag hab ich erst gesehen nachdem ich meinen abgeschickt
hatte. Natürlich kann man es mit einem Timer machen, der Vorteil bei
zwei liegt aber in der höheren Frequenz und in der einfacheren
Steuerung. Die Randbereiche (sehr kurze on- und off-Zeit) braucht
man sowieso nicht. Ich hab damit eine Funkfernsteuerung für eine
Märklin-Lok gemacht (Spur 1).

von peter dannegger (Gast)


Lesenswert?

Ich hätte hier noch ne PWM-Version, die sehr schnell ist:

http://home.tiscali.de/peterd/appl/soft/c51/pwm/index.htm


Peter

von Thomas F. (tommy_fux)


Lesenswert?

Hallo,
erstmal danke für die Hilfe von euch!

@Ralf: Ne ich setze das TR0-Bit nicht im Timer1-Interrupt - der Timer0
läuft ständig. Finde deinen Vorschlag mit nur einem Timer echt gut
werde das gleich mal ausprobieren.

@Jack: Danke dir für die ausführliche Erkärung jetzt ist mir klar warum
das nicht funktioniert.

@Peter: Dank dir auch für deinen Link leider war das Beispiel nur in C
und nicht in Assembler.

Nochmal danke.

Gruß Tommy

von Ralf (Gast)


Lesenswert?

@Thomas:

Wichtig ist bei der Ein-Timer-Lösung, dass du niemals einen Reload-Wert
einsetzt, der den Timer schneller auslöst als die Interrupt-Routine
dauert. Sonst bekommst du einen Stack Overflow.

Ralf

von peter dannegger (Gast)


Lesenswert?

"Sonst bekommst du einen Stack Overflow."


Nein, sowas geht beim 8051 nicht !

Du kannst maximal soviel Interrupts kellern, wie Du
Interruptprioritäten benutzt, dann ist definitiv Schluß.

Die Hardware zählt die RETIs mit. Ohne RETI, kein neuer Interrupt
gleicher oder niederer Priorität.

Sehr clever und sehr sicher dieser 8051.


Peter

von Ralf (Gast)


Lesenswert?

@Peter:

Oh verflixt, stimmt ja... Hab ich ganz vergessen...
Sorry...

Ralf

von Thomas F. (tommy_fux)


Lesenswert?

Hallo,

@Ralf: Ja dann kommt da warscheinlich wieder so ein vermatschtes Signal
raus wie ich es schon hatte.

@Peter: Aber merkt sich der MC denn nicht wenn ein zweiter INT
ausgelöst wird? Wenn ich die Funktionen von INTs richtig verstanden
habe kann ein INT höherer Priorität einen niedrigeren unterbrechen und
im Anschluss wird der niedrigere weiter abgearbeitet oder? Und wenn ein
INT gleicher Priorität kommt merkt der MC sich das nicht?
z.B. Timer0 INT wird ausgelöst und während dieser abgearbeitet wird
kommt der Timer1 INT (beide die gleiche Priorität)geht mir dann Timer1
INT verloren? Sorry für die vielen Fragen aber als Anfänger ist das
alles nicht so einfach.

Danke euch für die klasse Hilfe!

Gruß Tommy

von Ralf (Gast)


Lesenswert?

Nein, es geht dir nichts verloren.
Timer 0 ist von sich aus schon höher priorisiert als Timer 1.
Das heisst, wenn du die Prioritäten nicht änderst, darf Timer 0 immer.

Bezüglich Interrupts gleicher Prioritäten, der aktuelle Interrupt wird
nicht deswegen unterbrochen, aber der Controller merkt sich, dass da
noch ein Interrupt abgearbeitet werden soll, und startet nach Ablauf
der letzten Interrupt-Routine gleich die nächste Interrupt-Routine.
Geht also nix verloren.

Guck mal hier, vielleicht hilft dir das auch noch:

http://www.atmel.com/dyn/resources/prod_documents/doc0509.pdf
http://www.atmel.com/dyn/resources/prod_documents/doc4316.pdf

Im Kapitel 2.16 vom Hardware Manual steht die Sache mit den Interrupts
erklärt. Da steht auch, wie es funktioniert, wenn zwei gleich
priorisierte Interrupts gleichzeitig auftreten, und welcher von denen
dann zuerst abgearbeitet wird...

HTH

Ralf

von peter dannegger (Gast)


Lesenswert?

"Aber merkt sich der MC denn nicht wenn ein zweiter INT ausgelöst
wird?"

Jede Interruptquelle hat ein Interrupt-Pending-Flag und solange dieses
gesetzt ist, wird der Interrupthandler angesprungen, sobald es erlaubt
ist und wenns 10 Jahre dauert.

Man muß Interruptquellen auch nicht als Interrupts bearbeiten, sondern
kann auch auf dieses Flag pollen und dann die entsprechende Funktion
aufrufen (z.B. UART im Polling-Mode).


Peter

von Thomas F. (tommy_fux)


Lesenswert?

Hallo,

danke für die super Unterstützung! So mach es noch mehr Spaß.
Ich hoffe ich darf in Zukunft euch mal wieder mit meinen Anfängerfragen
nerven.

Gruß Tommy

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.