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
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