Frage:
Wie lange kann eine Interrupt-Serviceroutine maximal auf ATmega328P ausgeführt werden?
thebear8
2019-07-11 17:44:36 UTC
view on stackexchange narkive permalink

Ich habe einen ATmega328P, der prüft, ob eine Taste über Pinwechsel-Interrupts gedrückt wurde.Jetzt möchte ich eine LED für 200 ms einschalten. Kann ich die LED einfach einschalten, 200 ms warten und im ISR wie im folgenden Code wieder ausschalten?

  ISR (PCINT1_vect)
{
    if (PINB & 0b1)
    {
         PORT = 0b10;
         Verzögerung (200);
         PORT = 0;
    }}
}}
 

In einigen Forenbeiträgen zu AVR Freaks habe ich gelesen, dass Sie nicht viel Zeit in einem ISR verbringen sollten, aber ich habe nie genaue Zahlen gesehen.Ich kann diese Beiträge leider nicht mehr finden, daher kann ich sie nicht verlinken.Soweit ich mich erinnern kann, sagten alle, dass der Mikrocontroller abstürzen könnte, wenn Sie zu viel Zeit im ISR verbringen. Ist das wahr?Und wenn ja, gibt es danach ein genaues Zeitlimit?

Fünf antworten:
Neil_UK
2019-07-11 17:52:02 UTC
view on stackexchange narkive permalink

Wenn in der MCU nichts anderes ausgeführt wird, können Sie im ISR so lange dauern, wie Sie möchten. Aber , dies ist eine schlechte Angewohnheit, und es bedeutet, dass Sie den Code wahrscheinlich überarbeiten müssen, wenn Sie etwas anderes tun möchten.

Ein besonderer Fall ist, wenn die MCU eine serielle Bibliothek verwendet, die erwartet, dass Interrupts häufig genug funktionieren, um einzelne empfangene Zeichen zu bedienen.Bei 115.200 Baud (eine hohe serielle Geschwindigkeit, die häufig zur Minimierung der Downloadzeit verwendet wird) liegen weniger als 100 µs zwischen den Zeichen.Wenn Sie die Interrupts länger blockieren, besteht die Gefahr, dass Sie Eingabezeichen verlieren.

Führen Sie in der Regel das absolute Minimum in einem ISR aus.In Ihrer Anwendung wäre es sinnvoll, alle ms einen Interrupt zu haben, der einen Zählerwert erhöht und überprüft.Ich bin sicher, Sie können eine geeignete Logik ausarbeiten, um den Zähler so einzustellen und zu testen, dass zwischen dem Ein- und Ausschalten 200 ms liegen.

Dave Tweed
2019-07-11 17:49:14 UTC
view on stackexchange narkive permalink

Im schlimmsten Fall kann ein ISR ausgeführt werden, bis der nächste Interrupt desselben Typs erneut auftritt.

Im Allgemeinen ist es jedoch eine schlechte Entwurfspraxis, mehr Zeit in einem ISR zu verbringen als unbedingt erforderlich, da dadurch verhindert wird, dass der gesamte andere Code überhaupt ausgeführt wird.Dies ist ein großes Problem für alles andere als triviale Programme.

Ich würde sagen, im schlimmsten Fall kann ein ISR unbegrenzt laufen und verhindern, dass der nächste IRQ erneut auftritt.
@DmitryGrigoryev: In diesem Fall meinte ich "Worst Case", da das System NICHT sofort ausfällt.
Brethlosze
2019-07-11 17:51:50 UTC
view on stackexchange narkive permalink

Während die Praxis darin besteht, die minimal möglichen Ausführungszyklen innerhalb einer Unterbrechung und neben anderen allgemeinen Hardwarespezifikationen zuzuweisen, gibt es keine technischen Einschränkungen für deren Erhöhung, wenn keine andere auszuführende Unterbrechung vorliegt.

Bei attachInterrupt () Arduino-Referenz:

