Forum: Mikrocontroller und Digitale Elektronik AVR Interrupt Problem in C


von K.M. Henkler (Gast)


Lesenswert?

1
int state; 
2
3
ISR (INT0_vect)
4
{  
5
  EIMSK &= ~ (1 << INT0);     // Turns off INT0
6
  _delay_ms(100); // Entprellen des Tasters
7
  
8
  if(state==0) 
9
  {
10
    PORTB |= (1<<PB2); 
11
    state = 1;  
12
  }
13
  
14
  else 
15
  {
16
    PORTB &= ~(1<<PB2);
17
    state = 0; 
18
  }
19
  
20
   EIMSK |= (1 << INT0);     // Turns on INT0
21
}


Moin, ich habe das problem, das mein atmega bei einem interruptz den pin 
kurz high schaltet und danach auch wieder sofort low. also quasi geht er 
beide schritte durch, obwohl ich dort ne if unterscheidung mache, auch 
mit einer switch case anweisung klappt es nicht.

wisst ihr weiter?

von Frederik H. (diveturtle93)


Lesenswert?

Hallo,

Du musst festlegen ob der Interrupt bei einer fallenden oder steigenden 
Flanke ausgelöst wird.

Des Weiteren sollte man keine Wartezeit in der Interrupt-Routine machen.

Wo wird eigentlich die Variable state gesetzt.

von int_42 (Gast)


Lesenswert?

...und der Rest von dem Programm sieht wie aus!

von Marcus P. (marc2100)


Lesenswert?

Hi,
"int state" muss "volatile" sein.
Ansonsten solltest du ein Flag setzten, und die Arbeit im 
"Hauptprogramm" machen.
Den Interrupt brauchst du auch nicht ausschalten, die sind in einem 
Interrupt-Aufruf automatisch gesperrt.

von K.M. Henkler (Gast)


Lesenswert?

Marcus P. schrieb:
> Hi,
> "int state" muss "volatile" sein.

habe ich getestet, ohne veränderungen

> Ansonsten solltest du ein Flag setzten, und die Arbeit im
> "Hauptprogramm" machen.

hm, das wäre mir nun neu, wie kann ich das machen?

> Den Interrupt brauchst du auch nicht ausschalten, die sind in einem
> Interrupt-Aufruf automatisch gesperrt.

ok, da war ich mir nicht sicher, ich hatte in meinen anfängen, als ich 
in "arduino " programmiert habe immer das problem, das er, weil der 
taster nicht hardware seitig entprellt war, ständig neu in den isr 
gegangen ist und dabei irgendwann abgeschmiert ist.

anbei mal meinen test code:
1
#define F_CPU 16000000UL // 16 MHz
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <util/delay.h>
6
7
volatile int state;
8
9
int main(void)
10
{
11
  //state = 0;
12
  DDRD &= ~(1 << DDD2);     // Clear the PD2 pin
13
  // PD2 (PCINT0 pin) is now an input
14
15
  PORTD |= (1 << PORTD2);    // turn On the Pull-up
16
  // PD2 is now an input with pull-up enabled
17
18
   DDRB &= ~((1 << DDB0) | (1 << DDB2));
19
20
21
  EICRA |= (1 << ISC00);    // set INT0 to trigger on ANY logic change
22
  EIMSK |= (1 << INT0);     // Turns on INT0
23
24
  sei();                    // turn on interrupts
25
26
  while(1)
27
  {
28
    PORTB |= (1<<PB0);
29
    _delay_ms(500); 
30
    PORTB &= ~(1<<PB0); 
31
    _delay_ms(500);
32
  }
33
}
34
35
36
37
ISR (INT0_vect)
38
{  
39
  //EIMSK &= ~ (1 << INT0);     // Turns off INT0
40
  _delay_ms(10);
41
  
42
  if(state==0) 
43
  {
44
    PORTB |= (1<<PB2); 
45
    state = 1;  
46
  }
47
  
48
  else 
49
  {
50
    PORTB &= ~(1<<PB2);
51
    state = 0; 
52
  }
53
  
54
   
55
   //EIMSK |= (1 << INT0);     // Turns on INT0
56
}

von test (Gast)


Lesenswert?

Was hängt an dem Pin für "INT0", ein Taster? Wenn ja, vielleicht prellt 
Der und der Interrupt wird mehrmals hintereinander ausgeführt.

