Forum: Mikrocontroller und Digitale Elektronik Regelalgorithmus in ISR?


von Jan K. (jan_k)


Lesenswert?

Hallo,

ich habe gerade den ISR Artikel gelesen und dort steht, man sollte die 
ISR eher kurz halten und dort nur Flags setzen.

Wie ist das denn, wenn ich einen Timer laufen habe, der setzt eine Flag 
für die main. In der ISR wird die aktuelle Ausgangsgröße gemessen und in 
der main daraus mit der Führungsgröße die Regelabweichung und damit die 
Stellgröße berechnet.

Jetzt wird aber auch alle ~500 ms die Uart bemüht, die ~90ms benötigt. 
Kommt also schon relativ häufig vor. Die Timer bzw Abtastfrequenz 
beträgt 800us.

Das bedeutet, es gehen, wenn die Uart gerade sendet 113 ISR Zyklen 
verloren, in denen zwar die Ausgangsgröße geloggt und die Flag gesetzt, 
aber eigentlich nicht geregelt wird.

Daher die Frage: "Darf" ich die Regelung in die ISR verlagern?

Priorität hat die Regelung, die Logging Geschichte (mit UART) ist 
Beiwerk, aber zu Analysezwecke durchaus wichtig...

Danke für eure Hilfe!

von Εrnst B. (ernst)


Lesenswert?

Jan K. schrieb:
> "Darf" ich die Regelung in die ISR verlagern?

Kommt darauf an, wie lang deine Regelung rechnet.
Wenn du aber bisher mit 800µs zwischen den Messwerten ausgekommen bist, 
kann das nicht zu lange gewesen sein  => pack die Regelung in die ISR.
"Möglichst kurze ISR" bedeutet ja nicht, dass nur "Flag setzen" darin 
erlaubt wäre.

von Jan K. (jan_k)


Lesenswert?

Die Regelung rechnet etwa 80us.

Eine andere Möglichkeit wäre vllt die UART Ausgabe per DMA zu machen.

Was ist vernünftiger und gibt es noch andere Möglichkeiten?

von Oliver J. (skriptkiddy)


Lesenswert?

Jan K. schrieb:
> Eine andere Möglichkeit wäre vllt die UART Ausgabe per DMA zu machen.
Ich mache so etwas Interrupt-getrieben mit Ringpuffer.

Gruß Oliver

von Karl H. (kbuchegg)


Lesenswert?

Dein erster Gedanke sollte sein:
Wie wichtig ist es mir, dass (in deinem Fall) die Regelgleichung auch 
tatsächlich möglichst gleichbleibend regelmässig ausgeführt wird.

Da das bei einem Regler meistens eine absolute Notwendigkeit ist, 
solltest du sogar die Reglerauswertung in die ISR stecken, solange du 
dadurch das restliche Programm nicht in Zeitnot bringst.
Es hilft dir nichts, wenn du die Daumenregel "In einer ISR nur Flags 
setzen" zu wörtlich nimmst und dann einen wahnsinnig komplizierten 
Überbau im Hauptprogramm brauchst, der sicherstellen soll, dass an jeder 
einzelnen Stelle (zb bei der Ausgabe eines Strings) kurz zwischendruch 
mal eben bei Bedarf die Reglergleichung einmal abgearbeitet wird.

ISR sollen das tun, was notwendig ist. Nicht mehr. Aber auch nicht 
weniger. In deiner Anwendung hat die Regelmässigkeit der 
Reglerauswertung absolute Priorität vor allem anderen. Daher: Ab in die 
ISR damit.
Wenn die UART Ausgabe mal kurz für ein Zeichen stockt (weil 
zwischendurch einmal der PID läuft), interessiert das kein Schwein. 
Durch UART-BUffer kriegt das wahrscheinlich noch nicht einmal irgendwer 
mit.

von UR-Schmitt (Gast)


Lesenswert?

Jan K. schrieb:
> die Uart bemüht, die ~90ms benötigt.

Warum braucht das Senden eines oder ein paar Byte 90ms? Das ind ja je 
nach µC (der nicht angegeben ist) mehrere 100000 Taktzyklen!
Wartest du etwa bis alles gesendet worden ist?
Das wäre sehr ungeschickt.
Normalerweise macht man sich eine Sendefunktion die in etwa 
folgendermassen aussieht

SendeByte()
ist die UART frei
  dann schreibe das Byte in das Senderegister und starte Senden
else
  schreibe das Byte in den Sendepuffer

