Hallo Ich habe eine kleine Schaltung aufgebaut, die 2 Interrups
beinhaltet. INT0 und INT1.
Wird der Taster 1 betätigt, soll die Grüne Led an PortC 7 mal
Aufleuchten.
Wird der Taster 2 betätigt, soll die Rote Led an PortB 5 mal
Aufleuchten.
Wenn ein Taster Betätigt wird, springt das Programm in ein
Unterprogramm, welches mit CLI beginnt und mit SEI endet. (dies sollte
die Taster verriegeln) jedoch funktioniert das nicht.
Hier ist mein Listing:
.include"m8def.inc"
.org 0x0000
RJMP MAIN
RJMP TASTER1
RJMP TASTER2
RETI
MAIN:
SER R20
OUT DDRB,R20
OUT DDRC,R20
LDI R16,0x04 ;)
OUT SPH,R16 ;)Stack Configuration
LDI R16,0x5F ;) (RAMEND)
OUT SPL,R16 ;)
SBI DDRD,2 ;)
SBI PortD,2 ;)Pull Up wiederstand aktivieren
CBI DDRD,2 ;)
SBI DDRD,3 ;)
SBI PortD,3 ;)Pull Up wiederstand aktivieren
CBI DDRD,3 ;)
CLR R25
SEI ;Global Interrupt aktivieren
LDI R24,0B11000000 ;)Da das SBI nicht bei 0x3B geht ersetzt also
den befehl SBI 0X3B,6
OUT GICR,R24 ;)Interrupt INT0 und INT1 freigeben
LDI R16,0B00001010 ;Lade den Bitbefehl der auf Seite 66
nachgeschaut wurde in R16 Fallende Flanke INT0,INT1
OUT MCUCR,R16 ;MCUCR = I/O REG 0x35
Immer: RJMP Immer
TASTER1:
CLI ;Global Interrupt Disable
OUT GICR,R25 ;)Interrupt INT0 und INT1 verbieten
SER R20
LDI R21,0x0E
Weiter1:
OUT PORTC,R20
ldi R17, $16
WGLOOP0: ldi R18, $42
WGLOOP1: ldi R19, $DD
WGLOOP2: dec R19
brne WGLOOP2
dec R18
brne WGLOOP1
dec R17
brne WGLOOP0
; -----------------------------
; delaying 2 cycles:
nop
nop
COM R20
DEC R21
BRNE Weiter1
SEI ;Global Interrupt Enabel
OUT GICR,R24 ;)Interrupt INT0 und INT1 freigeben
RETI
TASTER2:
CLI ;Global Interrupt Disable
OUT GICR,R25 ;)Interrupt INT0 und INT1 verbieten
SER R20
LDI R21,0x0A
Weiter2:
OUT PORTB,R20
ldi R17, $16
WGLOOP00: ldi R18, $42
WGLOOP01: ldi R19, $DD
WGLOOP02: dec R19
brne WGLOOP02
dec R18
brne WGLOOP01
dec R17
brne WGLOOP00
; -----------------------------
; delaying 2 cycles:
nop
nop
COM R20
DEC R21
BRNE Weiter2
SEI ;Global Interrupt Enabel
OUT GICR,R24 ;)Interrupt INT0 und INT1 freigeben
RETI
;_________________________________________________________________
Ich hoffe das mir jemand helfen kann
MFG, Hermann
Nur ein paar Sachen:
Die Sprünge zur Interruptroutine gehören auf bestimmte Adressen. Da
fehlt ein „.org” vor den 2 rjmps.
Was Du alles mit cli und sei in den Interruptroutinen und Manipulation
von GICR veranstaltest, ergibt alles keinen Sinn. Schau Dir einfach den
Ablauf eines Interrupts im Manual mal nach und wie sich die Flags
automatisch setzen bzw. löschen.
Delay-Loops im Interrupt sind auch nicht übermäßig sinnvoll, aber zur
Übung mag's angehen. Du musst nur schwören, das in keinem ernst
gemeinten größeren Programm zu machen.
Die Interrupts sind Schrott. Wie schon erwaehnt macht man nichts mit
CLI/SEI im Interrupt. Dafuer muss man das Status Register sichern. Das
steht aber im Manual. Und Delays in Interupt sind auch nichts. Sowas
gibt's schlicht nicht.
Falls man eine Taste entprellen will so macht man das mit einem Timer
und einer Zustandsmaschine.
Hc Zimmerer und Sabb haben wichtige Punkte schon angesprochen.
Im Anhang ist ein simulationsfähiges Programm. Wenn du simulierst,
siehst du, dass INT0 Interrupt mit den 7x Blinken und Warten den µC fast
3,5 Sekunden lang in der INT0 ISR blockiert! Deine Endlosschleife (OK
ist ist im Moment leer) und andere ISRs (Taster2/INT1!) werden in dieser
Zeit nicht abgearbeitet!
Hallo, vielen Dank für die schnellen Antwochten.Ich habe mir das
simulationsprogramm angeschaut und getestet. Den Delay loop habe ich
daher in die Interrupt schleife getan da ich während dieser Zeit eh
nichts anderes machen kann. Die Befehle CLI und SBI habe ich verwendet
um die Taster zu verriegeln. das scheint jedoch nicht zu funktionieren.
Doch wie kann ich das tun? Indem ich die Ports während dem Interrupt als
Ausgang definiere?
Mir ist aufgefallen das wenn ich den Taster betätige,es sein kann das
die LED doppelt so oft Blinkt wie sie soll. Ich schätze das es daran
liegt, das sie nicht entprellt sind, und somit 2 mal als interrupt
erkannt werden.
Somit zu meiner zweiten Frage, wie kann ich einen Taster entprellen wenn
er einen Interrupt auslöst? muss ich die +-5ms Entprellzeit in die
Interruptschleife setzen?
Ich hoffe das ihr mir hier weiter helfen könnt...
MFG Hermann
Das wird hier fast täglich ad nauseam durchgekaut, warum es falsch ist
und wie mans richtig macht.
Benutz mal die Suchfunktion.
Interuptbedingungen setzen einfach erstmal nur ein Interruptflag. Ob
dabei Interupts enabled sind, spielt keine Geige.
Peter
Hermann schrieb:
> nichts anderes machen kann. Die Befehle CLI und SBI habe ich verwendet> um die Taster zu verriegeln. das scheint jedoch nicht zu funktionieren.> Doch wie kann ich das tun? Indem ich die Ports während dem Interrupt als> Ausgang definiere?
Ganz abgesehen davon, dass man Tasten anders behandelt (Peter hat das ja
schon angesprochen) ... du brauchst gar nichts tun! Kein CLI, kein SEI.
Während eine Interrupt Routine läuft, sind Interrupts per Default
gesperrt. Da kann dir also kein andere Interrupt in die Quere kommen!
Karl heinz Buchegger schrieb:
> Während eine Interrupt Routine läuft, sind Interrupts per Default> gesperrt. Da kann dir also kein andere Interrupt in die Quere kommen!
Ja das stimmt, jedoch werden sie danach abgearbeitet... und das dürfen
sie nicht...d.h. kurtz gefasst:
Eine kurtze betätigung von Taster1 generiert 5 rote LED-Impulse,ein
Drücken von Taster2 erzeugt 7 grüne LED-Impulse.Ein Led impuls = 0,25s
ON und 0,25s OFF. Während des Blinkens ssind die Taster verriegelt...
Hermann schrieb:
> Karl heinz Buchegger schrieb:>> Während eine Interrupt Routine läuft, sind Interrupts per Default>> gesperrt. Da kann dir also kein andere Interrupt in die Quere kommen!>> Ja das stimmt, jedoch werden sie danach abgearbeitet... und das dürfen> sie nicht...d.h. kurtz gefasst:
Es steht dir frei, am Ende einer Interrupt Service Routine, alle in der
Zwischenzeit aufgelaufenen Interrupt-Anforderungen wieder zu löschen.
Dies geschieht durch Löschen der entsprechenden Bits in den
entsprechenden Registern.
> Eine kurtze betätigung von Taster1 generiert 5 rote LED-Impulse,
Wenn ein Blinker in der ISR länger dauert, als das Prellen, kann das
nicht passieren. Bei prellenden Tastern wird genau 2 mal geblinkt. Die
Interrupt Anforderungs Flags zählen nicht mit, wieviele externe Pulse
während der ISR eingelaufen sind, sondern nur, dass mindestens ein Puls
reinkam. Wird am Ende der ISR das entsprechende ISR-Anforderungsflag
gelöscht, wird auch kein weiterer ISR Aufruf mehr gemacht.
Aber wie auch immer: Die Lösung des Problems liegt nicht darin, da jetzt
die ISR auf Biegen und Brechen mit Flag löschen und Wartezeiten
abzusichern, sondern die Lösung liegt in einem Timer, Pollen der
Tastereingänge und entsprechender Entprellung. Siehe den Wiki Artikel
über Entprellung.
Karl heinz Buchegger schrieb:
> Wird am Ende der ISR das entsprechende ISR-Anforderungsflag> gelöscht, wird auch kein weiterer ISR Aufruf mehr gemacht.
Danke Karl Heinz Buchegger...
Ich glaube das ist der Schlüssel zu meinem Problem... wenn ich es
schaffe diese bits zu veränden kann es doch auch sein das ich gar nichts
mehr zu entprellen brauch...oder?
Somit kann der dater ja x mal während der ISR gedrückt werden, wenn ich
die einträge am ende der ISR lösche intressiert das ja keinen mehr.
Nur noch eine frage... Wo finde ich dieses
Byte,Bit(ISR-Anforderungsflag)?
MFG Hermann
Hermann schrieb:
> Ich glaube das ist der Schlüssel zu meinem Problem... wenn ich es> schaffe diese bits zu veränden kann es doch auch sein das ich gar nichts> mehr zu entprellen brauch...oder?
Ich wusste es :-)
Machs richtig.
Denn dein nächstes Problem besteht darin, dass in einer ISR nicht
gewartet werden soll. Auch dann nicht, wenn man Blinken möchte.
Wenn du das aber korrigierst, dann hast du den Fall, dass die ISR viel
schneller abgearbeitet wird, als der Taster prellen kann.
Und damit löst dir der prellende Taster dann doch wieder den nächsten
Interrupt aus.
Hör endlich auf, dich zu drehen und zu winden. Hak die Erfahrung als 'so
gehts nicht vernünftig' ab und benutze endlich die entsprechende
Entprellroutine, die du im Wiki findest. In der Zeit, in der du hier
herumphilosophierst und dich windest, hättest du die schon 3 mal fix
fertig eingebaut und ein funktionierendes Programm.
Es schad nix, einmal gründlich durchzuspielen, wodurch Interruptflags
gesetzt werden, wann sie automatisch gelöscht werden, wie man sie
explizit löscht und was sie bewirken, nachdem die Interruptsource und
globale Interrupts freigegeben sind.
Am besten macht man es im Simulator.
Und wenn das alles verstanden wurde, schmeißt man es weg und macht es
richtig.
Peter
Danke für das rasche antwochten...
Ich sehe jedoch noch immer ein kleines Problem das ich nicht weiss wie
ich es löden kann...
ich bin vollkommen mit euch einverstanden das man in der ISR kein
delayloop setzten soll...
Jedoch ist eine Entprell zeit auch eine Zeitkonstannte von +-5ms und die
muss ich doch dann in die ISR setzten oder nicht??
Hermann schrieb:
> Jedoch ist eine Entprell zeit auch eine Zeitkonstannte von +-5ms und die> muss ich doch dann in die ISR setzten oder nicht??
Und genau das ist das hüpfende Komma, wo der Timerinterrupt seine
Trumpfkarte aus dem Ärmel zieht.
Er stellt einfach die Entprellzeit wieder dem Main oder anderen
Interrupts zur Verfügung.
Peter
Sorry aber ich blick hier echt nicht mehr durch...
ich habe mir jetzt das simulationsprogramm von Stefan B. zur Hilfe
geholt und 2-3 sachen hinzugefügt....
Einmal am ende jeder ISR ein "Out GICR,R25" wobei R25 = 0x00
und eine entprellzeit von 7ms in jede ISR, Das verstösst zwar gegen eure
tipps aber ich weiss nicht wie ich das mit einem Timer machen soll...
Zudem sollte das nur ein ganz einfaches programm werden , indem nie
etwas ins MAIN kommen sollte...
hier mein Listing:
.include"m8def.inc"
.def temp = r16
.org 0x0000
RJMP MAIN
.org INT0addr
RJMP TASTER1
.org INT1addr
RJMP TASTER2
; ##############################
; ##############################
; ##############################
MAIN:
; AVR-Tutorial: Stack
ldi temp, LOW(RAMEND)
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp
SER temp ; Loads $FF directly to register Rd.
OUT DDRB,temp ; PORTB komplett auf Ausgang (Default: LOW)
OUT DDRC,temp ; PORTC komplett auf Ausgang (Default: LOW)
CLR R25
; Taster1 init
SBI DDRD,PD2 ; PD2 Ausgang
SBI PortD,PD2 ; PD2 Pull-Up-Widerstand aktivieren
CBI DDRD,PD2 ; PD2 Eingang
; Taster2 init
SBI DDRD,PD3 ; PD3 Ausgang
SBI PortD,PD3 ; PD3 Pull-Up-Widerstand aktivieren
CBI DDRD,PD3 ; PD3 Eingang
; AVR-Tutorial: Interrupts
LDI temp,(1<<ISC11)|(1<<ISC01) ; Fallende Flanke INT0,INT1
OUT MCUCR,temp ;
LDI temp,(1<<INT1)|(1<<INT0) ; INT0 und INT1 enable (GIMSK == GICR)
OUT GICR,temp
SEI ;Global Interrupts aktivieren
; Endlosschleife
Immer:
RJMP MAIN
; ##############################
; ##############################
; ##############################
TASTER1:
; AVR-Tutorial: Interrupts
push temp ; Das SREG in temp sichern. Vorher
in temp, SREG ; muss natürlich temp gesichert werden
push R17
push R18
push R19
push R20
push R21
ldi R17, $2F
WGLOOP000: ldi R18, $B6
WGLOOP001: dec R18
brne WGLOOP001
dec R17
brne WGLOOP000 ;7ms Entprellzeit
; -----------------------------
; delaying 2 cycles:
nop
nop
SER R20
LDI R21,7*2 ; 7 mal Blinken
Blinken1:
OUT PORTC,R20
RCALL WARTEN
COM R20
DEC R21
BRNE Blinken1
pop R21
pop R20
pop R19
pop R18
pop R17
out SREG, temp ; Die Register SREG und temp wieder
LDI temp,(1<<INTF0) ; Aufgelaufene INT0 löschen
OUT GIFR,temp
pop temp ; herstellen
OUT GICR,R25 ;INT0 und INT1 Disable
RETI
; ##############################
; ##############################
; ##############################
TASTER2:
; AVR-Tutorial: Interrupts
push temp ; Das SREG in temp sichern. Vorher
in temp, SREG ; muss natürlich temp gesichert werden
push R17
push R18
push R19
push R20
push R21
ldi R17, $2F
WGLOOP010: ldi R18, $B6
WGLOOP011: dec R18
brne WGLOOP011
dec R17
brne WGLOOP010 ;7ms Entprellzeit
; -----------------------------
; delaying 2 cycles:
nop
nop
SER R20
LDI R21,5*2 ; 5 mal Blinken
Blinken2:
OUT PORTB,R20
RCALL WARTEN
COM R20
DEC R21
BRNE Blinken2
pop R21
pop R20
pop R19
pop R18
pop R17
out SREG, temp ; Die Register SREG und temp wieder
LDI temp,(1<<INTF1) ; Aufgelaufene INT1 löschen
OUT GIFR,temp
pop temp ; herstellen
OUT GICR,R25 ;INT0 und INT1 Disable
RETI
; ##############################
; ##############################
; ##############################
; Benutzt: R17, R18, R19
; wurden vorher gerettet
WARTEN:
ldi R17, $16
WGLOOP0: ldi R18, $42
WGLOOP1: ldi R19, $DD
WGLOOP2: dec R19
brne WGLOOP2
dec R18
brne WGLOOP1
dec R17
brne WGLOOP0
; -----------------------------
; delaying 2 cycles:
nop
nop
RET
Hermann schrieb:
> ich habe mir jetzt das simulationsprogramm von Stefan B. zur Hilfe> geholt und 2-3 sachen hinzugefügt....>> Einmal am ende jeder ISR ein "Out GICR,R25" wobei R25 = 0x00
Warum? Du willst doch INT0 und INT1 haben. Warum schaltest du die beiden
nach dem ersten Aufruf von INT0 oder INT1 ab? Dann funktionieren die
Taster garnicht nicht mehr wie gewünscht.
Wenn du was tun kannst, dann das Flag löschen, welches anzeigt, dass ein
weiterer INT0 oder INT1 ansteht. Und das ist im Code schon drin z.B. für
INT1
LDI temp,(1<<INTF1) ; Aufgelaufene INT1 löschen
OUT GIFR,temp
Es kann sein, dass ich das Datenblatt falsch gelesen habe und man vor
dem Löschen des Flags (durch Schreiben von 1 ins Bit) zuerst prüfen
muss, ob es gesetzt ist, um zu verhindern, dass man es irrtümlich setzt,
wenn es gelöscht ist.
Allerdings wenn ich das falsch mache (generell 1 in Bit INTFx schreiben
statt nur 1 schreiben, wenn Bit INTFx gleich 1), müsste die betreffende
LED ständig blinken und davon schreibst du nichts.
Das will ich heute abend testen, wenn bis dahin niemand etwas dazu
schreibt.
Wenn du magst, dann teste selbst die selektive Variante: Ändere diese
Stellen (entsprechend 2x bei INT0-ISR mit exit1 und INT1-ISR mit exit2)
1
pop R17
2
out SREG, temp ; Die Register SREG und temp wieder
3
LDI temp,(1<<INTF1) ; Aufgelaufene INT1 löschen
4
OUT GIFR,temp
5
pop temp ; herstellen
6
RETI
in
1
IN R17, GIFR ; Interruptflags holen
2
SBRS R17,INTF1 ; und Bit INTF1 prüfen
3
RJMP exit2 ; wenn Bit INTF1 nicht gesetzt (kein 2. INT1 da)
out SREG, temp ; Die Register SREG und temp wieder
9
pop temp ; herstellen
10
RETI
> 7ms Entprellzeit
Nutzen an der Stelle nichts. Der AVR merkt sich den nächsten Interrupt,
wenn an dem Pin eine weitere fallende Flanke kommt.
Aber du kannst wie oben den Merker (INTFx Flags) löschen. Und wenn das
Löschen nach 3,5s oder 2,5s gegen Ende der ISR gemacht wird, hat sich
IMHO jeder Taster ausgeprellt :)
Hallo Ich habe mich auch vertan... ich wollte auch Gifr schreiben...
aber für den moment verstehe ich gar nichts mehr... ich werde gleich
noch einen bekannten um einen rat fragen...
trotzem danke für die Hilfe...
Hermann schrieb:
> und eine entprellzeit von 7ms in jede ISR, Das verstösst zwar gegen eure> tipps aber ich weiss nicht wie ich das mit einem Timer machen soll...
In der Leiste links gibt es einen Abschnitt "Artikelübersicht". Klickst
du drauf, kommst du auf eine Seite in der es ein Suchfeld gibt (wieder
in der linken Leiste). Dort tippst du "Entprellung" ein und das Wiki
sucht dir den Artikel Entprellung raus. Auf der Seite findest du dann
eine 100% full-proof Tastenentprellung, auch in Assembler. Abschnitt
2.3.1
> Zudem sollte das nur ein ganz einfaches programm werden , indem nie> etwas ins MAIN kommen sollte...
Genau da liegt schon der nächste Konzeptfehler.
Denn was du als "einfach" ansiehst, hat sich ja wohl mitlerweile zu
einem Albtraum entwickelt. Unmengen an Arbeit in einer ISR zu erledigen,
sieht zwar auf den ersten Blick wie ein "einfaches Konzept" aus, ist es
aber nicht.