von K.M. Henkler (Gast)


Lesenswert?

test schrieb:
> Was hängt an dem Pin für "INT0", ein Taster? Wenn ja, vielleicht
> prellt
> Der und der Interrupt wird mehrmals hintereinander ausgeführt.

arbeite mit einem dev board, welches eigentlich mal für pic controller 
war. wegen dem nachprellen, hatte ich ja an das delay gedacht, aber auch 
wenn ich quasi eine 5V leitung nehme und ganz kurz an den pin halte, 
habe ich das problem.

von K.M. Henkler (Gast)


Angehängte Dateien:

Lesenswert?

sind so Standard Taster

von K.M. Henkler (Gast)


Lesenswert?

1
#define F_CPU 16000000UL // 16 MHz
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <util/delay.h>
6
7
volatile int state;
8
9
int main(void)
10
{
11
  //state = 0;
12
  DDRD &= ~(1 << DDD2);     // Clear the PD2 pin
13
  // PD2 (PCINT0 pin) is now an input
14
15
  PORTD |= (1 << PORTD2);    // turn On the Pull-up
16
  // PD2 is now an input with pull-up enabled
17
18
   DDRB &= ~((1 << DDB0) | (1 << DDB2));
19
20
21
  EICRA |= (1 << ISC00);    // set INT0 to trigger on ANY logic change
22
  EIMSK |= (1 << INT0);     // Turns on INT0
23
24
  sei();                    // turn on interrupts
25
26
  while(1)
27
  {
28
    PORTB |= (1<<PB0);
29
    _delay_ms(500); 
30
    PORTB &= ~(1<<PB0); 
31
    _delay_ms(500);
32
    
33
    if(state==0)
34
    {
35
      PORTB |= (1<<PB2);
36
    }
37
    
38
    else
39
    {
40
      PORTB &= ~(1<<PB2);
41
    }
42
  }
43
}
44
45
46
47
ISR (INT0_vect)
48
{  
49
  //EIMSK &= ~ (1 << INT0);     // Turns off INT0
50
  _delay_ms(10);
51
  
52
  if(state==0) 
53
  {
54
    //PORTB |= (1<<PB2); 
55
    state = 1;  
56
  }
57
  
58
  else 
59
  {
60
    //PORTB &= ~(1<<PB2);
61
    state = 0; 
62
  }
63
  
64
   
65
   //EIMSK |= (1 << INT0);     // Turns on INT0
66
}

so klappt es nun manchmal, aber auch nur sporadisch

von Dieter F. (Gast)


Lesenswert?

Das sieht mir nach einem ATMega16 oder ATMega32 aus - oder?

Müsstest Du dann nicht mit MCUCR und GICR arbeiten (und nicht mit EICRA 
und EIMSK)?

von Hubert G. (hubertg)


Lesenswert?

Eine Taste an INT0 ist nicht gut, da das Prellen immer mehrere ISR 
auslöst.
Da du auch noch auf ANY logic change gestellt hast, wird eine ISR beim 
drücken und eine beim loslassen der Taste ausgeführt. Abschalten nützt 
nichts da die letzte Anforderung gespeichert wird auch wenn die ISR 
gesperrt ist.
Also eine Taste am Besten pollen, oder auf rising edge stellen.

von Rolf M. (rmagnus)


Lesenswert?

K.M. Henkler schrieb:
> aber auch wenn ich quasi eine 5V leitung nehme und ganz kurz an den pin
> halte, habe ich das problem.

Auch die prellt. Dein Delay ist keine adäquate Entprellung. Der 
Interrupt wird durch das Prellen nochmal ausgelöst und das 
Interrupt-Flag gesetzt. Sobald deine ISR fertig ausgeführt ist, wird sie 
gleich wieder ausgeführt.
Mach die Entprellung richtig, dann funktioniert das auch.

K.M. Henkler schrieb:
>> Ansonsten solltest du ein Flag setzten, und die Arbeit im
>> "Hauptprogramm" machen.
>
> hm, das wäre mir nun neu, wie kann ich das machen?

ISRs sollten immer möglichst schnell abgearbeitet sein, weil während 
ihrer Laufzeit der Prozessor blockiert ist und nichts anderes tun kann. 
Aber gerade die Vermeidung von solchen Blockaden ist die Idee hinter dem 
Konzept von Interrupts. Deshalb sind Delays in der ISR ein no-go. Bei so 
einem kleinen Programm mag das noch nicht so wichtig sein, aber besser 
gar nicht erst angewöhnen, denn das führt nur zu Problemen.

