Forum: Mikrocontroller und Digitale Elektronik Problem mit Interrupt-Funktion


von sentinel (Gast)


Lesenswert?

Hallo zusammen,

ich programmiere momentan eine kleine Steuerung und stehe vor einem 
Problem wo ich nicht weiß wie ich es behebe.

Folgende Situation: Der Benutzer drückt einen Taster, wodurch ein 
Interrupt ausgelöst wird.
1
int main(void)
2
{
3
  [...]
4
5
  GICR |= (1 << INT2);
6
  MCUCSR |= (1 << ISC2);
7
  sei();
8
9
  [...]
10
}
11
12
ISR(INT2_vect)
13
{
14
  PORTA = PORTC = 0x00;
15
  PORTA = 0b01000000;
16
  
17
  _delay_ms(SHORT_DELAY);
18
  
19
  GICR |= 0b00010000;
20
  
21
  while (PINB != 0b00000100)
22
  {
23
          
24
  }
25
  
26
  PORTA = 0xFF;
27
  _delay_ms(SHORT_DELAY);
28
}

In der Schleife wird abgefragt, ob der Taster, der zuvor den Interrupt 
ausgelöst hat nochmals betätigt wurde, wodurch die ISR-Funktion 
verlassen werden soll.

Nach dem 2ten Betätigen des Tasters wird allerdings direkt wieder in die 
ISR-Funktion gesprungen (also der Interrupt ausgelöst). Weiß jmd. wie 
ich das verhindern kann?

Viele Grüße

von Micha H. (mlh) Benutzerseite


Lesenswert?

Merker setzen und den abfragen.

von Peter II (Gast)


Lesenswert?

sentinel schrieb:
> Nach dem 2ten Betätigen des Tasters wird allerdings direkt wieder in die
> ISR-Funktion gesprungen (also der Interrupt ausgelöst). Weiß jmd. wie
> ich das verhindern kann?

man müsste das Flag löschen, was zum auslösen führt.

ABER:

so etwas macht man nicht. Das Konzept solltest du gleich vergessen. in 
einer ISR macht man keine Warteschleifen rein. Auch die Abfrage des 
Taster macht in der ISR meist wenig sinn, mache es in der Main und schon 
ist das Problem weg.

von Kris M. (kristijan_m)


Lesenswert?

du könntest einen Zähler einbauen in deinen Interrupt bauen.

if>2 -> Interrupt oder sowas in der Art

und am ende wieder auf 0 stellen

von DomeG (Gast)


Lesenswert?

Interrupt am Anfang der ISR abschalten und am Ende wieder einschalten...

von PINB (Gast)


Lesenswert?

sentinel schrieb:
> while (PINB != 0b00000100)
>   {
>
>   }

Was ist PINB? Zwar noch nie gehört, aber das hört sich eher nach einem 
PIN an bzw. einem Bit, nicht einem ganzen Byte.

Zudem, wie schon geschrieben wurde, könnte man einen Merker setzen.

So nebenbei:
Eine ISR sollte kurz gehalten werden. Schleifen usw sollten wenn möglich 
vermieden werden.

von Peter II (Gast)


Lesenswert?

DomeG schrieb:
> Interrupt am Anfang der ISR abschalten und am Ende wieder einschalten...

Unsinn. und bringt auch nichts. Interrupt sind immer in einer ISR 
gesperrt (beim einem Atmel). Und nach den aktivieren würde er ein 2.mal 
auslösen.

von Bitflüsterer (Gast)


Lesenswert?

Grundsätzlich ist es sehr empfehlenswert, Taster zu entprellen. Such 
mal hier nach "Entprellung". Peter Danegger wird sich freuen. :-)
Aber darüber hinaus, ist es problematisch, Taster überhaupt an 
Interrupts zu betreiben. Und dann sind delays und while-Schleifen auch 
ganz "pfui, bäh" in ISRs. ;-)

Aber das sind hier nicht Deine primären Probleme:

Während das Programm (die ISR), nach dem ersten Tastendruck auf den 
zweiten wartet, wird - bewirkt eben durch dieses zweiten Tastendruck - 
auch der Interrupt ein zweites Mal aktiv (resp. das entsprechende 
Interrupt-Flag gesetzt).
Weil zu diesem Zeitpunkt noch die Abarbeitung der ISR aufgrund des 
ersten Ereignisses erfolgt, wird die ISR nach Verlassen ein zweites 
Mal aufgerufen.

Das willst Du natürlich nicht.

Das aber ergibt auch genau den Anhaltspunkt für die Lösung Deines 
Problems.
Kurz: Wenn der Interrupt, ohne das man etwas besonderes schreiben muss, 
sowieso zweimal ausgelöst wird, einmal beim ersten und einmal beim 
zweiten Tastendruck, warum dann in der ISR für den ersten Tastendruck, 
den zweiten vorsehen?

