Forum: Mikrocontroller und Digitale Elektronik 8051 - Mal wieder eine Interruptfrage


von Tobias H. (pasdvn)


Lesenswert?

Hallo Community,

mein erster Post hier, deshalb erst einmal ein 'Hallo' in die Runde :) 
Tolle Seite/Forum. Hab schon viele nützliche Infos bei euch gefunden.

Bin gerade dabei was für einen 8051 zu schreiben (AT89C51CC03) und habe 
zwei grundsätzliche Fragen zur Interruptbehandlung. Hab schon eine ganze 
Weile gesucht, aber keine wirklich befriedigende Antworten gefunden.

In eurem Interrupt Tut steht folgendes:

"Beim AVR ist das das I-Bit (Interrupt) im Statusregister (SREG). Dieses 
Bit wirkt wie ein Hauptschalter und kann global die Ausführung aller 
Interrupts ein - und ausschalten. Das heisst aber nicht, dass während 
der Zeit der inaktiven Interrupts diese verloren gehen. Vielmehr wird 
das jeweilige Interruptbit gesetzt, und wenn die Interrupts wieder 
freigegeben werden wird der Interrupt ausgeführt. Verloren gehen 
Interrupts erst dann, wenn die Sperrzeit zu groß ist und währenddessen 
mehr als ein Interrupt vom selben Typ eintrifft."

Ist es auch beim 8051 so, dass ich z.B. kurzzeitig alle Interrupts 
ausschalte kann und nach dem wieder-einschalten die "angesammelten" 
Interrupts abgearbeitet werden? Anhand der Strukturschaltpläne des 
Interruptsystems im Datenblatt kann man eventuell davon ausgehen, aber 
sicher bin ich mir eben nicht.

Eine zweite Frage noch: Der 8051 besitzt nur 1 Interrupt für die UART, 
der sowohl das Senden als auch das Empfangen bedient. Sehe ich das 
richtig, das es damit bei Full-Duplex Anwendungen nicht möglich ist 100% 
sicheren Code zu schreiben (also in Bezug auf das Verschlucken eines 
Sende- oder Empfangsinterrupts)?
In allen Beispielen wird immer nur aufgeführt, dass man den Interrupt 
durch die beiden Bit's (TI und RI) unterscheiden kann, jedoch steht 
nirgendwo, dass das eigentlich problematisch ist, egal wie kurz die ISR 
ist.

von Ralf (Gast)


Lesenswert?

> In eurem Interrupt Tut steht folgendes:
> ...
Wenn du dich mit einem 8051 beschäftigt, schaue nicht bei anderen 
Controller-Architekturen nach Infos! Das bringt dich durcheinander, weil 
du die Infos mischen wirst!

> Ist es auch beim 8051 so, dass ich z.B. kurzzeitig alle Interrupts
> ausschalte kann und nach dem wieder-einschalten die "angesammelten"
> Interrupts abgearbeitet werden? Anhand der Strukturschaltpläne des
> Interruptsystems im Datenblatt kann man eventuell davon ausgehen, aber
> sicher bin ich mir eben nicht.
1) Beim 805x gibt es Interruptprioritäten. Ein höher priorisierter 
Interrupt unterbricht einen laufenden niederpriorisierten Interrupt. Man 
kann die Prio eines Interrupts je nach Derivat höher setzen.
2) Interrupts werden durch ihr eigenes Interrupt-Enable-Flag scharf 
geschalten und zusätzlich durch das globale Interrupt Enable Flag. D.h. 
wenn das IE-Flag gelöscht ist, gibt's GAR keinen Interrupt.
3) Es ist beim 8051 normalerweise nicht notwendig, einen Interrupt 
wieder zu deaktivieren. Kommt natürlich auf die Applikation an, aber im 
Normalfall ist es nicht nötig.

> Sehe ich das richtig, das es damit bei Full-Duplex Anwendungen nicht
> möglich ist 100% sicheren Code zu schreiben (also in Bezug auf das
> Verschlucken eines Sende- oder Empfangsinterrupts)?
Siehst du falsch :)

