| 

.NET C# Java Javascript Exception

7
Bei der Ausführung eines SPS-Programms kann es zu unerwarteten Laufzeitfehlern kommen. Diese treten auf, sobald das SPS-Programm versucht eine unzulässige Operation auszuführen. Auslöser solcher Szenarien kann z.B. eine Division durch 0 sein oder ein Pointer verweist auf einen ungültigen Speicherbereich. Mit den Schlüsselwörtern __TRY und __CATCH kann auf diese Ausnahmen deutlich besser reagiert werden als […]

Bei der Ausführung eines SPS-Programms kann es zu unerwarteten Laufzeitfehlern kommen. Diese treten auf, sobald das SPS-Programm versucht eine unzulässige Operation auszuführen. Auslöser solcher Szenarien kann z.B. eine Division durch 0 sein oder ein Pointer verweist auf einen ungültigen Speicherbereich. Mit den Schlüsselwörtern __TRY und __CATCH kann auf diese Ausnahmen deutlich besser reagiert werden als bisher.

Die Liste der möglichen Ursachen für Laufzeitfehler kann endlos erweitert werden. Allen Fehlern ist aber gemeinsam: Sie führen zum Absturz des Programms. Bestenfalls wird durch eine Meldung auf den Laufzeitfehler hingewiesen:

Da sich anschließend das SPS-Programm in einem nicht definierten Zustand befindet, wird das System gestoppt. Dies ist anhand des gelben TwinCAT Icon in der Windows Taskleiste zu erkennen:

Für in Betrieb befindliche Anlagen ist das unkontrollierte Stoppen nicht immer die optimalste Reaktion. Außerdem gibt die Meldung nur unzureichend Auskunft darüber, wo genau im SPS-Programm der Fehler aufgetreten ist. Eine Optimierung der Software ist dadurch nur schwer möglich.

Um Fehler schneller ausfindig zu machen, können in dem SPS-Programm Überprüfungsfunktionen eingefügt werden.

Überprüfungsfunktionen werden jedes Mal aufgerufen, wenn die entsprechende Operation ausgeführt wird. Am bekanntesten dürfte die Funktion CheckBounds() sein. Bei jedem Zugriff auf ein Arrayelement wird vorher diese Funktion implizit aufgerufen. Als Parameter erhält die Funktion die Arraygrenzen und den Index des Elements, auf das der Zugriff erfolgen soll. Die Funktion kann so angepasst werden, dass bei einem Zugriff außerhalb der Arraygrenzen eine Korrektur erfolgt. Dieser Ansatz hat allerdings einige Nachteile:

  1. In CheckBounds() kann nicht festgestellt werden auf welches Array zugegriffen wird. Somit kann nur für alle Arrays die gleiche Fehlerkorrektur implementiert werden. Da bei jedem Arrayzugriff die Überprüfungsfunktion aufgerufen wird, kann sich die Laufzeit des Programms erblich verschlechtern.

Ähnlich verhält es sich auch bei den anderen Überprüfungsfunktionen.

Nicht selten werden die Überprüfungsfunktionen nur während der Entwicklungsphase eingesetzt. In den Funktionen werden Breakpoints aktiviert, die, sobald eine fehlerhafte Operation ausgeführt wird, das SPS-Programm anhalten. Über den Callstack kann anschließend die entsprechende Stelle im SPS-Programm ermittelt werden.

Die ‚try/catch‘-Anweisung

Allgemein werden Laufzeitfehler als Ausnahmen (Exceptions) bezeichnet. Für das Erkennen und Bearbeiten von Exceptions gibt es in der IEC 61131-3 die Anweisungen __TRY, __CATCH und __ENDTRY:

__TRY
 // statements
__CATCH (exception type)
 // statements
__ENDTRY
// statements

Der TRY-Block (die Anweisungen zwischen __TRY und __CATCH) beinhaltet die Anweisungen, die potenziell eine Exception verursachen können. Tritt keine Exception auf, werden alle Anweisungen im TRY-Block ausgeführt. Anschließend setzt das SPS-Programm hinter __ENDTRY seine Arbeit fort. Verursacht eine der Anweisungen innerhalb des TRY-Blocks jedoch eine Exception, so wird der Programmablauf unmittelbar im CATCH-Block (die Anweisungen zwischen __CATCH und __ENTRY) fortgeführt. Alle übrigen Anweisungen innerhalb des TRY-Blocks werden dabei übersprungen.

Der CATCH-Block wird nur im Falle einer Exception ausgeführt und enthält die gewünschte Fehlerbehandlung. Nach der Abarbeitung des CATCH-Blocks wird das SPS-Programm mit den Anweisungen nach __ENDTRY fortgesetzt.

Hinter der __CATCH-Anweisung wird in runden Klammern eine Variable vom Typ __SYSTEM.ExceptionCode angegeben. Der Datentyp __SYSTEM.ExceptionCode enthält eine Auflistung aller möglichen Exceptions. Wird der CATCH-Block durch eine Exception aufgerufen, so kann über diese Variable die Ursache der Exception abgefragt werden.

