Forum: Mikrocontroller und Digitale Elektronik Frage zu einer Ampelschaltung mit Interrupt


von max&moritz (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von max&moritz (Gast)


Lesenswert?

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!

von Falk B. (falk)


Lesenswert?

@  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

von max&moritz (Gast)


Lesenswert?

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!

von Falk B. (falk)


Lesenswert?

@  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

von max&moritz (Gast)


Lesenswert?

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

von max&moritz (Gast)


Lesenswert?

nicht funktionieren

von Karl H. (kbuchegg)


Lesenswert?

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

von max&moritz (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von einer (Gast)


Lesenswert?

Stichwort Flags

von Karl H. (kbuchegg)


Lesenswert?

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

von max&moritz (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.