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
Hermann schrieb: > Nur noch eine frage... Wo finde ich dieses > Byte,Bit(ISR-Anforderungsflag)? Es könnte helfen, in hermann_int0_int1.asm zu schauen.
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) |
4 | LDI R17,(1<<INTF1) ; aufgelaufene INT1 löschen (1 schreiben) |
5 | OUT GIFR,R17 |
6 | exit2: |
7 | pop R17 |
8 | 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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.