In dem folgenden Beispiel werden zwei Elemente aus einem Array dividiert. Das Array wird hierbei durch einen Pointer an die Funktion übergeben. Ist der Rückgabewert der Funktion negativ, so ist bei der Ausführung ein Fehler aufgetreten. Der negative Rückgabewert der Funktion gibt genauere Informationen über die Ursache der Exception:

FUNCTION F_Calc : LREAL
VAR_INPUT
 pData : POINTER TO ARRAY [0..9] OF LREAL;
 nElementA : INT;
 nElementB : INT;
END_VAR
VAR
 exc : __SYSTEM.ExceptionCode;
END_VAR

__TRY
 F_Calc := pData^[nElementA] / pData^[nElementB];
__CATCH (exc)
 IF (exc = __SYSTEM.ExceptionCode.RTSEXCPT_ARRAYBOUNDS) THEN
 F_Calc := -1;
 ELSIF ((exc = __SYSTEM.ExceptionCode.RTSEXCPT_FPU_DIVIDEBYZERO) OR
 (exc = __SYSTEM.ExceptionCode.RTSEXCPT_DIVIDEBYZERO)) THEN
 F_Calc := -2;
 ELSIF (exc = __SYSTEM.ExceptionCode.RTSEXCPT_ACCESS_VIOLATION) THEN
 F_Calc := -3;
 ELSE
 F_Calc := -4;
 END_IF
__ENDTRY

Die ‚finally‘-Anweisung

Mit __FINALLY kann optional ein Codeblock definiert werden, der immer aufgerufen wird, unabhängig davon ob eine Exception aufgetreten ist oder nicht. Es gibt nur eine einzige Randbedingung: Das SPS-Programm muss zumindest in den TRY-Anweisungsblock eintreten.

Das Beispiel soll so erweitert werden, dass das Ergebnis der Berechnung zusätzlich um Eins erhöht wird. Dieses soll unabhängig davon erfolgen, ob ein Fehler aufgetreten ist oder nicht.

FUNCTION F_Calc : LREAL
VAR_INPUT
 pData : POINTER TO ARRAY [0..9] OF LREAL;
 nElementA : INT;
 nElementB : INT;
END_VAR
VAR
 exc : __SYSTEM.ExceptionCode;
END_VAR

__TRY
 F_Calc := pData^[nElementA] / pData^[nElementB];
__CATCH (exc)
 IF (exc = __SYSTEM.ExceptionCode.RTSEXCPT_ARRAYBOUNDS) THEN
 F_Calc := -1;
 ELSIF ((exc = __SYSTEM.ExceptionCode.RTSEXCPT_FPU_DIVIDEBYZERO) OR
 (exc = __SYSTEM.ExceptionCode.RTSEXCPT_DIVIDEBYZERO)) THEN
 F_Calc := -2;
 ELSIF (exc = __SYSTEM.ExceptionCode.RTSEXCPT_ACCESS_VIOLATION) THEN
 F_Calc := -3;
 ELSE
 F_Calc := -4;
 END_IF
__FINALLY
 F_Calc := F_Calc + 1;
__ENDTRY

Beispiel 1 (TwinCAT 3.1.4024 / 32 Bit) auf GitHub

Die Anweisung im FINALLY-Block (Zeile 24) wird immer aufgerufen, unabhängig davon ob eine Exception erzeugt wird oder nicht.

Wird im TRY-Block keine Exception ausgelöst, so wird der FINALLY-Block direkt nach dem TRY-Block ausgerufen.

Tritt eine Exception auf, so wird erst der CATCH-Block ausgeführt und anschließend auch der FINALLY-Block. Erst danach wird die Funktion verlassen.

__FINALLY gestattet es somit, diverse Operationen unabhängig davon auszuführen, ob eine Exception aufgetreten ist oder nicht. Dabei handelt es sich in der Regel um die Freigabe von Ressourcen, wie z.B. das Schließen einer Datei oder das Beenden einer Netzwerkverbindung.

Besonders sorgfältig sollte man die Implementierung der CATCH– und FINALLY-Blöcke vornehmen. Tritt in einem dieser Codeblöcke eine Exception auf, so löst dieses einen unerwarteten Laufzeitfehler aus. Mit dem Ergebnis, dass das SPS-Programm unmittelbar gestoppt wird.

An dieser Stelle möchte ich noch auf den Blog von Matthias Gehring hinweisen. In einem seiner Posts (https://www.codesys-blog.com/tipps/exceptionhandling-in-iec-applikationen-mit-codesys) wird das Thema Exception Handling ebenfalls behandelt.

Das Beispielprogramm ist unter 32-Bit Systemen ab TwinCAT 3.1.4024 lauffähig. 64-Bit Systeme werden derzeit noch nicht unterstützt.

iec-61131-3 oop twincat vererbung sps methoden schnittstellen catch codesys try
Weitere News:
1 Meinung
0
We are the best writing company providing College Term Paper Writing Services papers over 15 years, we have been operational as we have assisted thousands of students with their Online Custom Research Paper Services.
Schreibe einen Kommentar:
Themen:
try codesys catch schnittstellen methoden sps vererbung twincat oop iec-61131-3
Entweder einloggen... ...oder ohne Wartezeit registrieren
Benutzername
Passwort
Passwort wiederholen
E-Mail