This article describes TRY, CATCH, FINALLY, and ENTRY, which can be used on 64Bit OS with Beckhoff 4026.
Come on, let’s enjoy FA.
TRY・CATCH・FINALLY・ENTRY?
These operators are an extension of the IEC 61131-3 standard and are used for exception handling in IEC code. try, catch, and finally are syntaxes used for exception handling in programming and are common in languages such as Java and JavaScript.
Required Platforms
Note that the 4024 version is only available for 32 BitOS.
- TC3.1 Build 4024 for 32-bit runtime systems
- TC3.1 Build 4026 for 64-bit runtime systems
Basic usage
Here is a look at how they work.
try block
The try block describes code that may throw an exception. If no exception is thrown, the catch block is skipped.
catch block
If an exception occurs within the try block, the program within this block is executed. This handles the exception and prevents the program from crashing.
finally block
The finally block is executed after try and catch, regardless of whether an exception was thrown or not. It is typically used for cleanup tasks or resource release.
Key Point
To summarize from the basic usage mentioned earlier, please note the following points for successful use of TRY, CATCH, and FINALLY.
- The try Block contains code that may throw an exception, and the catch Block handles the exception.
- The finally Block is useful for cleanup operations because it is executed regardless of whether or not an exception was thrown.
- By using try, catch, and finally, you can write robust programs that handle errors well.
Statements
This will be TRY, CATCH, and FINALLY Statements.
__TRY <try_statements> __CATCH(exc) <catch_statements> __FINALLY <finally_statements> __ENDTRY <further_statements> |
If an error exception occurs in the program that first appears under __Try, the PLC program will not stop.
Instead, it executes the following instruction _CATCH and starts exception handling.
The program under __FINALLY is then executed. Note that instructions under __FINALLY are always executed, i.e., instructions under __TRY are executed without throwing an exception.
Exception handling ends with __ENDTRY, after which the PLC program continues executing subsequent instructions (instructions after __ENDTRY).
__SYSTEM.ExceptionCode
The data type of the IEC variable representing error exceptions is __SYSTEM.ExceptionCode is: __SYSTEM. Such exceptions are caught by, for example, __TRY, __CATCH, __FINALLY, and __ENDTRY. the ExceptionCode data type can also be used to classify and log errors and exceptions that occur in the application code itself.
TYPE ExceptionCode : ( RTSEXCPT_UNKNOWN := 16#FFFFFFFF, RTSEXCPT_NOEXCEPTION := 16#00000000, RTSEXCPT_WATCHDOG := 16#00000010, RTSEXCPT_HARDWAREWATCHDOG := 16#00000011, RTSEXCPT_IO_CONFIG_ERROR := 16#00000012, RTSEXCPT_PROGRAMCHECKSUM := 16#00000013, RTSEXCPT_FIELDBUS_ERROR := 16#00000014, RTSEXCPT_IOUPDATE_ERROR := 16#00000015, RTSEXCPT_CYCLE_TIME_EXCEED := 16#00000016, RTSEXCPT_ONLCHANGE_PROGRAM_EXCEEDED := 16#00000017, RTSEXCPT_UNRESOLVED_EXTREFS := 16#00000018, RTSEXCPT_DOWNLOAD_REJECTED := 16#00000019, RTSEXCPT_BOOTPROJECT_REJECTED_DUE_RETAIN_ERROR := 16#0000001A, RTSEXCPT_LOADBOOTPROJECT_FAILED := 16#0000001B, RTSEXCPT_OUT_OF_MEMORY := 16#0000001C, RTSEXCPT_RETAIN_MEMORY_ERROR := 16#0000001D, RTSEXCPT_BOOTPROJECT_CRASH := 16#0000001E, RTSEXCPT_BOOTPROJECTTARGETMISMATCH := 16#00000021, RTSEXCPT_SCHEDULEERROR := 16#00000022, RTSEXCPT_FILE_CHECKSUM_ERR := 16#00000023, RTSEXCPT_RETAIN_IDENTITY_MISMATCH := 16#00000024, RTSEXCPT_IEC_TASK_CONFIG_ERROR := 16#00000025, RTSEXCPT_APP_TARGET_MISMATCH := 16#00000026, RTSEXCPT_ILLEGAL_INSTRUCTION := 16#00000050, RTSEXCPT_ACCESS_VIOLATION := 16#00000051, RTSEXCPT_PRIV_INSTRUCTION := 16#00000052, RTSEXCPT_IN_PAGE_ERROR := 16#00000053, RTSEXCPT_STACK_OVERFLOW := 16#00000054, RTSEXCPT_INVALID_DISPOSITION := 16#00000055, RTSEXCPT_INVALID_HANDLE := 16#00000056, RTSEXCPT_GUARD_PAGE := 16#00000057, RTSEXCPT_DOUBLE_FAULT := 16#00000058, RTSEXCPT_INVALID_OPCODE := 16#00000059, RTSEXCPT_MISALIGNMENT := 16#00000100, RTSEXCPT_ARRAYBOUNDS := 16#00000101, RTSEXCPT_DIVIDEBYZERO := 16#00000102, RTSEXCPT_OVERFLOW := 16#00000103, RTSEXCPT_NONCONTINUABLE := 16#00000104, RTSEXCPT_PROCESSORLOAD_WATCHDOG := 16#00000105, RTSEXCPT_FPU_ERROR := 16#00000150, RTSEXCPT_FPU_DENORMAL_OPERAND := 16#00000151, RTSEXCPT_FPU_DIVIDEBYZERO := 16#00000152, RTSEXCPT_FPU_INEXACT_RESULT := 16#00000153, RTSEXCPT_FPU_INVALID_OPERATION := 16#00000154, RTSEXCPT_FPU_OVERFLOW := 16#00000155, RTSEXCPT_FPU_STACK_CHECK := 16#00000156, RTSEXCPT_FPU_UNDERFLOW := 16#00000157, RTSEXCPT_VENDOR_EXCEPTION_BASE := 16#00002000, RTSEXCPT_USER_EXCEPTION_BASE := 16#00010000 ) UDINT ; END_TYPE |
Advantages?
Using try, catch, and finally offers several advantages in programming.
✓Simplified error handling
This allows exceptions to be handled gracefully without crashing the program and facilitates error management.
✓Code Clarity
By specifying how exceptions should be handled in the Catch Block, the code becomes more readable and the action to be taken in the event of an error is clearly indicated.
✓Resource Management
Finally Block can be clearly programmed to ensure that resources such as files and database connections are properly released, helping to prevent resource leaks.
✓Multiple Exception Handling
Different types of exceptions can be caught and handled separately. This allows tailored responses to specific errors.
✓Easier debugging
When an exception occurs, the details of the exception can be captured and logged, making it easier to identify and debug problems.
✓Improved application stability
Implementing proper exception handling will improve overall application stability and lead to a better user experience.
Implementation
From now on,we will use TRY, CATCH, FINALLY, and ENTRY to CATCH errors that lead to RUNTIME stoppage and record them in the Global Variable List.
DUT_History
This one defines 100 ExceptionCodes as an array and records the error contents when an exception occurs. nExcIndex is the Index of the next array to be recorded.
TYPE DUT_History : STRUCT nExcIndex : UINT:=0; aExceptionHistory : ARRAY[0..99] OF __SYSTEM.ExceptionCode; END_STRUCT END_TYPE |
F_ExceptionHisotryStack
Next, a Function Block is created to record the caught exceptions.
VAR
This is the FB Interface, which operates on the DUT_History defined earlier in VAR_IN_OUT.
FUNCTION F_ExceptionHisotryStack : BOOL VAR_INPUT InexcInput : __SYSTEM.ExceptionCode; END_VAR VAR_OUTPUT END_VAR VAR_IN_OUT ioData :DUT_History; END_VAR VAR _MaxIndex:DINT; END_VAR |
Program
Here is the program content: UPPER_BOUND retrieves the Index of the array, and if the Index to be recorded is less than the maximum Index, it stores Exception information and sets the Index to +1.
_MaxIndex:= UPPER_BOUND(ioData.aExceptionHistory,1); IF ioData.nExcIndex <=_MaxIndex THEN ioData.aExceptionHistory[ioData.nExcIndex]:=InexcInput; ioData.nExcIndex:=ioData.nExcIndex+1; END_IF |
MAIN
The last is the MAIN program, which contains an invalid pointer access and an error dividing by 0.
PROGRAM MAIN VAR History:DUT_History; END_VAR VAR nCounter_TRY1 : UINT; nCounter_TRY2 : UINT; nCounter_CATCH : UINT; nCounter_FINALLY : UINT; exc : __SYSTEM.ExceptionCode; lastExc : __SYSTEM.ExceptionCode; pSample : POINTER TO BOOL; bVar : BOOL; nSample : INT := 100; nDivisor : INT; END_VAR __TRY nCounter_TRY1 := nCounter_TRY1 + 1; pSample^ := TRUE; // null pointer access leads to “access violation” exception nSample := nSample/nDivisor; // division by zero leads to “divide by zero” exception nCounter_TRY2 := nCounter_TRY2 + 1; __CATCH(exc) nCounter_CATCH := nCounter_CATCH + 1; // Exception logging lastExc := exc; F_ExceptionHisotryStack(InexcInput:=exc,ioData:=History); // fix the error //correct the Pointer IF (exc = __SYSTEM.ExceptionCode.RTSEXCPT_ACCESS_VIOLATION) AND (pSample = 0) THEN pSample := ADR(bVar); //corret the Divide value ELSIF ((exc = __SYSTEM.ExceptionCode.RTSEXCPT_DIVIDEBYZERO) OR (exc = __SYSTEM.ExceptionCode.RTSEXCPT_FPU_DIVIDEBYZERO)) AND (nDivisor = 0) THEN nDivisor := 1; END_IF __FINALLY nCounter_FINALLY := nCounter_FINALLY + 1; __ENDTRY |
Error
This is the part of the program that performs invalid pointer access and division by zero, and is executed in the __TRY Block.
Catch
Exceptions raised in __TRY Block are taken to __CATCH, the first exception corrects the value of the pointer pSample, and the second exception corrects the value of the divisor nDivisor. These two exceptions are also stored in a global array for exception history.
So, as a result, the array aExceptionHistory has the following values
- aExceptionHistory[0] = RTSEXCPT_ACCESS_VIOLATION
- aExceptionHistory[1] = RTSEXCPT_DIVIDEBYZERO
- aExceptionHistory[2] to aExceptionHistory[99] = RTSEXCPT_NOEXCEPTION
Result
As you can see, an invalid pointer access and a divide-by-zero error will not stop TwinCAT
Runtime.
You can see that the Global Variable List stores exceptions that occur in the program.