> In allen Beispielen wird immer nur aufgeführt, dass man den Interrupt
> durch die beiden Bit's (TI und RI) unterscheiden kann, jedoch steht
> nirgendwo, dass das eigentlich problematisch ist, egal wie kurz die ISR
> ist.
Das steht deshalb nirgends, weil nicht problematisch IST.
Der Sende-Interrupt wird beim Senden des Stopbits ausgelöst. Entweder 
schiebst du ein weiteres Byte in den Sendebuffer oder nicht. Wo soll es 
da Timing-Probleme geben.
Genauso beim Empfangen. Byte wegsichern, und gut :)

Weitere Fragen? :)

Ralf

von Tobias H. (pasdvn)


Lesenswert?

> Weitere Fragen? :)
Jap ;) und Danke erstmal für die flotte Antwort!

> 1) Beim 805x gibt es Interruptprioritäten. Ein höher priorisierter
> Interrupt unterbricht einen laufenden niederpriorisierten Interrupt. Man
> kann die Prio eines Interrupts je nach Derivat höher setzen.
> 2) Interrupts werden durch ihr eigenes Interrupt-Enable-Flag scharf
> geschalten und zusätzlich durch das globale Interrupt Enable Flag. D.h.
> wenn das IE-Flag gelöscht ist, gibt's GAR keinen Interrupt.
> 3) Es ist beim 8051 normalerweise nicht notwendig, einen Interrupt
> wieder zu deaktivieren. Kommt natürlich auf die Applikation an, aber im
> Normalfall ist es nicht nötig.

Die Sachen sind mir soweit klar. Nehmen wir aber an ich hab einige 
Befehle in einer niedrig Priorisierten ISR, für dessen Ausführung es 
dringend notwendig ist auch höher priorisierte Interrupts kurzzeitig zu 
deaktivieren. Tritt nun innerhalb dieses Code-Teils ein höher 
Priorisierter Interrupt auf... ist der dann für immer weg. oder "greift" 
der dann wieder nachdem ich die Interrupts wieder eingeschaltet habe 
(EA=1), mal unabhängig davon, ob das vom Code her sinvoll ist oder 
nicht.

> Das steht deshalb nirgends, weil nicht problematisch IST.
> Der Sende-Interrupt wird beim Senden des Stopbits ausgelöst. Entweder
> schiebst du ein weiteres Byte in den Sendebuffer oder nicht. Wo soll es
> da Timing-Probleme geben.
> Genauso beim Empfangen. Byte wegsichern, und gut :)

Folgende Überlegung:
RxD Interrupt kommt -> Sprung in die entsprechende ISR -> Überprüfung TI 
== 1 -> nein, also weiter -> TxD Interrupt kommt zufällig gerade jetzt 
(es passiert natürlich nix, weil wir noch in der ISR sind) -> SBUF auf 
Empfangspuffer sichern, weil TI ja 0 war -> ISR verlassen

So verschwindet der TxD Interrrupt im Nirvana, oder hab ich einen 
Denkfehler in der Überlegung?

von 8051-Anwender (Gast)


Lesenswert?

Weder der TxD noch der RxD verschwindet im Nirwana.
Es genügt am Anfang der Seriellen ISR zu Prüfen ob RxD oder TxD
ausgelöst hat. Ich ziehe den RxD vor, weil es nicht stört ein
Byte etwas später zu senden, als ein Empfangenes zu spät zu sichern.
Der serielle Int ist die Veroderung des RxD und TxD-Ints.
Ein neuer! TxD kann erst kommen, wenn ein Byte rausgeschoben wurde,
also kein Byte senden, kein Interrupt.
Hat während der Abarbeitung des einen Int, egal ob RxD oder TxD,
der andere Int. ausgelöst, wird nach der ISR ein weiterer Befehl des
Progs abgearbeitet und sofort wieder die Serielle ISR aufgerufen.

von Tobias H. (pasdvn)


Lesenswert?

> Hat während der Abarbeitung des einen Int, egal ob RxD oder TxD,
> der andere Int. ausgelöst, wird nach der ISR ein weiterer Befehl des
> Progs abgearbeitet und sofort wieder die Serielle ISR aufgerufen.

Ok. Das ist eindeutig! (auch wenn ich mir nicht erklären kann wie das 
dann hardwaremäßig realisiert wird, wenn es einfach eine Veroderung ist, 
wie es auch in den Datenblättern immer steht).

