Forum: Compiler & IDEs Abarbeitung nach Interrupt INT0


von INT-0-8-15 (Gast)


Lesenswert?

Hallo liebe Leute!

Ich habe hier ein einfaches Programm, welches nach dem Einschalten des 
Controllers erstmal nur ein Ampellicht geben soll.
Sobald INT0 aktiv wird (Taster gedrückt wird), so soll die 
Interrrupt-Routine (ISR) ausgeführt werden. Das ist dann einfach ein 
Blinklicht der Ampel auf allen 3 LEDs.
Sobald ich den Taster erneut drücken möchte, soll wieder die normale 
Ampelsteuerung (Rot-Rotgelb-Grün--Gelb-Rot) funkionieren, usw.

Wie realisiere ich das??

Hier der Code:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr/interrupt.h>
4
5
6
7
ISR (INT0_vect)        // Interrupt-Vektor-Service-Routine -> was passiert, wenn Interrupt ausgelöst wird?
8
{
9
  while(1)
10
  {
11
      PORTB = 0x38;
12
      _delay_ms(10);
13
      PORTB = 0;
14
      _delay_ms(10);  
15
  }
16
  
17
}
18
19
20
int main (void)
21
{
22
  
23
  DDRB = 0x38;    
24
25
26
  MCUCR |= (1<<ISC01);
27
  MCUCR &= ~(1<<ISC00);
28
  GIMSK |= (1<<INT0);     // fallende Flanke an INT0 erzeugt Interrupt
29
30
  
31
  sei();            // Interrupts scharf schalten (aktivieren)
32
33
  while(1)
34
  {
35
    PORTB = 0x20;
36
    _delay_ms(30);
37
    PORTB = 0x30;
38
    _delay_ms(10);
39
    PORTB = 0x08;
40
    _delay_ms(30);
41
    PORTB = 0x10;
42
    _delay_ms(10);
43
  }  
44
  return 0;
45
}

Vielen Dank!

von Sven P. (Gast)


Lesenswert?

Die Interrupt-Routine wird nie mehr verlassen. Da beim Eintritt in die 
Routine das I-Flag gelöscht wird, werden bis zum Verlassen keine 
weiteren Interrupts behandelt.
Ergo: Aufgehangen.

Endlosschleifen und Delays in Interruptroutinen sind überdies eh nich so 
prickelnd.

von Detlev T. (detlevt)


Lesenswert?

Da mechanische Taster prellen, ist das mit dem Interrupt keine gute 
Idee. Hier im Forum gibt es diverse Routinen zum Entprellen per 
Software, die du dafür nutzen kannst. Die Ergebnisse fragst du dann 
einfach in der Hauptschleife ab.

Gruß, DetlevT

von Magnetus (Gast)


Lesenswert?

Mal nebenbei bemerkt:

Dir ist schon klar, dass bei deinem Programm eine komplette Ampelphase 
nur 90 Millisekunden dauern würde?

Gruß,
Magnetus

von INT-0-8-15 (Gast)


Lesenswert?

das mit der Ampelphasenlänge ist mir bewusst, da ich das Programm nur 
simuliere und momentan die "virtuelle Taktfrequenz" zu niedrig wäre um 
nicht stundenlang auf einen "Signalwechsel" warten zu müssen. Deshalb 
hab ich die "delay-Zeit" auf nur 30 ms gesetzt.

Vom Entprellen der Taster natürlich abgesehen, mir gehts nur darum, wie 
ich aus der Interrupt-Funktion wieder herauskomme.


Gruß

von docean (Gast)


Lesenswert?

INT-0-8-15 schrieb:
> mir gehts nur darum, wie
> ich aus der Interrupt-Funktion wieder herauskomme.

indem du dort den Pin vom Taster abfragst? statt while(1)

von Grrrr (Gast)


Lesenswert?

Dein Grundgedanke scheint, der Beschreibung entsprechend, gewesen zu 
sein, das das Programm nach dem Tastendruck in einer Sondersituation 
(alle Lichter blinken) ist.

So hast Du aber die Beschreibung der Funktion zu direkt in ein Programm 
umgesetzt.

Zwar soll ein Interrupt die Behandlung von asynchronen Ereignissen 
ermöglichen, aber das heisst nicht, das er auch unmittelbar zur Trennung 
von Betriebsarten dient, d.h. das in main das "normale" Programm abläuft 
und im Interrupt das "besondere" Programm.

Die zwei verschiedenen Abläufe werden beide in main beschrieben. 
Lediglich die Umschaltung zwischen den beiden Abläufen erfolgt im 
Interrupt. Das bedeutet im allgemeinen das setzen einer (volatile) 
Variable im Interrupt, die dann in main abgefragt wird. Passenderweise 
an einer Stelle bei der sinnvolle Übergänge zwischen den Betriebsweisen 
möglich sind.

Was hier über Tastenentprellung gesagt wurde ist dennoch zusätzlich zu 
beachten.

Viel Erfolg

von INT-0-8-15 (Gast)


Lesenswert?

> indem du dort den Pin vom Taster abfragst? statt while(1)

Dann würde der aber doch nur ein einziges Mal das Blinken blinken 
lassen, oder?
1
ISR (INT0_vect)        // Interrupt-Vektor-Service-Routine -> was passiert, wenn Interrupt ausgelöst wird?
2
{
3
  if(PINB == wert)
4
  {
5
      PORTB = 0x38;
6
      _delay_ms(10);
7
      PORTB = 0;
8
      _delay_ms(10);  
9
  }
10
  
11
}


Wäre das nicht doppelgemoppelt? Weil dass der PIN gedrückt wurde, ist ja 
sicher, sonst wäre er erst garnicht in die ISR-Routine gekommen, 
richtig?

Gruß

von Karl H. (kbuchegg)


Lesenswert?

INT-0-8-15 schrieb:

> Wäre das nicht doppelgemoppelt? Weil dass der PIN gedrückt wurde, ist ja
> sicher, sonst wäre er erst garnicht in die ISR-Routine gekommen,
> richtig?

Schon.
Aber deine Frage war ja: wie komme ich aus der ISR wieder raus, wenn der 
Taster losgelassen wird. Und diese Lösung würde realsieren: Solange die 
Taste gedrückt ist, bleibt das Programm in dieser Schleife hängen.

Vielleicht ist dir auch gar nicht bewusst, dass diese Abfrage das hier 
realsiert:

* solange eine Taste gedrückt ist

und nicht

* wenn eine Taste gedrückt wurde, mache einmal


Aber sei gewarnt: Es ist trotzdem die falsche Lösung.
Die richtige Lösung besteht darin, wie weiter oben schon angesprochen, 
dass deine Hauptschleife 2 Modi hat, die per Variable ausgewählt werden. 
In der ISR wird dann einfach nur der andere Modus ausgewählt, in dem die 
Variable entsprechend gestellt wird.

Auf solche nicht absehbar langen Schleifen in einer ISR solltest du dich 
erst gar nicht einlassen.

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.