ATmega8 Interrupt wird zwei Mal ausgeführt

OP #5591714
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
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
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.
OP
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
}
Gast
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.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 8 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.