Hallo als vorbereitung für ne Arbeit sollen wir ne Ampel schaltung realisieren. gefordert ist das die ampel mit einem externen interrupt an PD3 gestartet wird. Die schaltzeit zwischen den übergängen soll 2 sec. betragen. mein problem ist nun: das programm läuft soweit jedoch nicht immer. es kann sein dass ich bis zu 3 mal hintereinander den ablauf starten kann. danach wiederholt sich der ablauf 2 mal bis die ampel wieder zu ihrer grundstellung zurückkehrt. die ampel hat eine fußgänger sowie eine "auto" ampel fußgänger ampel: Rot = LED1 Grün = LED0 auto ampel: Rot = LED7 Gelb = LED6 Grün = LED5 ich hoffe ihr könnt mir helfen. danke! .device ATmega8515 .nolist .include "m8515def.inc" ;======================================================================= === ;DECLARATIONS .def temp = r16 .def merker = r17 .def counter = r18 ;======================================================================= === ;START Programm rjmp Init .org $04 rjmp inter ;======================================================================= == Init: ser temp out DDRA, temp out DDRB, temp out DDRC, temp out PORTB,temp clr temp out PORTA, temp out PORTC, temp ldi temp, 0b11110111 out DDRD, temp com temp out PORTD, temp ;==========================STACK======================================== ===== ldi temp,LOW(RAMEND) out SPL,temp ldi temp,HIGH(RAMEND) out SPH,temp ;======================INTERRUPT INI===================================== ldi temp, 0b00001000 out MCUCR,temp ldi temp, 0b10000000 out GICR,temp sei ;==============================MAIN PROGRAMM=========================== start: ldi temp, 0b11010101 out PORTB,temp rjmp start ;=============================Unterprogramm============================= ====== warten: ldi temp, 0b00000101 out TCCR0, temp ldi merker, 36 ldi counter, 200 warten_1: in temp,TCNT0 cp temp,counter brne warten_1 subi counter, -200 dec merker brne warten_1 clr temp out TCCR0,temp out TCNT0,temp ret ;========================INTERRUPT ROUTINE============================== inter: push temp ldi temp, 0b10111101 ;GELB_ROT out PORTB,temp rcall warten ldi temp, 0b01111101 ;ROT_ROT out PORTB,temp rcall warten ldi temp, 0b01111110 ;ROT_GRÜN out PORTB,temp rcall warten ldi temp, 0b01111101 ;ROT_ROT out PORTB,temp rcall warten ldi temp, 0b00111101 ;ROTGELB_ROT out PORTB,temp rcall warten ldi temp, 0b11011101 out PORTB,temp pop temp reti
max&moritz schrieb: > als vorbereitung für ne Arbeit sollen wir ne Ampel schaltung > realisieren. gefordert ist das die ampel mit einem externen interrupt an > PD3 gestartet wird. Lass mich raten. Du hast da im Moment einen Taster angeschlossen? > mein problem ist nun: > zu 3 mal hintereinander den ablauf starten kann. danach wiederholt sich > der ablauf 2 mal bis die ampel wieder zu ihrer grundstellung > zurückkehrt. Dein Taster wird prellen. Du drückst zwar nur einmal. Die Kontaktfeder im Taster federt aber und gaukelt dem µC mehrere Tastendrücke vor. Der eine wird sofort mit dem Ausführen der ISR quittiert und während die anderen Tastendrücke dafür sorgen, dass das 'Imterrupt-eingetrudelt' Bit noch während die ISR läuft gleich wieder gesetzt wird.
erst mal danke karl heinz. ok, habe noch was vergessen zu sagen, ich verwende ein stk500, an PD3 ist ein schalter mit PullUp. Der Interrupt wird mit einer fallenden Flanke an PD3 ausgelöst. Ist es nicht so dass wenn einmal der Interrupt ausgelöst ist er komplett einmal die routine durchläuft? danke!
@ max&moritz (Gast) >nicht so dass wenn einmal der Interrupt ausgelöst ist er komplett einmal >die routine durchläuft? Doch. Aber was macht dein Prozessor, der ja schon recht flink ist, 3ms später, wenn der Interrupt längst abgearbeitet ist? Dann prellt der Taster und löst einen zweiten Interrupt aus. So ein Schaltung mit Interrupt zu machen ist schlicht Unsinn. Das macht man dreimal besser mit einer Abfrage in einer laaaaaaangsamen Hauptschleife. Da kann man den uC problemlos mit 10kHz takten, der langweit sich immer noch. MFG Falk
ok, es ist halt ne übung zu interrupts. mein interruptroutine ist ja nicht nur 10µs lang sondern die komplette ampelphasen. das müssten fasst 10 sec sein. von daher kann es doch garnix mit prellen zu tun haben, oder?? Danke!
@ max&moritz (Gast) >mein interruptroutine ist ja nicht nur 10µs lang sondern die komplette >ampelphasen. das müssten fasst 10 sec sein. Dann bekommst erst DU und dann dein Lehrer ein paar ordentliche hinter die Ohren für so einen Unsinn! Lies mal DRINGEND den Artikel Interrupt und lerne wie man es richtig macht. Und dann mach es richtig. Und wenn das deinem Lehrer nicht gefällt dann schick ihn zu mir! MFG Falk
hmm ok falk, in dem artikel heist es dass bei längern interrupts daten verloren gehen können... dann könnte es bei mir deshalb noch funktionieren....
max&moritz schrieb: > nicht funktionieren Nein. Dein Problem ist das Prellen der Taster. Jeder AVR hat Bit in einem Register, das ihm sagt, dass die Interruptbedingung zugetroffen hat und er gefälligst die ISR aufrufen soll. Dieses Bit wird nach jedem CPU-Befehl abgefragt und wenn es gesetzt ist, wird in die ISR gesprungen. Mit einer Ausnahme: Befindet sich der Prozessor bereits in einer ISR, dann unterbleibt diese Auswertung (Im Grunde ist das genau das, was sei bzw. cli machen: Die Freigabe ob Interrupts überhaupt abgearbeitet werden. Bei Einsprung in eine ISR macht der Prozessor ein automatisches cli, und beim reti macht er ein automatisches sei). Sobald die ISR betreten wird, wird das bewusste Bit wieder zurückgesetzt. Wenn also derselbe Interrupt erneut auftritt, während der Prozessor in der ISR ist, dann speichert dieses Bit das Auftreten des Interrupts. Kommt der Prozessor aus der ISR wieder heraus, dann ist das interrupt-auslösende Bit schon wieder gesetzt, und nach dem nächsten Befehl geht es wieder in die ISR. Wenn du also, während der Prozessor in der ISR ist, die Taste erneut drückst, dann beginnt nach dem Abarbeiten der bisherigen ISR, sofort die nächste. Dies deshalb, weil ja in diesem Bit zwischengespeichert wurde, dass eine Interruptanforderung eingegangen ist. Und genau das tusu du unbewusst. Die Taste macht das für dich. Ein paar Millisekunden nach dem ersten Tastendruck kommt von der Taste der nächste "Tastendruck".
danke karl heinz, wie kann ich aber nun verhindern das das bit erneut gesetzt wird? lässt sich der interupttaster genauso entprellen wie ein normaler taster? oder muss ich in cli befehl nach dem ersten interrupt anwenden dass keine weitere interrupts mehr zugelassen werden?? hoffe du kannst mir ein lösungsansatz geben, komme nicht weiter... danke
max&moritz schrieb: > danke karl heinz, > wie kann ich aber nun verhindern das das bit erneut gesetzt wird? > lässt sich der interupttaster genauso entprellen wie ein normaler > taster? Wie Du merkst, raufen sich hier alle Programmierer die Haare über den Ansatz. Aber es würde zu weit führen, alles von Anfang an richtig zu machen. Wenn Dein Lehrer denkt, der externe Interrupt ist fürs Tasten abfragen da, dann mußt Du ihm eben den Gefallen tun. Um eine Entprellung kommst Du aber nicht drumrum. Zuerst mach im Interrupt ne Wartezeit ~100ms und wenn danach der Pin immer noch low ist, dann fängst Du an. Ansonsten gehts mit RETI wieder raus. Und nach dem Ampelgedöns löscht Du das Interruptflag, damit Du erst ab da an wieder neue Drücke akzeptierst. Das Interruptflag muß man löschen, indem man es auf 1 setzt, da hat wohl irgend son Heini bei Atmel seinen ulkigen Tag gehabt. Peter
max&moritz schrieb: > danke karl heinz, > wie kann ich aber nun verhindern das das bit erneut gesetzt wird? gar nicht. Aber du kannst das bewusste Flag löschen, wenn eine ISR knapp vor dem fertig werden ist. :-) > lässt sich der interupttaster genauso entprellen wie ein normaler > taster? Der ganze Ansatz mit Auslösung durch Taster am Interrupt und Abarbeitung der Ampelphasen in einer ISR ist kompletter Schwachsinn. > oder muss ich in cli befehl nach dem ersten interrupt anwenden dass > keine weitere interrupts mehr zugelassen werden?? Du hast nicht sorgfältig genug gelesen. Sobald eine ISR angesprungen wird, macht der AVR implizit einen cli
so, das letze mal... karl heinz, zu deinem tipp "das bewusste Flag" löschen: jetzt habe ich kurz vor dem fertigwerden des interrupts, ldi temp, 0b10000000 out GIFR,temp jetzt siehts ganz gut aus. =) danke
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.