Danke für die Hilfe!

von Ralf (Gast)


Lesenswert?

> ...oder "greift" der dann wieder nachdem ich die Interrupts wieder
> eingeschaltet habe (EA=1), mal unabhängig davon, ob das vom Code her
> sinvoll ist oder nicht.
Richtig erkannt, wobei ich es (wenn ich es denn mal machen müsste) 
vorziehen würde, nur den relevanten (=höher priorisierten) Interrupt zu 
sperren.
Aber nochmal: Wenn die Interrupts richtig geschrieben sind besteht dazu 
m.E. keine Notwendigkeit.
Durch das Sperren des Interrupts wird ja nur verhindert, dass die 
Interrupt-Service-Routine angesprungen wird, die Flags, die den 
Interrupt auslösen sind ja nach wie vor aktiv, d.h. nach dem 
Freischalten wird der entsprechende Interrupt angesprungen. Aber 
Vorsicht, man sollte nicht zu lange sperren, weil nur ein Interrupt 
gespeichert wird, d.h. wenn du beispielsweise solange sperrst wie zwei 
Bytes brauchen, um empfangen zu werden, dann geht eins davon sicher 
flöten!

> auch wenn ich mir nicht erklären kann wie das dann hardwaremäßig
> realisiert wird, wenn es einfach eine Veroderung ist, wie es auch in den
> Datenblättern immer steht)
Nicht so kompliziert denken :)
Die Sendeschaltung löst setzt ein Flag (TI), wenn das Byte den seriellen 
Port inklusive Stopbit verlassen hat. Die Empfängerschaltung setzt ein 
Flag (RI) nach dem gemäß der eingestellten Baudrate erwarteten Zeitpunkt 
des Stopbits.
Beide Flags zusammen werden verodert und das Ergebnis der 
Interrupt-Schaltung zugeführt.

Ralf

von Tobias H. (pasdvn)


Lesenswert?

Ralf schrieb:
> Die Sendeschaltung löst setzt ein Flag (TI), wenn das Byte den seriellen
> Port inklusive Stopbit verlassen hat. Die Empfängerschaltung setzt ein
> Flag (RI) nach dem gemäß der eingestellten Baudrate erwarteten Zeitpunkt
> des Stopbits.
> Beide Flags zusammen werden verodert und das Ergebnis der
> Interrupt-Schaltung zugeführt.

Das ist je gerade mein Problem. Wenn ich davon ausgehe, das die 
Interruptlogik in irgend einer Weise auf steigende Flanken dieser Bit's 
triggert, wie kann sie dann indem oben beschriebenen Fall triggern, wenn 
durch das ODER der Pegel auf der "Leitung" die ganze Zeit auf High 
gehalten wird.
Aber im Grunde ist das ja auch erst einmal nicht so wichtig, solange es 
so funktioniert, wie ich es haben möchte :).

von Ralf (Gast)


Lesenswert?

> Wenn ich davon ausgehe, das die Interruptlogik in irgend einer Weise auf
> steigende Flanken dieser Bit's triggert, wie kann sie dann indem oben
> beschriebenen Fall triggern, wenn durch das ODER der Pegel auf der
> "Leitung" die ganze Zeit auf High gehalten wird.
Wer sagt denn, dass die Interruptlogik auf steigende Flanken reagiert? 
:)

Mal angenommen, es kommt ein Byte rein und setzt RI. Du bist noch in 
einem höher priorisierten Interrupt, währenddessen wird das aktuell zu 
sendende Byte auch rausgepustet. Du verlässt den höher priorisierten 
Interrupt. Der UART-Interrupt kommt dran, mit RI und TI gesetzt.

Die ISR sieht, dass RI gesetzt ist, löscht das RI-Flag, holt das 
empfangene Byte aus dem Empfangsregister und speichert es weg.
Somit ist nur noch TI am "Oder" aktiv. Das gleiche Spiel: TI wird 
gelöscht, und nach Bedarf ein weiteres Byte geholt und in das 
Senderegister geschoben.
Fertig. Alle Eingänge des "Oders" auf Low.

Besser jetzt? :)

