0

I'm having a problem with structured text in Codesys V3.5 SP9 Patch 5. What I want to do is to be able to use a timer within a function created by me, which is called in a POU. I've done the same without using function by putting timer directly into POU and it is working.

My function declaration:

FUNCTION AssignDOORStatus : USINT
VAR_INPUT

    DDUC_ComSta_Dcux_x: BOOL; //No communication
    DDUC_DCUxEmHdler_x: BOOL; //Emergency handler

END_VAR
VAR

    Timer: TP; //Timer to do intermittence between current doors status and emergency handler
    CurrentDoorStatus: USINT;
    TONProcessTime: TIME := T#1S; //TONProcesTime

END_VAR

My function code:

IF DDUC_ComSta_Dcux_x THEN

    CurrentDoorStatus := 0;

ELSE

    CurrentDoorStatus := 1; 

END_IF


IF DDUC_DCUxEmHdler_x THEN

    Timer(IN := NOT Timer.Q, PT := TONProcessTime); //Timer starts
    Timer();

    IF Timer.Q THEN //When TONProcessTime has gone by

        IF AssignDOORStatus <> CurrentDoorStatus THEN

            AssignDOORStatus := CurrentDoorStatus;

        ELSE AssignDOORStatus := 10;

        END_IF

    END_IF

ELSE

    AssignDOORStatus := CurrentDoorStatus;

END_IF

My code in POU main:

testdoor := AssignDOORStatus(DDUC_ComSta_Dcu1_S1_T,DDUC_DCU1EmHdler_S1_T);

This code is used to assign to "AssignDOORStatus" 0 or 1 depending on variable "DDUC_ComSta_Dcux_x " and then, when "DDUC_DCUxEmHdler_x " is true, it flips "AssignDOORStatus" value from "0 or 1" to 10, using timer.

I have to call in POU many times this function.

Thanks in advance!

MetalxBeat
  • 97
  • 1
  • 2
  • 11

1 Answers1

4

Functions have no memory. Therefore all variables declared inside VAR are temporary and are reset to their default for each new call.

FunctionBlocks/Programs have memory. Therefore all variables declared inside VAR remain their values between each call.

That's why you should not use a function, which will forget everything between each call from MAIN. For instance the timer will be reset from the previous call.

Instead you should write a function block (or FB), which can be re-used for the several doors you want to handle. Inside the function block will be a set of variables (especially the timer), which will be unique for each instance and also be remembered from call to call.

The above is a very short description so you should really look up the function block in your compilers help file to get a proper explanation, e.g. for input/output parameters.
Below is my suggestion for a program that uses the same FB for three different door instances:

(The FB, first the declaration and then it's code)
FUNCTION_BLOCK FB_AssignDOORStatus
VAR_INPUT
    DDUC_ComSta_Dcux_x: BOOL; //No communication
    DDUC_DCUxEmHdler_x: BOOL; //Emergency handler
END_VAR
VAR_OUTPUT  
    AssignDoorStatus: USINT;    
END_VAR
VAR
    Timer: TP; //Timer to do intermittence between current doors status and emergency handler
    CurrentDoorStatus: USINT;
    TONProcessTime: TIME := T#1S; //TONProcesTime
END_VAR
----------
IF DDUC_ComSta_Dcux_x THEN
    CurrentDoorStatus := 0;
ELSE
    CurrentDoorStatus := 1; 
END_IF

IF DDUC_DCUxEmHdler_x THEN
    Timer(IN := NOT Timer.Q, PT := TONProcessTime); //Timer starts
    Timer();

    IF Timer.Q THEN //When TONProcessTime has gone by
        IF AssignDOORStatus <> CurrentDoorStatus THEN
            AssignDOORStatus := CurrentDoorStatus;
        ELSE
            AssignDOORStatus := 10;
        END_IF
    END_IF
ELSE
    AssignDOORStatus := CurrentDoorStatus;
END_IF

(MAIN, first the declaration and then it's code)
PROGRAM MAIN
VAR
    // You must make an instance of your function block(s). This instance will live from call to call. 
    fbAssignDOORStatus_1: FB_AssignDOORStatus;
    fbAssignDOORStatus_2: FB_AssignDOORStatus;
    fbAssignDOORStatus_3: FB_AssignDOORStatus;
    // ...
    // Better to use an array to hold the many FB instances needed...
    // You could use a for loop in the MAIN program to call all the instances.

    // Test variables to hand to the fb's during runtime.
    ComSta: BOOL;
    EmHdler: BOOL;
    TestDoor1, TestDoor2, TestDoor3: USINT;
    // Here you could also use an array or re-use some common variable... 
END_VAR
----------
fbAssignDOORStatus_1(
    DDUC_ComSta_Dcux_x := ComSta,
    DDUC_DCUxEmHdler_x := FALSE,
    AssignDoorStatus => TestDoor1);

fbAssignDOORStatus_2(
    DDUC_ComSta_Dcux_x := TRUE,
    DDUC_DCUxEmHdler_x := EmHdler,
    AssignDoorStatus => TestDoor2);

fbAssignDOORStatus_3(
    DDUC_ComSta_Dcux_x := ComSta,
    DDUC_DCUxEmHdler_x := EmHdler,
    AssignDoorStatus => TestDoor3);
Felix Keil
  • 2,344
  • 1
  • 25
  • 27
pboedker
  • 523
  • 1
  • 3
  • 17
  • Thank you so much!! I had heard about function blocks but I was always using functions without knowing such a difference between them. Now it's working fine :) – MetalxBeat Mar 02 '18 at 09:30