: Bearbeitet durch User
von K.M. Henkler (Gast)


Lesenswert?

Dieter F. schrieb:
> Das sieht mir nach einem ATMega16 oder ATMega32 aus - oder?
>
> Müsstest Du dann nicht mit MCUCR und GICR arbeiten (und nicht mit EICRA
> und EIMSK)?

ne ist der 328P

Hubert G. schrieb:
> Eine Taste an INT0 ist nicht gut, da das Prellen immer mehrere ISR
> auslöst.
> Da du auch noch auf ANY logic change gestellt hast, wird eine ISR beim
> drücken und eine beim loslassen der Taste ausgeführt. Abschalten nützt
> nichts da die letzte Anforderung gespeichert wird auch wenn die ISR
> gesperrt ist.
> Also eine Taste am Besten pollen, oder auf rising edge stellen.

jo stimmt, jetzt hat es "klick" gemacht, ja klar so hat er ja immer 2 
veränderungen, ohmann ;)

Rolf M. schrieb:
> K.M. Henkler schrieb:
>> aber auch wenn ich quasi eine 5V leitung nehme und ganz kurz an den pin
>> halte, habe ich das problem.
>
> Auch die prellt. Dein Delay ist keine adäquate Entprellung. Der
> Interrupt wird durch das Prellen nochmal ausgelöst und das
> Interrupt-Flag gesetzt. Sobald deine ISR fertig ausgeführt ist, wird sie
> gleich wieder ausgeführt.
> Mach die Entprellung richtig, dann funktioniert das auch.
>
> K.M. Henkler schrieb:
>>> Ansonsten solltest du ein Flag setzten, und die Arbeit im
>>> "Hauptprogramm" machen.
>>
>> hm, das wäre mir nun neu, wie kann ich das machen?
>
> ISRs sollten immer möglichst schnell abgearbeitet sein, weil während
> ihrer Laufzeit der Prozessor blockiert ist und nichts anderes tun kann.
> Aber gerade die Vermeidung von solchen Blockaden ist die Idee hinter dem
> Konzept von Interrupts. Deshalb sind Delays in der ISR ein no-go. Bei so
> einem kleinen Programm mag das noch nicht so wichtig sein, aber besser
> gar nicht erst angewöhnen, denn das führt nur zu Problemen.

ja ich werde das delay wieder raus nehmen, war ja nur ein test, ob sich 
so was ändert. das eigentliche programm ist auch länger, nur ich habe 
bisher nie was mit interruppts gemacht und hab gedacht, ich schreibe 
besser erstmal nen test programm. auf polling wollte ich verzichten. 
deswegen möchte ich ja interrupts benutzen.


Wollte nochmal Fragen, wie das mit dem Flag gemeint ist. Soll ich quasi 
nur die variable ändern und das pin umschalten zb. dann unter main() 
machen?

von Hubert G. (hubertg)


Lesenswert?

K.M. Henkler schrieb:
> Wollte nochmal Fragen, wie das mit dem Flag gemeint ist. Soll ich quasi
> nur die variable ändern und das pin umschalten zb. dann unter main()
> machen?

Genau so macht man das. Das Problem mit Tastenprellen wirst du aber so 
nur schwer in den Griff bekommen. Du musst dir im main erst wieder eine 
Abfrage einbauen die eine ISR innerhalb eines kurzen Zeitraums 
ignoriert.

von Dieter F. (Gast)


Lesenswert?

K.M. Henkler schrieb:
> ne ist der 328P

Aber nicht auf dem Bild.

Egal, hast Du Dir schon mal Peter Danneggers Routinen angeschaut?

https://www.mikrocontroller.net/articles/Entprellung

Die funktionieren zuverlässig.

von Walter S. (avatar)


Lesenswert?

K.M. Henkler schrieb:
> auf polling wollte ich verzichten.
> deswegen möchte ich ja interrupts benutzen.

eine ganz schlechte Idee wenn man mechanische Taster einlesen will.
Entweder du glaubst das, oder du verstehst das oder du muss deine 
eigenen Erfahrungen machen

von Dieter F. (Gast)


