Forum: Mikrocontroller und Digitale Elektronik allg. Frage zu Interrupts und Programmablauf (in C)


von Hans Meier (Gast)


Lesenswert?

Hallo,

so langsam bin ich völlig am verzweifeln, stehe mit dem uC auf
"Kriegsfuss" ;=)
Bevor ich mit was großem weiter mache, muss ich erwst weiter Grundlagen
lernen. Was ein Interrupt ist, was er macht, wer wann die Steuerung
übernimmt ist mir soweit klar. Einzig und allein zur Implementierung
(in C) habe ich eine Frage. Meinetwegen habe ich so etwas:

void main (void)
{
   // Schleife die immer läuft
   while (1)
   {
      // Schleife die nur läuft wenn der Interrupt ausgelöst wurde
      while (interrupt_ausgeloest)
      {
         // mach was :=)
         pause
         Ports lesen
         Ports schreiben
         usw.

         [...]

         interrupt_ausgeloest = 0;
      }
   }
}

void Interruptroutine (void)
{
   interrupt_ausgeloest = 1;
}


Was den Interrupt auslöst ist erstmal egal. Was ich letztendlich haben
möchte: wenn der Interrupt ausgelöst wurde, soll im Hauptprogramm eine
"extra-Schleife" abgearbeitet werden und zwar immer (!) vom Beginn ab
an. Obiges macht das ja fast soweit, nur was passiert wenn der Interrupt
2 mal "schnell" hintereinander ausgelöst wird? Soweit ich das
verstehe, passiert da nichts weiter, die while (interrupt_ausgeloest)
Schleife läuft einfach an der alten Stelle weiter (ok, das
Hauptprogramm wird unterbrochen, die Interruptroutine wird abgearbeitet
und das Hauptprogramm wird an der alten (!) Stelle fortgesetzt (also
nicht wie gewünscht von Beginn an)). Sie beginnt also nicht so wie von
mir gewünscht von vorne.

Wie kann ich dieses Problem lösen? Soll die ganze Interrupt-Schleife in
die Interruptroutine (was passiert dann bei 2 "schnellen"
Interrupts?), kann man die while schleife immer von Anfang an beginnen
(wäre mir am liebsten)?

Freue mich über jeden Tipp, Link, Codeschnipsel...

Gruß,

Hans

von Elektrolurch (Gast)


Lesenswert?

if (interrupt_ausgeloest == 1) danach gleich die Variable auf 0 setzen
und dann mit der Portmanipulation fortfahren. Wenn inzwischen der
Interrupt noch einmal auftritt, wird im Hauptprogramm wieder in den
Programmteil verzweigt.

von ...HanneS... (Gast)


Lesenswert?

Hi...

Also wenn der Umgang mit Interrupts unter C wirklich so umständlich und
kompliziert sein sollte, dann werde ich wohl für immer bei Assembler
bleiben.

Da kümmert mich der Int in der Hauptschleife nicht, denn jeder Int hat
seine eigene ISR, die beim Aufruf abgearbeitet wird. Und in dieser kann
man Flags (Bits in einem dafür reservierten Register) setzen, auf die
die Hauptschleife reagieren kann...

Bit- & Bytebruch...
...HanneS...

von Olaf Stieleke (Gast)


Lesenswert?

Ich hab das vor geraumer Zeit gelernt: Was bei einem IRQ passieren soll,
gehört in den IRQ-Handler, nicht ins Main.

Wäre es nicht also sinnvoller, die Schleife direkt im Interrupt-Handler
ablaufen zu lassen (womit es dann keine Schleife mehr wäre)? Dann würde
sich das Problem mit zwei schnell nacheinander auftretenden IRQ's
nicht stellen (SEI vorausgesetzt).

Darüber hinaus kann der IRQ-Handler ja noch immer ein Flag setzen, das
das Hauptprogramm "wenn es Zeit hat" auswertet.

von Hans Meier (Gast)


Lesenswert?

Hallo,

erst mal danke für die Antworten.

@Elektrolurch:
bist du dir da sicher? Wenn der Interrupt abgearbeitet wurde, kehrt der
uC doch an seine alte Stelle im Programm zurück, also mitten in die if
Schleife und nicht an den Anfang (bzw. sogar noch davor wo die
Bedingugn geprüft wurde), oder irre ich da gewaltig?

@...HanneS...
Keine Angst, das geht in C ja genauso. z.B. folgendes:
SIGNAL (SIG_INTERRUPT0)
{
    // int 0 ausgelöst
}

SIGNAL (SIG_OVERFLOW1)
{
    // Überlauf 1 ausgelöst
}

SIGNAL (SIG_UART_RECV)
{
    // Empfangen
}
usw.
Es interessiert mich einzig und allein dein Satz "...auf die
die Hauptschleife reagieren kann...". Das ist mein "Problem".

@Olaf Stieleke:
Bis jetzt habe ich immer nur gelesen und gelernt, das eine Interrupt
Routine möglichst kurz/schnell fertig sein sollte. "Leider" muss ich
auch ein paar Takte bei der Abarbeitung warten.

Gruß,

Hans

von Joline (Gast)


Lesenswert?

Hi,

Interrupts werden durch bestimmte Ereignisse ausgelöst, z.B.
Timer-Überlauf (passiert, wenn bspw. der 8-Bit-Timer > 255 werden
würde). Auf diese Interrupts kann man reagieren, indem man bestimmte
ISR (Interrupt-Service-Routinen) in sein Programm einbaut, also z.B.

SIGNAL (SIG_OVERFLOW0)
{

}

um mal beim 8-Bit-Timer zu bleiben.

Der Sinn solcher Funktionen liegt nun darin, das gerade laufende
Programm zu unterbrechen (deshalb Interrupt = Unterbrechung), weil eben
was Wichtiges passiert ist und den in der ISR definierten Code
auszuführen. Anschliessend macht das Programm an der Stelle weiter, an
der es unterbrochen wurde.

Ein C-Programm sieht also dann in etwa so aus:

void main (void)
{
   // Schleife die immer läuft
   for (;;)
   {
   }
}

SIGNAL (interruptkennung)
{
    // mach was :=)
    Ports lesen
    Ports schreiben
    usw.

    [...]
}

Pausen (respektive irgendwelche Zählschleifen) sollte man in seinem
Programm möglichst vermeiden. Der Prozessor hat meist genug zu tun, als
sich mit solchen (meist sinnlosen) Dingen aufzuhalten. Dann sind
plötzlich nämlich auch die kleineren unter ihnen ganz schnell.  ;o)

Joline

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.