mikrocontroller.net

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


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Hugo P. (portisch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Ich habe eine kleine Funktion die auf einen Interrupt von INT1 wartet um 
die Pulszeit am INT1 zu messen.
uint16_t Capture(void)
{
  uint8_t sreg = SREG;
  cli(); // disable IRQs

  // enable external interrupt INT1, rising edge
  EICRA = (1 << ISC11) | (1 << ISC10);
  EIMSK = (1 << INT1);
  EIFR = (1 << INTF1);

  // wait for rising edge
  while(! (EIFR & (_BV(INTF1))));
  
  TCNT1 = 0;
  // switch to falling edge
  EICRA = (1 << ISC11);
  EIFR = (1 << INTF1);  
  
  // wait for falling edge
  while(! (EIFR & (_BV(INTF1))));  
  
  ret = TCNT1;
  
  SREG = sreg; // enable IRQs
  
  return ret;
}

Nun resetet sich der AVR aber immer. Sobald ich die ISR einfüge läuft 
es:
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.

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
1 lesenswert
nicht 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

Autor: Peter D. (peda)
Datum:

Bewertung
0 lesenswert
nicht 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
Autor: Ingo L. (corrtexx)
Datum:

Bewertung
0 lesenswert
nicht 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
 EICRA = (1 << ISC11) | (1 << ISC10);
aufgeführte Bedingung erfüllt wird.

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
2 lesenswert
nicht 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.

Autor: Xperte (Gast)
Datum:

Bewertung
1 lesenswert
nicht 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.

Autor: Hugo P. (portisch)
Datum:

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

Autor: Theor (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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).
uint16_t Capture(void)
{
  // wait for low
  while (! (PORT & (1 << PIN)));
  // wait for high
  while (PORT & (1 << PIN));

  ; rising edge occurred

  TCNT1 = 0;
  
  // wait for falling edge
  while (! (PORT & (1 << PIN)));

  return (TCNT1);
}

Autor: Name H. (hacky)
Datum:

Bewertung
2 lesenswert
nicht 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

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
-3 lesenswert
nicht 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 ;-)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.