Anders ausgedrückt: Der Mechanismus, der jedesmal, also bei beiden 
Tastendrücken eine gesonderte Reaktion hervorruft ist schon vorhanden. 
Der Interrupt eben. Du brauchst nicht, mittels Software einen weiteren 
Mechanismus erfinden, der unmittelbar mit dem ersten Tastendruck 
verknüpft, auch den zweiten Tastendruck verarbeitet. Das täte der zweite 
Interrupt (der hier unerwünscht auftritt) ohnehin.

OK. Was ist also die Lösung?

Du merkst Dir einfach im Interrupt, in einem Flag (denk' ich an volatile 
in der Nacht ...), dass die Taste gedrückt wurde. In der Main-Funktion 
wertest Du dieses Flag aus. Damit ist Deine ISR sehr kurz, was man, als 
Daumenregel, vorziehen sollte.

Probier das mal. - Aber, wie schon ganz oben geschrieben, nur zu 
Übungszwecken - Stand der Technik, oder sagen wir mal: "das übliche und 
bewährte Muster" ist "Entprellung" und "ohne Interrupts für Tasten".

von PINB (Gast)


Lesenswert?

Peter II schrieb:
> Unsinn. und bringt auch nichts. Interrupt sind immer in einer ISR
> gesperrt (beim einem Atmel)

Da sollte jemand noch einmal über die Lehrbücher...

Bitflüsterer schrieb:
> Während das Programm (die ISR), nach dem ersten Tastendruck auf den
> zweiten wartet, wird - bewirkt eben durch dieses zweiten Tastendruck -
> auch der Interrupt ein zweites Mal aktiv (resp. das entsprechende
> Interrupt-Flag gesetzt).

True Story. Das wäre die korrektur zu Peter's aussage

von Udo S. (urschmitt)


Lesenswert?

sentinel schrieb:
> Weiß jmd. wie
> ich das verhindern kann?

Indem man so einen Scheiß nicht macht.
Delays gehören gar nicht in das Programm schon gar nicht in die ISR.
Und die Logik auf einen 2. Tastendruck zu warten gehört über eine 
Statusvariable in die Main Schleife und nicht in die ISR.
Entprellung wurde schon gesagt.
Arbeite hier die Grundlagen unter AVR-Grundlagen und AVR  durch:
http://www.mikrocontroller.net/articles/Hauptseite

von oldmax (Gast)


Lesenswert?

Hi
Wieder einmal das Thema Ich habe einen Kontakt in einer ISR-abgefragt. 
Warum? Eine ISR ist dazuda, Signale nicht zuverpassen. Wenn ndu dein 
Programm mit Warteschleifen aufbaust, kann das gut passieren, das pollen 
eben so manches übersieht. Darumm läßt mann einen Controller auch immer 
frei laufen und wenn es etwas gibt, was eine Zeit erfordert, nutzt man 
den Timer. Darum gibt es auch EVA,, Einlesen, Verarbeiten und Ausgeben. 
Montakte können problemlos im Eingabeabschnitt gepollt werden. Da werden 
sie dann auch entprellt und als gültige Signale abgelegt. Nun kann man 
entscheiden, ob eine weitere Eventsteuerung mittels Jobflags aufgesetzt 
werden soll, sprich Flankenauswertung. Z.B. Du hast ene VAriable namens 
Ablage. In jedem Durchlauf prüfst du mit einer ExclusivOder, ob neue 
Signaleingänge zu den abgelegten unterschiedlich sind Mit einer 1 ist 
ein Unterschied detektiert. Nun nimmst du diese 1 und prüfst, ob der 
neue Wert auf 1 steht (AND), dann hast du die Flanke von 0 nach 1. Oder 
du prüfst, ob der alte Wert 1 war, dann hast du die Flanke von 1 nach 0. 
Nach dieser Prüfung kopierst du den neuen Wert n die Ablage, um im 
nächsten Zyklus wieder auf ein Ereignis zu prüfen. Die Ergebnisbits sind 
dann die Auslöser deiner Aktion. Nach der Bearbeitung werden sie 
gelöscht. Erst, wenn wieder ein Ereignis auftritt, wird die Bearbeitung 
erneut durchgeführt. Die Interrupteingänge sind viel zu wertvoll für 
Kontaktbehaftete Eingänge. Klar, bei einem kleinen Impuls, so bei 5 bis 
10 msek. Signaldauer, da sieht es dann wieder anders aus. Aber da 
erfasst du auch nur das Signal und setzt ein Ereignisbit, um dieses dann 
in der Main abzuarbeiten. Daher gebe ich keinen Rat, wie du die ISR 
verbiegen musst, damit dein Vorhaben Erfolg hat. Denk mal drüber nach.
Gruß oldmax

von oldmax (Gast)


Lesenswert?

Hi
Holla, heut hat meine Tastatur ein Eigenleben.... Sorry für die Fehler.
Gruß oldmax

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.