Im Allgemeinen sollte ein ISR so kurz und schnell wie möglich sein. Wenn dein Die Skizze verwendet mehrere ISRs, von denen jeweils nur einer ausgeführt werden kann Interrupts werden ausgeführt, nachdem der aktuelle in einer Reihenfolge beendet wurde das hängt von der Priorität ab, die sie haben. millis () ist auf Interrupts angewiesen zu zählen, so wird es nie innerhalb eines ISR inkrementieren. Seit delay () erfordert Interrupts, um zu funktionieren, es funktioniert nicht, wenn es innerhalb eines ISR aufgerufen wird. micros () funktioniert zunächst, verhält sich jedoch nach 1-2 unregelmäßig Frau. delayMicroseconds () verwendet keinen Zähler, daher funktioniert es als normal.

Bei 25 möglichen Unterbrechungen in dieser Prozessorfamilie wird empfohlen, diese wie pünktliche Ereignisse zu behandeln, damit andere Unterbrechungen auftreten können.

Während die Verzögerung in einem ISR im Allgemeinen eine schlechte Idee ist, verwendet die Frage das scheinbar _delay_ms () `von avr-gcc, das auf Zyklen basiert, im Gegensatz zur Arduino` delay () `Funktion, die auf dem Timer-Interrupt beruht.
Dmitry Grigoryev
2019-07-12 13:45:51 UTC
view on stackexchange narkive permalink

Technisch gesehen ist es nicht verboten, innerhalb eines Interrupts eine Endlosschleife zu starten, daher gibt es keine Obergrenze für die ISR-Ausführungszeit. Interrupts sind jedoch am nützlichsten, wenn Sie Ihren normalen Programmablauf unterbrechen möchten, um eine kurze Aktion auszuführen, die sofort ausgeführt werden muss, und die Qualifizierer "kurz". und "sofort" hängen natürlich zusammen: Wenn Ihr längster ISR 1 ms dauert, hat ein eingehender Interrupt mit derselben Priorität eine Antwortzeit von 1 ms. Im Wesentlichen ist Ihre ISR-Ausführungszeit also durch die gewünschte IRQ-Antwortzeit begrenzt.

Wenn Ihr Programm lange in einem Interrupt wartet , ist es möglicherweise einfacher, Interrupts vollständig zu löschen und Polling zu verwenden, was die Programmierung erheblich vereinfacht.

Es gibt Fälle, in denen Sie Interrupts missbrauchen können, um mehr oder weniger regulären Code auszuführen. Ein Beispiel wäre die Implementierung einer Aufgabenpriorität: Eine Aufgabe mit niedriger Priorität wird aus der Hauptschleife gestartet, während eine Aufgabe mit höherer Priorität ein periodisch ausgelöster Timer-Interrupt ist. Dies erfolgt normalerweise auf MCUs mit mehreren IRQ-Prioritätsstufen, sodass das System bei Bedarf weiterhin über reguläre ISRs verfügen kann.

AaronD
2019-07-12 03:21:12 UTC
view on stackexchange narkive permalink

Sie haben eine Single-Core-Single-Threaded-CPU. Dies bedeutet, dass zu jedem Zeitpunkt genau eines getan wird. Wenn Ihre Anwendung mehrere Aufgaben erfordert, muss der Code so gestaltet sein, dass zwischen allen gewechselt werden kann. Dies kann so trivial oder so komplex sein, wie Sie möchten.

Normalerweise puttert die CPU um die Hauptschleife und macht alles, was sich dort befindet, und das ist alles gut und schön, bis ein Interrupt auftritt. Die Interrupt-Hardware erzwingt grundsätzlich einen Funktionsaufruf an das entsprechende ISR, obwohl es in der Hauptschleife keine Aufrufanweisung dafür gibt. Aufgrund dieser Unvorhersehbarkeit stammen die meisten Regeln für das Schreiben von ISRs.

Unabhängig davon, wie viel Zeit Sie in einem ISR verbringen, wird die Hauptschleife angehalten und auf die Rückkehr des ISR gewartet. Wenn die Hauptschleife die einzige ist, die einen aktiven Watchdog-Timer zurücksetzt (sehr gute Praxis), wird der Watchdog während dieser Zeit nicht zurückgesetzt. Wenn der Watchdog eine Zeitüberschreitung aufweist, wird ein Hard-Reset durchgeführt. Genau wie beim externen Zurücksetzen, jedoch mit verschiedenen Flags, die Sie beim Start überprüfen können. Dies ist wahrscheinlich der "Absturz", von dem Sie gehört haben.


Es ist sehr empfehlenswert, den Watchdog zu verwenden und ihn bei jeder Fahrt um die Hauptschleife nur einmal zurückzusetzen. Dies zwingt Sie dazu, Code zu schreiben, der reagiert. Wenn Sie auf etwas warten müssen, können Sie ein Ereignis einrichten (Timer abgelaufen, nächster Charakter empfangen usw.) und fortfahren. Suchen Sie regelmäßig nach diesem Ereignis oder setzen Sie einen anderen Interrupt auf dessen Abschluss und kehren Sie dann zu diesem zurück. In der Zwischenzeit fahren Sie mit dem fort, was Sie sonst noch getan haben.

Meine Hauptstruktur sieht normalerweise so aus:

  #include "module1.h"
#include "module2.h"

void main (void)
{
    //insgesamt
    //Chip
    //Konfiguration

    mod1_init ();
    mod2_init ();

    // Interrupt-Flags löschen
    // globale Interrupt-Aktivierung

    während (1)
    {
        // Wachhund löschen

        mod1_run ();
        mod2_run ();
    }}
}}
 

Und meine Module sind wie folgt:

  void modX_init (void)
{
// Hardware und Variable init nur für dieses Modul
    // Verwenden Sie keine Interrupts, wenn die Abfrage gut genug ist
}}

void modX_run (void)
{
    if (POLLED_INTERRUPT_FLAG)
    {
        POLLED_INTERRUPT_FLAG = 0;

        // nicht blockierender "ISR" -Code
    }}
}}

void ISR modX_ISR (void)
{
    // Okay, dies erfordert eine * sofortige * Antwort
    // verbringe die absolute Mindestzeit hier und steige aus
}}
 

Die Funktionssignaturen müssen nicht void sein, die meisten jedoch. Manchmal habe ich ein breites Timing in einem Modul, das auch von einem anderen verwendet wird, und es ist praktisch, den Rückgabewert eines modX_run () und die Argumente eines anderen (oder einer grundlegenden Logik) zu verwenden Stellen Sie diese Verbindung her. Zum Beispiel:

  if (DMX_run ()) // enthält ein eigenes Timing und gibt zu Beginn jedes 30-Hz-Intervalls true zurück, andernfalls false
{
    I2C_start (); // I2C-Frames werden mit DMX synchronisiert
}}
I2C_run (); // Einmal gestartet, läuft ein I2C-Frame frei, bis er fertig ist
 

Wenn Sie das Datenblatt studieren, stellen Sie möglicherweise auch fest, dass die Hardware-Peripheriegeräte massiert werden können, um das zu tun, was Sie wollen, ohne dass die CPU eingreift.

Die Erzeugung von Ausgangsimpulsen ist beispielsweise weit verbreitet. Schalten Sie es ein, stellen Sie das Peripheriegerät so ein, dass es einige Zeit später ausgeschaltet wird, und vergessen Sie es. Es befindet sich normalerweise im selben allgemeinen Bereich wie PWM.



Diese Fragen und Antworten wurden automatisch aus der englischen Sprache übersetzt.Der ursprüngliche Inhalt ist auf stackexchange verfügbar. Wir danken ihm für die cc by-sa 4.0-Lizenz, unter der er vertrieben wird.
Loading...