Forum: Mikrocontroller und Digitale Elektronik Interrupts deaktiviert, ISR wird trotzdem benötigt?


von Hugo P. (portisch)


Lesenswert?

Hallo,

Ich habe eine kleine Funktion die auf einen Interrupt von INT1 wartet um 
die Pulszeit am INT1 zu messen.
1
uint16_t Capture(void)
2
{
3
  uint8_t sreg = SREG;
4
  cli(); // disable IRQs
5
6
  // enable external interrupt INT1, rising edge
7
  EICRA = (1 << ISC11) | (1 << ISC10);
8
  EIMSK = (1 << INT1);
9
  EIFR = (1 << INTF1);
10
11
  // wait for rising edge
12
  while(! (EIFR & (_BV(INTF1))));
13
  
14
  TCNT1 = 0;
15
  // switch to falling edge
16
  EICRA = (1 << ISC11);
17
  EIFR = (1 << INTF1);  
18
  
19
  // wait for falling edge
20
  while(! (EIFR & (_BV(INTF1))));  
21
  
22
  ret = TCNT1;
23
  
24
  SREG = sreg; // enable IRQs
25
  
26
  return ret;
27
}

Nun resetet sich der AVR aber immer. Sobald ich die ISR einfüge läuft 
es:
1
ISR (INT1_vect) {}

Dann wird sie aber trotzdem aufgerufen, oder?
Ich habe mir gedacht, dass nach dem cli() die ISR nicht gebraucht 
werden, oder? Wie kann ich die ISR "wegoptimieren"?

Ich habe AVR Studio 5.1 mit AVR/GCC.

von Wilhelm M. (wimalopaan)


Lesenswert?

Weil der Interrupt "pending" ist und sobald Du die Interrupts mit sei() 
wieder global einschaltest, der Int ausgelöst wird, weil das 
entsprechende Flag noch gesetzt ist

von Peter D. (peda)


Lesenswert?

Hugo P. schrieb:
> Ich habe mir gedacht, dass nach dem cli() die ISR nicht gebraucht
> werden, oder?

Sofern nach dem cli() nie wieder ein sei() aufgerufen wird, geht das 
auch.


Hugo P. schrieb:
> Wie kann ich die ISR "wegoptimieren"?

Einfach nicht den zugehörenden Interrupt freigeben.

: Bearbeitet durch User
von Ingo L. (corrtexx)


Lesenswert?

Hugo P. schrieb:
> EIMSK = (1 << INT1);
Warum aktivierst du den Interrupt überhaupt, wenn du ihn nicht nutzen 
willst? Das INTF1 wird unabhängig, ob du einen Interrupt auslösen 
willst, gesetzt wenn die hier
1
 EICRA = (1 << ISC11) | (1 << ISC10);
aufgeführte Bedingung erfüllt wird.

von Wilhelm M. (wimalopaan)


Lesenswert?

Die Frage ist eher, warum überhaupt einen ext. Interrupt einschalten, 
wenn man ihn nicht haben will. Im grunde wird ja ein Polling gemacht, 
dann braucht man keine Interrupts.

von Xperte (Gast)


Lesenswert?

Wobei sich natürlich die Frage stellt warum du Interrupts aktiviert hast 
aber dann nicht nutzen willst.  Falscher Ansatz bzw. Denkfehler?

Hugo P. schrieb:
> Wie kann ich die ISR "wegoptimieren"?

Indem du keine Interrupts benutzt.

von Hugo P. (portisch)


Lesenswert?

Das löschen von
1
EIMSK = (1 << INT1);
ist die Lösung. Somit wird die ISR nicht aufgerufen.

von Theor (Gast)


Lesenswert?

@ Hugo

Also, mich würde ja auch mal interessieren, ob es einen vernünftigen 
Grund gibt, das so zu machen.

Das Verfahren hat aus meiner Sicht nur Nachteile.

1. Zusätzlicher Aufwand um EICRA, EIMSK und EIFR zu bedienen.
2. Ein Busy-Waiting auf die jeweilige Flanke.

Den Zweck könnte man auch ohne 1. erreichen, selbst wenn man 
Busy-Waiting verwendet.

Und Busy-Waiting wendet man, meiner Meinung nach, auch nur in den ersten 
Programmen an, um das Prinzip der Erkennung von Flanken mal zu lernen. 
Oder, falls definitiv klar ist, dass die nachfolgende Änderung in einem 
Zeitabstand kommt, der nicht gemessen werden muss und kürzer ist, als es 
bräuchte, um einen Timer zu konfigurieren. (Also etwa Status-Abfragen in 
der UART).

Ausserdem kann das, wenn man schon soweit ist, der Timer von alleine - 
ohne Busy-Waiting, so dass die CPU nebenbei noch anderes tun kann.

Magst Du das mal erklären?


Mal Code ohne EICRA und Konsorten (mit irgendeinem Pin der auf Eingang 
konfiguriert ist).
1
uint16_t Capture(void)
2
{
3
  // wait for low
4
  while (! (PORT & (1 << PIN)));
5
  // wait for high
6
  while (PORT & (1 << PIN));
7
8
  ; rising edge occurred
9
10
  TCNT1 = 0;
11
  
12
  // wait for falling edge
13
  while (! (PORT & (1 << PIN)));
14
15
  return (TCNT1);
16
}

von Purzel H. (hacky)


Lesenswert?

> Ich habe eine kleine Funktion die auf einen Interrupt von INT1 wartet um
die Pulszeit am INT1 zu messen.

Ist ganz schlechter Stil. Man sollte nie in einer Funktion warten. Das 
nennt sich blockierend. Und ist sehr schwer zu debuggen. Mach alle 
Funktionen nicht blockierend und warte ausschliesslich im Main.

Mach eine Zustandsvariable im Main und benutze diese zum Reagieren und 
auch zum Debuggen

von Wilhelm M. (wimalopaan)


Lesenswert?

Gorch F. schrieb:
>> Ich habe eine kleine Funktion die auf einen Interrupt von INT1 wartet um
> die Pulszeit am INT1 zu messen.
>
> Ist ganz schlechter Stil.

Naja, Stil ist für manche ja das Ende des Besens ...

> Man sollte nie in einer Funktion warten. Das
> nennt sich blockierend. Und ist sehr schwer zu debuggen.

Ich sehe überhaupt keinen Grund, warum das schwer zu debuggen sein 
sollte.

> Mach alle
> Funktionen nicht blockierend und warte ausschliesslich im Main.

Oh, nun ist main() blockierend ... ups

Oftmals kann bei simplen Anwendungen die Variante ohne Interrupts 
sinnvoller sein: der Compiler kann besser optimieren und so manche 
push/pop-Orgien sind auch unnötig.

Also: ob polling in simplen µC Anwendungen ohne OS schlecht oder gut 
ist, hängt von einigen Faktoren ;-)

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.