Forum: Mikrocontroller und Digitale Elektronik Atmel 8051er zwischen Interrupts Prioritäten wechseln geht das


von Ertan M. (drbrain)


Lesenswert?

Hallo zusammen !

ich hätte eine ganz einfache Frage, die mir seit ein paar Tagen den Kopf 
zerbricht.

Mein Frage lautet ist es mit dem Atmel AT89C51ED2 möglich zwischen zwei 
Interrupts Prioritäten während einer Interrupt Service Routine zu 
wechseln ?

unten habe ich ein Lauflicht programmiert der durch den externen 
Interrupt(lsbzumsb auf Port 2) 0 oder Interrupt1(msbzulsb auf Port 2) 
ausgelöst werden kann die höhere Priorität ist auf den externen 
Interrupt 1
gesetzt.

wenn mann P3.2 drückt fängt das Lauflicht vom lsb zu msb sich zu bewegen
da der P3.3 die höhere Priorität hat wird die ISR2 ausgelöst wenn man 
P3.3 drückt und das Lauflicht fängt dann an sich vom msb zu lsb zu 
bewegen jedoch kann ich jetzt nicht den Interrupt0 P3.2 (lsbzumsb) 
auslösen weil der Interrupt 1 die höhere Priorität hat. Was kann ich 
bzw. muss ich machen damit die sich höhere Prioritäten im ISR sich 
switchen : einmal die Priorität 3 für EX0 und einmal für EX1 !



mov IPL0,#00000100b  Priorität 3 für EX1
mov IPH0,#00000100b  Priorität 3 für EX1





include C51ED2.inc

code at 0
sjmp init


isr1:
org 003h
push acc
push psw
call lsbzumsb
pop acc
pop psw
reti


isr2:
org 0013h
push acc
push psw
call msbzulsb
pop acc
pop psw
reti


lsbzumsb:
mov r3,#150
sprung3:
mov p2,a
call zeit
RL a
djnz r3,sprung3
ret


msbzulsb:
mov r4,#150
sprung4:
mov p2,a
call zeit
RR a
djnz r4,sprung4
reti


init:
mov IPL0,#00000100b
mov IPH0,#00000100b
mov a,#1
setb IT0
setb IT1
clr IE0
clr IE1
setb EX0
setb EX1
setb EA

zeit:
mov r1,#200
sprung2:
mov r2,#200
sprung1:
djnz r2,sprung1
djnz r1,sprung2
ret


haupt :

sjmp haupt

end.

von Peter D. (peda)


Lesenswert?

Ja man kann die Priorität jederzeit ändern.

Der 8051 hat eine äußerst clevere und einfache Methode, die Prioritäten 
zu verwalten.
Für die 4 Prioritäten sind nur 4 Bits nötig.
Die Priorität wird beim Interrupteintritt ausgewertet und setzt das 
entsprechende Bit. Jedes RETI löscht dann wieder genau ein Bit, das 
höherwertige zuerst.

Wenn man nun in einem Interrupt seine eigene Priorität erhöht, muß das 
unmittelbar vor dem RETI geschehen, sonst kann es passieren, daß man 
sich selbst unterbricht (2 Instanzen des Handlers).


So und nun die schlechte Nachricht, das wird Dir bei Deinem Problem 
nicht das geringste helfen.

Interrupts sind dazu da, daß man nur kurz darin verweilt und sein Ding 
macht. Du willst aber für immer drin bleiben und das geht nicht.

Du mußt also Deinen Programmablauf nochmal neu überdenken.


Interrupts sind auch generell keine gute Methode, Tasten abzufragen, da 
Tasten prellen.


Peter

von Ertan M. (drbrain)


Lesenswert?

hallo erstmal vielen dank für die schnelle Antwort !
die Verwaltung von Prioritäten werden bei mir über mov IPL0,#00000100b
mov IPH0,#00000100b gesetzt, die Entprellung kann ja über eine 
Zeitverzögerung  kompensiert werden.
Wenn Sie mir vielleicht ein Programmbeispiel zeigen könnten
wäre ich Ihnen sehr verbunden.


Mit freundlichen Grüßen

Ertan

von Bruno (Gast)


Lesenswert?

Hallo Ertan,

setze in den Interrupts doch einfach nur bits sozusagen als Flags, z.B.:

isr1:
org 003h
setb ($2F).0
clr ($2F).1
reti

isr2:
org 0013h
clr ($2F).0
setb ($2F).1
reti


Im Initialisierungsteil löschst du die beiden Flags:

init:
...
clr ($2F).0
clr ($2F).1


Den eigentlichen Aufruf von lsbzumsb und msbzulsb erfolgt dann im 
Hauptprogramm anhand der Flags:

haupt :

jnb ($2F).0,keinlsbzumsb
call lsbzumsb

keinlsbzumsb:
jnb ($2F).1,keinmsbzulsb
call msbzulsb

keinmsbzulsb:

sjmp haupt


Wenn Du sofort umschalten können willst, mußt Du die Schleifen noch 
abbrechen können:

lsbzumsb:
clr ($2F).0
mov r3,#150
sprung3:
mov p2,a
call zeit
RL a
jb ($2F).1,Endelsbzumsb
djnz r3,sprung3
Endelsbzumsb:
ret


msbzulsb:
clr ($2F).1
mov r4,#150
sprung4:
mov p2,a
call zeit
RR a
jb ($2F).0,Endemsbzulsb
djnz r4,sprung4
Endemsbzulsb:
reti

Wenn ($2F).0 gesetzt ist (durch isr1), dann wird lsbzumsb aufgerufen.
Wenn ($2F).1 gesetzt ist (durch isr2), dann wird msbzulsb aufgerufen.

Hab's nicht ausprobiert, aber ich hoffe, es funktioniert...

Viel Glück,

Bruno

von Ertan M. (drbrain)


Lesenswert?

Hallo erstmal vielen dank für eure schnelle Antwort .

die Idee ist super jedoch kann ich mit den Flags nichts anfangen da der 
Compiler diese Syntax nicht erkennt setb ($2F).0 ! ? bitte um Hilfe !


MfG Ertan

von E. B. (roquema) Benutzerseite


Lesenswert?

Welcher Compiler? Das ist doch Assembler. Welchen benutzt Du denn?
Im RAM ist der Bereich 20h bis 2Fh bitadressierbar.
(Siehe Datenblatt bzw. 8051 Hardwarebook)
Will man ein Bit davon nutzen, schreibt man das entspr. Bit hinter die 
Adresse der Speicherzelle z.B.
2F.0h 1.Bit (niederwertigstes) der Speicherzelle 2Fh im RAM
2F.1h 2. Bit    "
usw.

Wie die Syntax genau bei deinem Assembler aussieht musst Du im Manual 
nachsehen.
Probier mal: clr 2F.0h bzw. setb 2F.0h

von Ertan M. (drbrain)


Lesenswert?

Hallo :-))

ich benutze den RIDE51 RAISONANCE Kit !

setb 2F.0h bzw. 2F.0h akzeptiert der Compiler nicht aber setb 2Fh 
compiliert er ohne Probleme ?



MfG

Ertan

von Bruno C. (bruno)


Lesenswert?

Hallo Ertan,

leider kenne ich Deinen Compiler nicht, in meinem ist die Syntax wie ich 
oben beschrieben habe, z.B. ($2F).1

Wenn das bei Dir nicht funktioniert, dann nimm anstelle eines Bits ein 
ganzes Byte als Flag, z.B. nimmst Du 30h anstelle von ($2F).0 und 31h 
anstelle von ($2F).1 und weist denen entweder 0 oder 1 zu. Dann werden 
nur die Sprünge etwas umständlicher, aber Du könntest den jew. Wert in 
den Akku kopieren und dann jz bzw. jnz benutzen.

Also anstelle von

   clr ($2F).0    bzw.    setb ($2F).0

schreibst Du

   mov 30h,#0     bzw.    mov 30h,#1

und anstelle von

   jb ($2F).0,Endelsbzumsb

schreibst Du dann

   mov A,30h
   jnz Endelsbzumsb

bzw. aus

   jnb ($2F).0,keinmsbzulsb

wird dementsprechend

   mov A,30h
   jz keinmsbzulsb

Dann mußt Du aber ggf. den Akku retten, wenn Du ihn irgendwo sonst in 
Deinem Programm ebenfalls benutzt (Push ACC und Pop ACC).

Apropos push und pop, mit fällt da gerade noch etwas auf: In Deinen 
Interrupt Serviceroutinen rettest Du den Akku und das PSW, aber Du mußt 
darauf achten, sie in umgekehrter Reihenfolge vom Stack zurückzuholen, 
wie Du sie hinaufschiebst. Du hast

push acc
push psw
call lsbzumsb
pop acc
pop psw

geschrieben, es müßte aber

push acc
push psw
call lsbzumsb
pop psw
pop acc

sein. Das ist sehr wichtig, denn ansonsten findet sich der Inhalt des 
Akkus anschließend im PSW wieder und umgekehrt. Allerings brauchst Du 
Akku und Prozessorstatuswort nur dan zu retten, wenn Du es auch 
veränderst, ansonsten kannst Du die Befehle weglassen.

Viel Spaß mit Deinem Projekt,

Bruno

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.