Initialization of POUs (FB_Init)

necati
2022-07-25
2024-07-29
  • necati - 2022-07-25

    Hi there,

    I have a problem about Initialization process. My project has 3 POUs and calling sequence as shown below.

    In this example, all POUs are initialized, before PLC switches run position. So, C_init.X and C_init.Y gets always 0. In fact, the have to be equal GVL.X and GVL.Y variables. To prevent this, I want to initialize, manually, "MVB_Set_Parameters" with some global variable conditions in Main (PRG).

    It can be possible to do this? Can you please help me?

    1. Main (PRG) : Cyclic main program
    PROGRAM Main
    VAR
    END_VAR
    
    GVL.Condition:= TRUE;
    GVL.X:= 16;
    GVL.Y:= 3;
    MVB_Config();
    
    1. MVB_Config (PRG)
    PROGRAM MVB_Config
    VAR
        {attribute 'init_on_onlchange' }
        C_init: MVB_Set_Parameters(Condition:=GVL.Condition,X:=GVL.X,Y:=GVL.Y);
    END_VAR
    
    1. MVB_Set_Parameters (FB)
    FUNCTION_BLOCK MVB_Set_Parameters
    VAR_INPUT
        Condition:BOOL;
        X:INT;
        Y:INT;
    END_VAR
    VAR_OUTPUT
        xError:INT;
    END_VAR
    VAR
    
    END_VAR
    
    1. FB_Init (under MVB_Set_Parameters) : Initialization function
    //FB_Init is always available implicitly and it is used primarily for initialization.
    //The return value is not evaluated. For a specific influence, you can also declare the
    //methods explicitly and provide additional code there with the standard initialization
    //code. You can evaluate the return value.
    METHOD FB_Init: BOOL
    VAR_INPUT
        bInitRetains: BOOL; // TRUE: the retain variables are initialized (reset warm / reset cold)
        bInCopyCode: BOOL;  // TRUE: the instance will be copied to the copy code afterward (online change)   
        Condition:BOOL;
        X:INT;
        Y:INT;
    END_VAR
    
    THIS^.Condition:= Condition;
    THIS^.X:= X;
    THIS^.Y:= Y;
    
    
    IF Condition THEN
        xError:=X+Y;
    ELSE
        xError:=X*Y;
    END_IF
    
     
  • hermsen

    hermsen - 2022-07-25

    Changed the anwser after a discussion with @fajean.

    Yes the FB_Init can write the value's in the input parameter but calling the FB with input parameters will overwrite the initial value cyclically.

    My suggestion

    PROGRAM MVB_Config
    VAR_INPUT
        Condition:BOOL;
        X:INT;
        Y:INT;
    END_VAR
    VAR
        xError: INT;
    END_VAR
    
    
    /// BODY
    IF Condition THEN
        xError:=X+Y;
    ELSE
        xError:=X*Y;
    END_IF
    
    PROGRAM Main
    VAR
    END_VAR
    
    
    ///Body
    GVL.Condition:= TRUE;
    GVL.X:= 16;
    GVL.Y:= 3;
    MVB_Config( GVL.Condition, GVL.X, GVL.Y );
    

    Tip: Just use one program and rewrite MVB_Config into a Function Block and the give in an initalisation method. That way the program becomes modular.

     

    Last edit: hermsen 2022-07-26
    • fajean - 2022-07-25

      You write :

      FBInit can not initialize FUNCTIONBLOCK inputs since they are INPUTS and thus they are read only and BY VALUE from point of view of method FBInit Method.

      Do you mean this as a recommendation, or as a statement of limitations of the compiler?

      I do not think the compiler enforces VAR_INPUT to be read-only from within the function block or its FB_Init. VAR_INPUT variable can also be of the "REFERENCE TO" or "POINTER TO" kinds, so inputs are not necessarily BY VALUE. Having FB_Init write to the inputs of a function block is technically possible and valid I think.

      Everything I do is structured text only, so maybe things I do in ST would not work for function blocks intent to be used in "visual" languages. I basically use VAR_INPUT as "public members" (as opposed to VAR which I use as "private members", although they are still accessible, just hidden in the IDE's drop-down list).

       
      • hermsen

        hermsen - 2022-07-26

        I do not think the compiler enforces VAR_INPUT to be read-only from within the function block or its FBInit. VAR_INPUT variable can also be of the "REFERENCE TO" or "POINTER TO" kinds, so inputs are not necessarily BY VALUE. Having FB_Init write to the inputs of a function block is technically possible and valid I think.

        I have tested your idea in 3.5.17.10;
        The situation is rather complex so bear with me.

        1) If the FB is instantiated and NOT called from code, any input can written from the inside of the FB (yes this is valid operation, but I personally think this is NOT a good practice as it makes for code very confusing code due to at least 2 reasons:
        1) An instance is "expected" to be called during runtime,
        2) If the instance is called during runtime, inputs of the instance are continuously written by the caller, so they are regarded as read-only from within the FB (but technically they are writable but overwritten)
        3) If the instance of the FB is NOT called, inputs can written from within the FB body but this is perceived as counter intuitive and should be avoided.

        In other words, should you do it just because you can? In this case I'd say no unless you show me some good practical usage* for this. I am looking forward to your suggestions.

        PS I deliberately did not mention usage of pointers, interfaces or references (I regard these as "pointers" in general) with which many more tricks can be done. Avoid using them in your example ;-)

         
        • fajean - 2022-07-26

          I think writing to inputs to give them an initial value from a FB_Init is fine in all cases. Of course, thereafter, if the inputs are cyclically fed with values and the inputs are also written to from code, there is going to be a problem.

          I use structured text as a "normal" programming language. I have implemented my own cyclical execution framework (my function blocks have no body, and that empty body is never called). My function blocks cannot be used in a ladder diagram, which is not a tradeoff for me because the ladder diagram that would express the systems I design would probably cover entire football fields.

          I use VAR_INPUT not as a way to connect my function blocks together and have their code called, but rather as writable public member variables. I make heavy use of this, with most of these VAR_INPUT variables being structures.

          I would agree, however, that when relying on the native execution model, writing to inputs would probably very rarely be a good idea (except, perhaps, for setting initial values).

           
  • hermsen

    hermsen - 2022-07-25

    I am trying to help out our friend with useful feedback. Since I dont know his knowledge level of ST so I thought not to bother with references or pointers via VAR_INPUT.

    Have you got some tips for him?

     

    Last edit: hermsen 2022-07-25
  • fajean - 2022-07-25

    Expanding on h-hermsen's final tip, consider this idea:

    The main program :

    // Main program
    PROGRAM MAIN
    VAR
        {attribute 'init_on_onlchange' }
        C_init: MVB_Set_Parameters(TRUE, 16, 3);  
    END_VAR
    

    The helper function block :

    FUNCTION_BLOCK MVB_Set_Parameters
    VAR_INPUT
      Condition:BOOL;
      X:INT;
      Y:INT;
    END_VAR
    VAR_OUTPUT
        xError:INT;
    END_VAR
    

    The helper function block's FB_Init :

    METHOD FB_Init: BOOL
    VAR_INPUT
      bInitRetains: BOOL;
      bInCopyCode: BOOL;
      Condition:BOOL;
      X:INT;
      Y:INT;
    END_VAR
    
    THIS^.Condition:= Condition;
    THIS^.X:= X;
    THIS^.Y:= Y;
    
    IF Condition THEN
        xError:=X+Y;
    ELSE
        xError:=X*Y;
    END_IF
    

    Please note both the main program and the function block have no body. The inputs are set once at the beginning, not cyclically : I do not know if this fits your intent.

     
    • installwhat - 2024-07-29

      Hi

      I was wondering if there's a pattern I can employ to acheive what you're doing but with a "reference to" and also allowing for online changes?

      Someone told me that the new beckhoff keeps references safe during online changes but all the documentation I've found suggests that's not the case.

      The easiest thing is to use fb_init for normal vars and pointers and references can be added in the function body every cycle and this allows for method calls after so far as I can tell.

       
  • necati - 2022-07-26

    Dear fajean and h-hermsen,

    Thanks for your quick recommendations. I will try them.

     
    πŸ‘
    1

Log in to post a comment.