ISR wird nach einem Pinchange Interrupt 2x ausgeführt?

OP #2581281
Lesenswert?

Hallo!

Ich verwende den ATtiny44 und über den PCINT0 wird eine ISR bei 
positiver Flanke ausgelöst und eine AD-Wandlung durchgeführt.
Wird ein Interrupt ausgelöst, springt mein Debugger nach Ausführung der 
ISR nochmals in die ISR. Erst danach wird das Programm weiter 
ausgeführt.

Hat jemand einen Tip was da sein könnte?
Moderator Persönliche Seite #2581288
Lesenswert?

H. G. schrieb:
> Ich verwende den ATtiny44 und über den PCINT0 wird eine ISR bei
> positiver Flanke ausgelöst und eine AD-Wandlung durchgeführt.
> Wird ein Interrupt ausgelöst, springt mein Debugger nach Ausführung der
> ISR nochmals in die ISR. Erst danach wird das Programm weiter
> ausgeführt.

Bei einem PCINT kann man nicht vorgeben, ob er bei einer steigenden oder 
fallenden Flanke aufgerufen wird. Er wird in jedem Fall bei beiden 
Flanken aufgerufen.

> Hat jemand einen Tip was da sein könnte?

Wenn obiges nicht zutrifft, muss es an der Zeile 42 in Deinem Programm 
liegen ;-)
#2581337
Lesenswert?

Ggf. den Interupt in der ISR beim ersten Aufruf erstmal deaktivieren und 
mit einem Timer nach n ms wider aktivieren, wenn der PCINT nicht noch 
andere Pins abfragen muss die während der Deaktivierungszeit eintreffen 
könnten.

Dann hätte man auch das Tastenentprellen mit erledigt.
OP #2581382
Lesenswert?

Ich habe jetzt versucht, gleich am Anfang der ISR alle Interrupts zu 
deaktivieren und nicht wieder zu aktivieren.

Trotzdem springt der Debugger ein 2. Mal rein. ???
Kann ja normal nicht sein, oder?

Hier meine ISR:
1
// ***********     Pin change INT0 service routine      *************
2
ISR (PCINT0_vect)
3
{
4
    cli();
5
    ADMUX   &= !(1<<MUX0);             // Auf ADC-Kanal 0 umschalten
6

7
    ADCSRA |= (1<<ADSC);                  // Start ADC-Converter
8
      while (ADCSRA & (1<<ADSC));          // wait for ADC-Conversion
9
      x = ADC;                // Dummy read out
10

11
    ADCSRA |= (1<<ADSC);                  // Start ADC-Converter
12
      while (ADCSRA & (1<<ADSC));          // wait for ADC-Conversion
13
      switch_value2 = ADC;          // Value for endswitch
14
    
15
    ADCSRA |= (1<<ADSC);                  // Start ADC-Converter
16
      while (ADCSRA & (1<<ADSC));          // wait for ADC-Conversion
17
      switch_value3 = ADC;          // Value for endswitch
18
    
19
    switch_value = (switch_value2 + switch_value3) / 2;    // ADC Durchschnittswert berechnen
20

21
    if ( (switch_value >= 849) && (switch_value <=988) )  // 4,15V ... 4,8V
22
    {
23
      ES1 = 1;
24
      ES2 = 0;
25
    }
26

27
    if ( (switch_value >= 661) && (switch_value <=767) )  // 3,23V ... 3,75V
28
    {
29
      ES2 = 1;
30
      ES1 = 0;
31
    }
32

33
    ADMUX   |= (1<<MUX0);             // Auf ADC-Kanal 1 umschalten
34

35
    ADCSRA |= (1<<ADSC);                  // Start ADC-Converter
36
      while (ADCSRA & (1<<ADSC));          // wait for ADC-Conversion
37
      x = ADC;                // Dummy read out
38
    
39
    //sei();
40
}
OP #2581394
Lesenswert?

Udo Schmitt schrieb:
> H. G. schrieb:
>> Hast du ein Beispiel mit einem Timer Interrupt in C für eine Taste?
>
> Der nächste Software-Guttenberg.
> Und was er kopieren kann ist ihm nicht einfach genug, deshalb fragt er
> nach etwas noch einfacherem...
> Ohne Worte

Ich fragte nach einem Beispiel und nicht nach einem fertig angepassten 
Code! Ist dir langweilig oder warum müllst du das Forum mit solch 
unqualifizierten Ansagen voll? Oder darf man hier im Forum nicht fragen? 
Ist das ein Forum nur für Profis? Anfänger raus?
#2581413
Lesenswert?

H. G. schrieb:
> 20?
>
> Da hab ich dann wohl ein anderes Beispiel angesehen!
> Hast du einen Link?

Auf wieviele Assembler Instruktionen läuft das wohl im Compiler raus.
1
ISR( TIMER0_OVF_vect )                            // every 10ms
2
{
3
  static uint8_t ct0, ct1, rpt;
4
  uint8_t i;
5
 
6
  i = key_state ^ ~KEY_PIN;                       // key changed ?
7
  ct0 = ~( ct0 & i );                             // reset or count ct0
8
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
9
  i &= ct0 & ct1;                                 // count until roll over ?
10
  key_state ^= i;                                 // then toggle debounced state
11
  key_press |= key_state & i;                     // 0->1: key press detect
12
 
13
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
14
     rpt = REPEAT_START;                          // start delay
15
  if( --rpt == 0 ){
16
    rpt = REPEAT_NEXT;                            // repeat delay
17
    key_rpt |= key_state & REPEAT_MASK;
18
  }
19
}

Den Aufwand in der ISR kannst du vernachlässigen, das kostet deinen µC 
weniger als 1% Rechenzeit. Und das geile ist: Das funktioniert von 1 bis 
8 Tasten ohne Codeänderung. Selbst bei 1 Taste lohnt sich der Code 
schon, weil die Entprellung zuverlässig funktioniert und du keinen 
Tastendruck deines Benutzers verpasst. Und einen Auto-Repeat der bei 
gedrückter Taste dem Programm weitere Tastendrücke vorgaukelt, kriegst 
du automatisch mit dazu (besonders cool bei Zahleneingaben mittels 
Up-Down einzusetzen)

Oft genug bewährt, oft genug eingesetzt. Es lohnt ganz einfach nicht, 
sich da auch nur den geringsten Gedanken über eine andere Lösung zu 
machen. Dieses Ding ist in 10 Minuten in einen Code integriert und 
funktioniert bullet-proof.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren