Forum: Mikrocontroller und Digitale Elektronik ATmega8 Interrupt wird zwei Mal ausgeführt


von Michi R. (snowsaw)


Lesenswert?

Hallo

In der Schlaufe legt sich der uC gleich schlafen.
Mit INT0 wird er wieder geweckt.
Nun läuft der Code in der ISR jedoch zwei mal ab. Warum?
1
/*
2
  IC: ATmega8
3
 */ 
4
5
#define F_CPU 3686400UL
6
#include <avr/io.h>
7
#include <util/delay.h>
8
#include <avr/sleep.h>
9
#include <avr/interrupt.h>
10
11
// global variable to count the number of overflows
12
volatile uint8_t tot_overflow;
13
14
void goSleep()
15
{
16
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
17
    GICR |= (1 << INT0); // enable external interrupt
18
    sleep_enable();
19
    sleep_cpu();
20
    sleep_mode();
21
    sleep_disable();
22
    GICR &= ~(1 << INT0); // disable external interrupt here, in case the external low pulse is too long
23
}
24
25
int main(void)
26
{
27
  DDRB |= (1 << PB0);   // Setzen Output
28
  DDRB |= (1 << PB1);   // Setzen Output
29
  DDRB |= (1 << PB2);   // Setzen Output
30
  PORTC |= (1 << PC1);   // Setzen PulUp Eingang
31
  PORTD |= (1 << PD2);   // Setzen PulUp Eingang
32
  
33
  MCUCR &= ~((1 << ISC01) | (1 << ISC00)); // INT0 fallende Flake
34
  sei();
35
  
36
  while(1){
37
    PORTB |= (1 << 1);  // led ein
38
    goSleep();  // schlafen
39
  }  
40
}
41
42
ISR(INT0_vect)
43
{
44
  PORTB &= ~(1 << 1);  // led aus
45
  PORTB &= ~(1 << 2);  // led aus
46
  _delay_ms(200);
47
  PORTB |= (1 << 2);  // led ein
48
  _delay_ms(200);
49
  PORTB &= ~(1 << 2);  // led aus
50
  _delay_ms(200);
51
  PORTB |= (1 << 2);  // led ein
52
  _delay_ms(200);
53
  PORTB &= ~(1 << 2);  // led aus
54
}

Danke

von Max D. (max_d)


Lesenswert?

Ich bin zu faul ins DB zu gucken welche der beiden Versionen zutrifft:
1. Dein Kommentar zum Interruptmodus stimmt, dann setzt Kontaktprellen 
dir den flag gleich nach dem Eintritt nochmal
2. Dein Kommentar in gosleep stimmt, dann springt er dir da vor dem 
abschalten des interrupts raus und führt die isr aus bis der low weg ist

von Michi R. (snowsaw)


Lesenswert?

Was könnte man im DB nachschauen?

von Max D. (max_d)


Lesenswert?

Michi R. schrieb:
> MCUCR &= ~((1 << ISC01) | (1 << ISC00)); // INT0 fallende Flake

impliziert Flankenauslösung (einmalig wenn Pin 1->0 geht)

Michi R. schrieb:
> GICR &= ~(1 << INT0); // disable external interrupt here, in case the
> external low pulse is too long

impliziert Pegelinterrupt (solange Pin = 0 wird getriggert)

Das Datenblatt sagt dann:
ISC00 = 0; ISC01 = 0; The low level of INT0 generates an interrupt 
request;

Ergo ist dein Kommentar neben der Zuweisung schlicht FALSCH.
Solange dein Pin low ist feuert der Interrupt ununterbrochen.

Falls du den Pegelinterrupt behalten willst, dann schalte die 
Interruptbehandlung schon in der ISR aus (aber vor dem Schlafengehen 
wieder an natürlich).

Beitrag #5594721 wurde von einem Moderator gelöscht.
von Michi R. (snowsaw)


Lesenswert?

So geht es...

Nach dem Aufwachen wird der Interrupt nur einmal ausgeführt.

Mir ist noch nicht so ganz klar warum. Auf jeden Fall wird cli() erst in 
den darauffolgenden Tackten ausgeführt und die Interrupts sind während 
des Schlafens aktiv.

1
void goSleep()
2
{
3
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
4
  cli();
5
  sleep_enable();
6
  sei();
7
  sleep_cpu();
8
  sleep_disable();
9
}
10
11
ISR(INT0_vect)
12
{
13
  GICR &= ~(1 << INT0); // disable external interrupt here, in case the external low pulse is too long
14
  GIFR |= (1 << INTF0);  // int0 reset
15
  GICR |= (1 << INT0); // enable external interrupt
16
}

von MWS (Gast)


Lesenswert?

Michi R. schrieb:
> GICR &= ~(1 << INT0);
> ...
> GICR |= (1 << INT0);

Ist Quatsch, in der ISR sind Interrupts global gesperrt und zum Löschen 
eines Int-Flags muss man den entsprechenden Interrupt auch nicht 
ausschalten.

Nur das Löschen des Int-Flags macht Sinn um ein weiteres eingetretenes 
Triggerereignis zu löschen.

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.