Lesenswert?

K.M. Henkler schrieb:
> auf polling wollte ich verzichten.
> deswegen möchte ich ja interrupts benutzen.

Mit PeDa's Routinen nutzt Du Interrupts (zum pollen :-) )

Ansonsten musst Du halt per Hardware entprellen - Möglichkeiten stehen 
auch im Link.

von K.M. Henkler (Gast)


Lesenswert?

https://sites.google.com/site/qeewiki/books/avr-guide/external-interrupts-on-the-atmega328

Hab die Seite als Hilfestellung benutzt. Auch wegen den Timern ist die 
Top. Gerade wenn man noch lernen muss Datenblätter zu lesen und zu 
verstehen.

Hab den Mode "The falling edge of INTx generates an interrupt request" 
eingefügt. Nun läuft es so wie ich es mir gedacht habe. Das mit dem 
internen Interrupt werde ich mit dem Polling dann auch mal testen. Danke 
euch für die fixe hilfe, ich stand ja voll auf dem schlauch mit dem mode 
des Interrupts.

Man sollte nicht immer nur kopieren sondern auch verstehen was dort 
wirklich gemacht wird ;)

von Dieter F. (Gast)


Lesenswert?

K.M. Henkler schrieb:
> Hab den Mode "The falling edge of INTx generates an interrupt request"
> eingefügt. Nun läuft es so wie ich es mir gedacht habe.

Das ist ja spannend - kannst Du den entsprechenden Code bitte hier 
einstellen? Ich wusste nicht, dass eine Umstellung auf "falling edge" 
die Prellerei eliminiert. Das wäre ja wirklich prima :-)

von K.M. Henkler (Gast)


Lesenswert?

Dieter F. schrieb:
> K.M. Henkler schrieb:
>> Hab den Mode "The falling edge of INTx generates an interrupt request"
>> eingefügt. Nun läuft es so wie ich es mir gedacht habe.
>
> Das ist ja spannend - kannst Du den entsprechenden Code bitte hier
> einstellen? Ich wusste nicht, dass eine Umstellung auf "falling edge"
> die Prellerei eliminiert. Das wäre ja wirklich prima :-)

ich habe mal mit meinem oszi gemessen, ein prellen bzw nachschwingen 
kann ich nicht festtellen, wundert mich ja selber, denke das es 
irgendwie schon entstört ist, da es ein dev board ist. bei meiner 
platine die ich später entwerfen will, werde ich auch hardware seitig 
entprellen, macht vieles software seitig einfacher.

hier noch der code, obwohl ich ja denke das es von dir Ironie war :P
1
#define F_CPU 16000000UL // 16 MHz
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <util/delay.h>
6
7
volatile int state;
8
9
int main(void)
10
{
11
  //state = 0;
12
  DDRD &= ~(1 << DDD2);     // Clear the PD2 pin
13
  // PD2 (PCINT0 pin) is now an input
14
15
  PORTD |= (1 << PORTD2);    // turn On the Pull-up
16
  // PD2 is now an input with pull-up enabled
17
18
   DDRB &= ~((1 << DDB0) | (1 << DDB2));
19
20
21
  EICRA |= (1 << ISC01);    // set INT0 to trigger on ANY logic change
22
  EIMSK |= (1 << INT0);     // Turns on INT0
23
24
  sei();                    // turn on interrupts
25
26
  while(1)
27
  {
28
    PORTB |= (1<<PB0);
29
    _delay_ms(50); 
30
    PORTB &= ~(1<<PB0); 
31
    _delay_ms(50);
32
    
33
    if(state==0)
34
    {
35
      PORTB |= (1<<PB2);
36
    }
37
    
38
    else
39
    {
40
      PORTB &= ~(1<<PB2);
41
    }
42
  }
43
}
44
45
46
47
ISR (INT0_vect)
48
{  
49
  //EIMSK &= ~ (1 << INT0);     // Turns off INT0
50
  //_delay_ms(10);
51
  
52
  if(state==0) 
53
  {
54
    //PORTB |= (1<<PB2); 
55
    state = 1;  
56
  }
57
  
58
  else 
59
  {
60
    //PORTB &= ~(1<<PB2);
61
    state = 0; 
62
  }
63
  
64
   
65
   //EIMSK |= (1 << INT0);     // Turns on INT0
66
}

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.