Jede UART hat eine ISR die aufgerufen wird wenn ein Byte gesendet wurde
in der steht dann:

ist noch ein Byte im Sendepuffer
  wenn ja dann schreibe das Byte in das Senderegister
  Sende

So dauert ein Senden nur höchstens ein paar hundert Taktzyklen, der Rest 
läuft asynchron

von Jan K. (jan_k)


Lesenswert?

Erst einmal vielen Dank für die Antworten. Werde einige Fragen versuchen 
zu beantworten:

kurz zur Aufklärung: es handelt sich um einen STM32F100 @ 24 Mhz

Oliver J. schrieb:
> Ich mache so etwas Interrupt-getrieben mit Ringpuffer.

Mache ich auch. Dieser Buffer wird dann, wenn er voll ist geschickt. Das 
führt zur nächsten Frage :

UR-Schmitt schrieb:
> Wartest du etwa bis alles gesendet worden ist?
> Das wäre sehr ungeschickt.

Ja. :/
Es sind 1042 Bytes. Die Uart läuft mit 115200 Baud. Tatsächlich arbeite 
ich in einer Funktion den kompletten UART Puffer per Schleife ab und 
warte jeweils, bis die TXE und TC Bit gesetzt sind.

UR-Schmitt schrieb:
> Normalerweise macht man sich eine Sendefunktion die in etwa
> folgendermassen aussieht
>
> SendeByte()
> ist die UART frei
>   dann schreibe das Byte in das Senderegister und starte Senden
> else
>   schreibe das Byte in den Sendepuffer
>
> Jede UART hat eine ISR die aufgerufen wird wenn ein Byte gesendet wurde
> in der steht dann:
>
> ist noch ein Byte im Sendepuffer
>   wenn ja dann schreibe das Byte in das Senderegister
>   Sende
>
> So dauert ein Senden nur höchstens ein paar hundert Taktzyklen, der Rest
> läuft asynchron

Verdammt, das ist mir echt noch nicht eingefallen, aber scheint sinnig 
;)
Denke ich wollte so wenig Interrupts wie möglich machen und den Puffer 
lieber an einem Stück versenden.

@ Karl Heinz:

auch dir vielen Dank für die Antwort. Dass die Abtastung und vor allem 
Regelung oberste Priorität hat ist korrekt. Daher darf ja das Programm 
auf keinen Fall so bleiben wie es ist ;)

Habe gerade mit dem Scope nochmal nachgemessen:

ISR so wie sie jetzt ist (nur in den Ringpuffer schreiben) : 2.8us
ISR puffern + berechnen : 13.6us
ISR puffern + berechnen + pid berechnen + pwm : 37.2us

Scheint also nicht wirklich zeitkritisch zu sein das ganze, obwohl es 
recht viel Code ist.

Denke ich werd's dann wirklich in die ISR packen, die Geschichte mit den 
Uart Interrupts gucke ich mir aber trotzdem an. Oder lieber direkt mit 
dem DMA arbeiten? Immerhin gibt es ihn ja ;)

Vielen vielen Dank!

von Karl H. (kbuchegg)


Lesenswert?

Jan K. schrieb:

> Mache ich auch. Dieser Buffer wird dann, wenn er voll ist geschickt.

Hä?


> Ja. :/
> Es sind 1042 Bytes. Die Uart läuft mit 115200 Baud. Tatsächlich arbeite
> ich in einer Funktion den kompletten UART Puffer per Schleife ab und
> warte jeweils, bis die TXE und TC Bit gesetzt sind.

UNgeschickt.
Eine normale UART kann einen Interrupt auslösen, wenn sie das nächste 
Zeichen wegschicken kann.
In dieser Interrupt Routine wird die UART mit dem nächsten Zeichen aus 
der Sende-FIFO gefüttert. Mehr nicht.
Wenn die UART dieses Zeichen dann draussen hat, meldet sie sich sowieso 
dann wieder mit einem neuen Interrupt: "Hey, ich brauch was zu tun!". 
Und dann fütterst du ihr das nächste Zeichen (sofern noch eines im 
Buffer ist). Der Trick besteht jetzt darin, dass diese UART-ISR trivial 
einfach ist. Ein paar Taktzyklen und die UART ist wieder gefüttert. 
Während die UART dann ihren Teil macht, kann dein Programm sich wieder 
anderen Aufgaben widmen (anstatt blödsinnig auf das Fertig von der UART 
zu warten)

