Mapping PLC world(code) to Hardware world(remote IO) with some OOP style

mike-mn
2016-12-16
2017-01-19
  • mike-mn - 2016-12-16

    I am having a bit of trouble figuring out how to map my PLC bool/int type data to control words of the modbus request to remote IO. Hoping someone might be able to help me out.

    This code works and I can read(and write) data directly in readArray.

    FUNCTION_BLOCK ModbusConnection
    VAR
       readArray: ARRAY[0..3] OF UINT;// Array of data to be read
    END_VAR
    METHOD PROTECTED readRequest : BOOL
    requestWrapper.FunctionCode := MODBUS_READ_INPUT_REGISTERS_CODE;
    requestWrapper.ReadStartingAddress := 16#0000;
    requestWrapper.QuantityToRead := 4;
    requestWrapper.RequestDataPointerToUInt := ADR(readArray);
    requestWrapper.RequestData.SizeOfArrayUInt := ANY_TO_UINT(SIZEOF(readArray));
    

    I have been trying to layout some OOP style to my Remote IO to create a framework that can be reused.

    TYPE STRUCT_DI_8 :
    STRUCT
       I00:DigitalInputObject;
       I01:DigitalInputObject;
       I02:DigitalInputObject;
       I03:DigitalInputObject;
       I04:DigitalInputObject;
       I05:DigitalInputObject;
       I06:DigitalInputObject;
       I07:DigitalInputObject;
    TYPE T_DO_8 :
    STRUCT
       Q00:DigitalOutputObject;
       Q01:DigitalOutputObject;
       Q02:DigitalOutputObject;
       Q03:DigitalOutputObject;
       Q04:DigitalOutputObject;
       Q05:DigitalOutputObject;
       Q06:DigitalOutputObject;
       Q07:DigitalOutputObject;
    VAR_GLOBAL
       remoteIOBank : RemoteIOObject ;  
    END_VAR
    FUNCTION_BLOCK RemoteIOObject EXTENDS ModbusConnection
    VAR     
       _Slot1: T_DI_8;
       _Slot2: T_DO_8;
    END_VAR
    Methods Slot1 and Slot2
    FUNCTION_BLOCK ModbusConnection
    VAR
    END_VAR
    METHOD PROTECTED readRequest : BOOL
    RemoteIO.FunctionCode := MODBUS_READ_INPUT_REGISTERS_CODE;
    RemoteIO.ReadStartingAddress := 16#0000;
    RemoteIO.QuantityToRead := 1;
    RemoteIO.RequestDataPointerToUInt := ADR(readArray);
    RemoteIO.RequestData.SizeOfArrayUInt := ANY_TO_UINT(SIZEOF(readArray));
    END_METHOD
    

    I think(hope) I am close, but having a hard time visualizing the connection of my Digital input and output objects into a controlword array that I need to pass to the modbus request wrapper. Thanks mostly to Scott Cunningham posts for helping to get my framework design this far.

    If I am not close...please help, if I am close, please point me towards the finish line.

     
  • Anonymous - 2016-12-19

    Originally created by: scott_cunningham

    There is difficult situation you are heading towards. On one hand, setting up an object to be a Modbus object such that if you change the value or check the value, a Modbus read/write should be triggered, is just what the concept of OOP idea is... However, if you do implement it that way, then each word in the Modbus array could/should trigger a read or write on the Modbus side. This is perfect for objects that are hardly used. But, if many of those objects are accessed often, then you generate many single word read/write requests on the Modbus... a definite bandwidth killer.

    You may be better off having a single FB responsible for reading/writing all of the data in some sort of cyclic manner (multiple register read/write). Then, in your ClassModbus object, you create a method that maps a local variable to one of the Modbus array elements. In this way, whenever the element is updated, the final object already sees it. I use this technique with EtherCAT.

    Example:

    In your case, you could have something like this:

    Then when you make your final object - say CommandSpeed, it could extend ClassModbus.

    Just an idea.

     
  • mike-mn - 2016-12-20

    Scott,
    Thanks for reading through my poorly formed question and providing the answer I was seeking in spite of it...

    You brought up my exact issue. I am having trouble with the linkToModbus method or in your case, the linkToEthercat method. I cant seem to visualize how calling this once, maintains the connection to the read and write arrays for the MBConnection. Since I am only instantiating the RemoteIO class once, does that mean I need 3 sets of variables for the IO points? One for code to use i.e. xx.DI1.TurnOn(), one for local RemoteIO use and one for Modbus use i.e. a bit of a word in the read array?

    FWIW, I do have the read connection call throttled and also only call writes on change. The connection cacked within a few seconds if I pounded it with calls.

     
  • mike-mn - 2017-01-19

    I ended up getting this to work well after much wailing and gnashing of teeth...

    Hope this helps someone in the future...not a lot of detail, but we can do mostly OOP style with Codesys...

     

Log in to post a comment.