1

Beginner in the whole PLC stuff, so corrections are welcome.

I am trying to tidy up my project and current situation is thus: I receive 16 byte arrays from modbus. These act as buttons, lights, conveyors what have you in Factory IO.

GAB_FactoryIO_Inputs    AT %I*      :   ARRAY [0..15] OF BYTE;
GAB_FactoryIO_Outputs   AT %Q*      :   ARRAY [0..15] OF BYTE;

So instead of referring to "Start button" with its bit "IO.GAB_FactoryIO_Inputs[0].0" I made a clumsy conversion POU and GVL to go through each bit and give them a new name. So it currently it looks like 200 lines of this:

IO.iSensor10_Capa   :=  IO.GAB_FactoryIO_Inputs[7].3;
IO.iSensor9_Capa    :=  IO.GAB_FactoryIO_Inputs[7].4;
IO.iPositioner_Limit    :=  IO.GAB_FactoryIO_Inputs[7].5;
IO.iPositioner_Clamped  :=  IO.GAB_FactoryIO_Inputs[7].6;
IO.iPick2_Detected  :=  IO.GAB_FactoryIO_Inputs[7].7;
IO.iPick2_MovX  :=  IO.GAB_FactoryIO_Inputs[8].0;
IO.iPick2_MovZ  :=  IO.GAB_FactoryIO_Inputs[8].1;
IO.iPick2_Rot   :=  IO.GAB_FactoryIO_Inputs[8].2;
IO.iPick2_GripRot   :=  IO.GAB_FactoryIO_Inputs[8].3;

And this

iPositioner_Limit   :   BOOL;
iPositioner_Clamped :   BOOL;
iPick2_Detected :   BOOL;
iPick2_MovX :   BOOL;
iPick2_MovZ :   BOOL;   
iPick2_Rot  :   BOOL;   
iPick2_GripRot  :   BOOL;   

It all works as it should, but I cant help to feel its amateurish, unwieldy and slows things down.

I've read about structures, enumeration and alias, and thought structures would be my savior by handily arranging them inside "cabinets", like so:

stCNC.Button1
stCNC.Button3
stCNC.Sensor1

And hidden inside structures would be the conversion between stCNC Sensor1 = IO.GAB_FactoryIO_Inputs[9].4;

But for some reason that doesnt work at all. I'm most likely going at it plain wrong angle, but have no idea what to look for next.


EDIT work in progress thus far. Seems like I got the hang of the basics. @kolyur had simple enough example to follow, so I started from there, and progressed towards @Steve and @YAVA examples:

//sending inputs to GVL FactoryIO_Inputs AT %I* : ARRAY [0..15] OF BYTE;
fbMBReadInputs(pDestAddr := ADR(IO.FactoryIO_Inputs), 

//in GVL IO
FactoryIO_Inputs    AT %I*      :   U_UNION2;

//inside S_LIGHTS:
TYPE S_LIGHTS :
STRUCT
    LIGHT0  : BIT;
    LIGHT1  : BIT;
    LIGHT2  : BIT;
    LIGHT3  : BIT;
    LIGHT4  : BIT;
    LIGHT5  : BIT;
    LIGHT6  : BIT;
    LIGHT7  : BIT;
END_STRUCT
END_TYPE

//inside U_UNION1
TYPE U_UNION1 :
UNION
nArray :    ARRAY[0..15] OF BYTE;
sName :     S_NAME;

//Then instantiating in POU
VAR
sLights : S_LIGHTS;
---
sLights.LIGHT1 := TRUE;

3 Answers3

5

You can try to use a UNION. It is basically an "overlay" variable you can place over another variable.

TYPE Test :
UNION
    nARRAY          : ARRAY[0..15] OF BYTE;
    sHumanReadable  : sStruct;    
END_UNION
END_TYPE

UNION on Infosys

YAVA
  • 66
  • 2
  • Most upvotes tell this should be the best answer, and I really appreciate the help, but I cant make head or tails of it. INFOSYS is notoriously unhelpful for beginners, thus I can only conclude UNION affects all variables assigned under it. I'm trying now to create Struct in useful names, but I dont know where to bring in nARRAY to play. – SpaceRodent Apr 12 '21 at 20:26
  • 1
    @SpaceRodent Would edit this to help it make sense but I don't have enough rep :( --- Basically, as you have said UNION present a single data space. So in this instance if sStruct is made up of Elem1 : Bit, Elem2 : Bit.... The UNION maps nArray[0].0 to Elem1, nArray[0].1 to Elem2... And so on. --- Basically if you have a struct of 16Byte size you will be able to access the data from the array by calling the element of the struct that maps to that position. – Steve Apr 13 '21 at 01:39
  • @Steve thank you! I think your help was the final straw I needed to figure things out. Its very elementary and quite simple honestly, but simply not knowing where to put all the simple pieces was frustrating. – SpaceRodent Apr 13 '21 at 17:53
2

A structure could help if you make use of the BIT datatype. BITs address individual bits (unlike BOOLs which require a whole byte) but they can only be used within structures.

TYPE Test
STRUCT
  button1 : BIT;
  button2 : BIT;
  button3 : BIT;
  button4 : BIT;
  sensor1 : BIT;
  sensor2 : BIT;
  sensor3 : BIT;
  sensor4 : BIT;
END_STRUCT
END_TYPE

This structure occupies one byte and you could make an array of them to potentially use in your Modbus routine instead of the byte arrays.

kolyur
  • 93
  • 6
  • Awesome, I'll give it a try. So if I understand this correctly, instead of assigning inputs to array of bytes, I'm assigning them to arrays of structures, and insides of those structs would look identical to your example? Inputs AT %I* : ARRAY [0..15] OF TestStruct – SpaceRodent Apr 12 '21 at 20:33
  • 1
    Yes, I'm fairly sure that will work since the data sizes are the same. You might have discovered that you can't do StructVar := ByteVar even if the data sizes are the same, because they are different types. But you could use MEMCPY to do a straight memory copy: MEMCPY(ADR(StructVar), ADR(ByteVar), 1) – kolyur Apr 13 '21 at 12:10
2

Instead of first linking each IO to a global variable list and then link them to a function block, you could link the symbols directly to an instance of a function block.

For example you make the following function block and put the hardware inputs in the VAR section or you could put them in VAR_INPUT. You could also collect the inputs into a struct as the others suggested and use this struct in the function block.

FUNCTION_BLOCK Picker
VAR
    MoveX AT %I : BOOL;
    MoveY AT %I : BOOL;
    Rotate AT %I : BOOL;
    GripRotate AT %I : BOOL;
END_VAR

Then in your program you make an instance of the picker

PROGRAM MAIN
VAR
    picker1 : Picker;
END_VAR

And then from you system configuration you can link each terminal input directly to the VAR's inside picker1.

Roald
  • 940
  • 7
  • 20
  • Wish I could have known this is possible. I tried to find a way to map those virtual inputs/outputs to act as hardware IO, but had no idea how to approach that. I'll give it a try and ask for more. – SpaceRodent Apr 12 '21 at 20:36