Ralf

von Peter D. (peda)


Lesenswert?

Tobias H. schrieb:
> Nehmen wir aber an ich hab einige
> Befehle in einer niedrig Priorisierten ISR, für dessen Ausführung es
> dringend notwendig ist auch höher priorisierte Interrupts kurzzeitig zu
> deaktivieren.

Nun, dann hast Du was falsch gemacht.
Die höhere Priorität weist man ja gerade deshalb zu, damit er andere 
Interrupts unterbrechen darf. Willst Du das nicht, weise einfach die 
gleiche Priorität zu.
Natürlich kann man für atomare Zugriffe jederzeit das EA-Bit kurz mal 
löschen.

Tobias H. schrieb:
> Tritt nun innerhalb dieses Code-Teils ein höher
> Priorisierter Interrupt auf... ist der dann für immer weg.

Jede Interruptquelle hat ein Pending-Flag und solange dieses gesetzt 
ist, wird geprüft, ob der Interrupt ausgeführt werden darf.
Einige Interrupts löschen das Flag automatisch beim Eintritt, bei 
anderen muß man es manuell löschen.


Der Begriff Priorität hat beim AVR und 8051 unterschiedliche Bedeutung, 
daher gibt es oftmals große Verwirrung.
Beim 8051 legt die Priorität wirklich fest, welcher Interrupt einen 
anderen unterbrechen darf.
Beim AVR ist damit aber nur die Abarbeitungsfolge gemeint, wenn bei der 
Interruptfreigebe mehrere Interrupts anhängig sind (Pending-Bit 
gesetzt). Das nennt sich beim 8051 Polling Sequence.

Daher gibt es beim AVR regelmäßig Fragen, wo man denn nun die Priorität 
einstellt. Die Antwort ist: garnicht.


Peter

von Tobias H. (pasdvn)


Lesenswert?

> Wer sagt denn, dass die Interruptlogik auf steigende Flanken reagiert?
> :)
Hast du natürlich recht..

> Besser jetzt? :)
Ja :)


> Natürlich kann man für atomare Zugriffe jederzeit das EA-Bit kurz mal
> löschen.
Genau dafür brauche ich es auch!

Mit den AVR's hab ich (kaum) praktische Erfahrung. Nur halt schon viel 
gelesen, weil ich da demnächst auch mal ein bisschen mit rumspielen 
will. Muss aber sagen, dass das mit den vielen (wirklich priorisiebaren) 
Interrupts beim 8051 schon 'ne tolle Sache ist :).

Vielen Dank nochmal für eure Antworten. Hat mir sehr geholfen!

von Ralf (Gast)


Lesenswert?

> Vielen Dank nochmal für eure Antworten.
Jederzeit wieder :)

> Hat mir sehr geholfen!
Freut uns ^^

Ralf

von HolgerT (Gast)


Lesenswert?

Für weitere Erklärungen guggst Du hier (ab S. 52):

www.atmel.com/atmel/acrobat/doc0499.pdf
([PDF] AT89 Series Hardware Description - Atmel Corporation)

von HolgerT (Gast)


Lesenswert?

Nachtrag: der ..CC03 ist im Dokument nicht explizit gelistet. Das mag 
daran liegen, dass die Doku schon einige Jahre auf dem Buckel hat und 
der uC damals noch nicht im Protfolio war. Es ist davon auszugehen, dass 
die dargestellte Struktur auch in den ..CC03 übernommen wurde.

von Peter D. (peda)


Lesenswert?

Tobias H. schrieb:
>> Natürlich kann man für atomare Zugriffe jederzeit das EA-Bit kurz mal
>> löschen.
> Genau dafür brauche ich es auch!

Wobei ein Datenaustausch direkt zwischen Interrupts ein äußerst seltener 
Fall sein dürfte.
In der Regel müssen Daten erstmal verarbeitet werden und Interrupts 
sollten aber kurz gehalten sein.

Üblich ist daher, Daten zwischen Main und Interrupts zu übertragen, d.h. 
nur das Main muß atomare Zugriffe machen:
- 1.Interrupt empfängt Daten
- Main verarbeitet Daten
- 2.Interrupt gibt Daten aus


Peter

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.