Forum: Mikrocontroller und Digitale Elektronik ISR wird nach einem Pinchange Interrupt 2x ausgeführt?


von H. G. (ledi)


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?

von Peter D. (peda)


Lesenswert?

H. G. schrieb:
> Hat jemand einen Tip was da sein könnte?

Ja, Deine (jede) Taste prellt.
Deshalb Tasten nie mit einem externen Interrupt abfragen!
Sondern mit einem Timerinterrupt entprellen.


Peter

von Frank M. (ukw) (Moderator) Benutzerseite


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 ;-)

von Dirk .. (kcc)


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.

von H. G. (ledi)


Lesenswert?

Peter Dannegger schrieb:
> ...Sondern mit einem Timerinterrupt entprellen.

Hallo Peter!

Ich habe mir deine Komfortroutine etwas angesehen, aber das ist 
natürlich ein overkill für eine einzige Taste welche am PCINT0 hängt.

Hast du ein Beispiel mit einem Timer Interrupt in C für eine Taste?

von Peter D. (peda)


Lesenswert?

H. G. schrieb:
> Ich habe mir deine Komfortroutine etwas angesehen, aber das ist
> natürlich ein overkill für eine einzige Taste welche am PCINT0 hängt.

Das ist so wenig Code, das ist selbst für nur eine Taste effizient.
Den Repeat-Teil kann man ja weglassen, wenn man ihn nicht benötigt.


Peter

von Udo S. (urschmitt)


Lesenswert?

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

von H. G. (ledi)


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
}

von H. G. (ledi)


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?

von Karl H. (kbuchegg)


Lesenswert?

H. G. schrieb:

> Hier meine ISR:

Un du machst dir Sorgen um die 20 (Assembler-)Instruktionen (auf die der 
C-Code hinausläuft) in der PeDa Entprell-Lösung?

von Stefan E. (sternst)


Lesenswert?

H. G. schrieb:
> Kann ja normal nicht sein, oder?

Doch, denn das Sperren der Interrupts (und gesperrt sind sie in der ISR 
sowieso, dein cli() macht also in Wirklichkeit gar nichts) hat keinen 
Einfluss darauf, dass beim Eintreffen eines Ereignisses das 
entsprechende Interrupt-Flag gesetzt wird.

von H. G. (ledi)


Lesenswert?

20?

Da hab ich dann wohl ein anderes Beispiel angesehen!
Hast du einen Link?

von Peter D. (peda)


Lesenswert?

H. G. schrieb:
> Kann ja normal nicht sein, oder?

Doch, siehe Abschnitt:
4.8 Reset and Interrupt Handling

Es gäbe da einen dirty Hack: direkt vor dem Enable das Interruptflag 
setzen.


Peter

von Thomas E. (thomase)


Lesenswert?

H. G. schrieb:
> Hast du einen Link?
Kriegst du auch irgendwas alleine hin?

mfg.

von Karl H. (kbuchegg)


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.

von H. G. (ledi)


Lesenswert?

DANKE! Das hilft mir weiter!

von Karl H. (kbuchegg)


Lesenswert?

stammt von
Entprellung

Lass dich nicht von der Anzahl der C Zeilen blenden. Entscheidend ist, 
was nach dem Compilieren übrig bleibt. Und das ist nicht viel.

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.