0

I need to concatenate a string and an integer and a string into a variable - in this case an input.

The inputs are named as following:

DI_Section1_Valve AT %I*: BOOL;
DI_Section2_Valve AT %I*: BOOL;
DI_Section3_Valve AT %I*: BOOL;

Now, I want to loop through these (this is just a short example):

For i:= 1 TO 3 DO
    Var[i] := NOT CONCAT(CONCAT('DI_Section', INT_TO_STRING(i)), '_Valve')
END_FOR

But by concatenating strings, I'll end up with a string, eg. 'DI_Section1_Valve', and not the boolean variable, eg. DI_Section1_Valve.

How do I end up with the variable instead of just the string? Any help is appreciated, thanks in advance. /Thoft99

Thoft
  • 15
  • 5

2 Answers2

1

That technique is called variable variables. Unfortunately this is not available in ST. There are few ways around it. As I understand Twincat 3 is based on Codesys 3.5. That means UNION is available. There is also a trick that references to BOOL does not work as expected and one reference take one byte. So you cannot place them in order, so you need to know BYTE address of input module.

TYPE DI_Bits : STRUCT
        DI_Section1_Valve  : BIT; (* Bit 1 *)
        DI_Section2_Valve  : BIT; (* Bit 2 *)
        DI_Section3_Valve  : BIT; (* Bit 3 *)
        DI_Section4_Valve  : BIT; (* Bit 4 *)
        DI_Section5_Valve  : BIT; (* Bit 5 *)
        DI_Section6_Valve  : BIT; (* Bit 6 *)
        DI_Section7_Valve  : BIT; (* Bit 7 *)
        DI_Section8_Valve  : BIT; (* Bit 8 *)
    END_STRUCT
END_TYPE

TYPE DI_Sections : UNION
        ByName : DI_Bits; 
        ByID : ARRAY[1..8] OF BOOL; (* Comment *)
        ByMask: BYTE;
    END_UNION
END_TYPE

PROGRAM PLC_PRG
    VAR
        DIS AT %IB0.0: DI_Sections; (* Our union *)
        xOut : BOOL;
    END_VAR


    xOut := DIS.ByID[1];
    xOut := DIS.ByName.DI_Section1_Valve;
    
    DIS.ByID[5] := TRUE; 
    // Now DIS.ByName.DI_Section5_Valve also EQ TRUE

END_PROGRAM
Sergey Romanov
  • 2,949
  • 4
  • 23
  • 38
0

You can't access a variables by using strings. What you can do instead is manually create an array of pointers to the values you want to index, for example:

    DI_Section1_Valve AT %I*: BOOL;
    DI_Section2_Valve AT %I*: BOOL;
    DI_Section3_Valve AT %I*: BOOL;

    DI_Section_Valves: ARRAY [1..3] OF POINTER TO BOOL
        := [ADR(DI_Section1_Valve), ADR(DI_Section2_Valve), ADR(DI_Section3_Valve)];
    FOR i:= 1 TO 3 DO
        out[i] := DI_Section_Valves[i]^;
    END_FOR

EDIT: Alternatively, you could create a function that does this:

METHOD Get_DI_Selection_Valve : BOOL
VAR_INPUT
    i: INT;
END_VAR

    CASE i OF
    1: Get_DI_Selection_Valve := DI_Section1_Valve;
    2: Get_DI_Selection_Valve := DI_Section2_Valve;
    3: Get_DI_Selection_Valve := DI_Section3_Valve;
    END_CASE
FOR i:= 1 TO 3 DO
    out[i] := Get_DI_Selection_Valve(i);
END_FOR

The idea is the same though

Guiorgy
  • 1,405
  • 9
  • 26