Wenn du µC programmierst, musst du agierenb wie eine Hasufrau, die auch 
5 Sachen 'gleichzeitig' macht, indem sie zwischen den einzelnen Aufgaben 
hin und herflitzt.
Wassser auf den Herd, Herd einschalten
Ab zur Waschmaschine, Wäsche sortieren
Zwischendurch mal schnell zum Postkastn, Post auf den Tisch
Staubsauger rausholen
Wäsche in die Waschmaschine, Maschine einschalten
Kurz beim Herd vorbeischauen, ob das Wasser schon kocht
Ersten Brief öffnen, Rechnung beiseitelegen
Wasser kocht, also Nudeln rein
....

In keinem Fall bleibt sie daneben stehen und wartet darauf, dass etwas 
fertig wird. Wenn es etwas zu warten gibt, dann wird eben in der 
Zwischenzeit etwas anderes gemacht.

von Jan K. (jan_k)


Lesenswert?

Jo, ungeschickt. Hatte Ur-Schmitt ja schon angedeutet ;)

Werde die Interrupts einbauen und die Berechnung in die ISR verlegen bei 
den Zeiten, oder?

von UR-Schmitt (Gast)


Lesenswert?

Jan K. schrieb:
> Jo, ungeschickt. Hatte Ur-Schmitt ja schon angedeutet ;)
>
> Werde die Interrupts einbauen und die Berechnung in die ISR verlegen bei
> den Zeiten, oder?

Für einen Ringpuffer und die Funktionen zum Senden gibts bestimmt 
massenweise Code im I-Net und auch im Forum. Würde mich wundern wenn es 
hier nicht C Code geben würde zwar für einen kleineren Puffer und für 8 
Bitter aber in C lässt sich das ja anpassen.
Nur um das Prinzip zu verstehen.

von Jan K. (jan_k)


Lesenswert?

Ich habe bereits einen Ringpuffer implementiert in den letzten Tagen. 
Sogar einen mit zwei Lesezeigern, damit ich aus der main die in der 
Timer ISR empfangenen Werte verarbeiten kann. Aber das liegt ja jetzt 
wieder in der ISR -> ein Lesezeiger und ein Puffer weniger -> Speicher + 
Aufwand gespart, sehr schön :)

Wie Karl Heinz oben sagte: Ich habe das Hauptprogramm ziemlich 
aufgebläht, weil ich die ISR so kurz wie möglich halten wollte.

Die ISR für die UART sollte machbar sein.

Danke euch!

von UR-Schmitt (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Wäsche in die Waschmaschine, Maschine einschalten
> Kurz beim Herd vorbeischauen, ob das Wasser schon kocht
> Ersten Brief öffnen, Rechnung beiseitelegen
> Wasser kocht, also Nudeln rein
> ....
>
> In keinem Fall bleibt sie daneben stehen und wartet darauf, dass etwas
> fertig wird. Wenn es etwas zu warten gibt, dann wird eben in der
> Zwischenzeit etwas anderes gemacht.

Aber wehe die Freundin ruft an...
Dann gibts kalt weil die Nudel kaputtgekocht sind :-)

Also Jan, den "Freundin ruft an" Interrupt unbedingt gesperrt lassen.

von Jan K. (jan_k)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Wenn du µC programmierst, musst du agierenb wie eine Hasufrau, die auch
> 5 Sachen 'gleichzeitig' macht, indem sie zwischen den einzelnen Aufgaben
> hin und herflitzt.
> Wassser auf den Herd, Herd einschalten
> Ab zur Waschmaschine, Wäsche sortieren
> Zwischendurch mal schnell zum Postkastn, Post auf den Tisch
> Staubsauger rausholen
> Wäsche in die Waschmaschine, Maschine einschalten
> Kurz beim Herd vorbeischauen, ob das Wasser schon kocht
> Ersten Brief öffnen, Rechnung beiseitelegen
> Wasser kocht, also Nudeln rein
> ....
>
> In keinem Fall bleibt sie daneben stehen und wartet darauf, dass etwas
> fertig wird. Wenn es etwas zu warten gibt, dann wird eben in der
> Zwischenzeit etwas anderes gemacht.

hahah :D Alles klar merke ich mir ;)

UR-Schmitt schrieb:
> Aber wehe die Freundin ruft an...
> Dann gibts kalt weil die Nudel kaputtgekocht sind :-)
>
> Also Jan, den "Freundin ruft an" Interrupt unbedingt gesperrt lassen.

mit Vergnügen.

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.