Skip to content

Function Blocks and Libraries

Commercial

Included in the public demo Compare editions

A FUNCTION_BLOCK keeps inputs, outputs and local state in each instance between calls and scans. Reuse the same definition for independent machines or sequences. Put shared FUNCTION and FUNCTION_BLOCK declarations in PLCLibrary components on model nodes.

Each PLCProgram has its own instances and memory. A PLCLibrary supplies definitions; it has no scan or Run state.

One definition, many instances A PLC Library on a model node holds FUNCTION and FUNCTION_BLOCK definitions but never scans. Every active library is visible to every PLC Program of the model. Each program declares its own instances of a function block, such as two Gate instances in Line1 and one in Line2, and each instance keeps its own inputs, outputs and state between scans. One definition, many instances PLC Library definitions only, no scan FUNCTION_BLOCK Gate FUNCTION Scale Active includes it, Order sorts the libraries PLC Program Line1 gateIn : Gate own state gateOut : Gate own state PLC Program Line2 gate : Gate own state k := Scale(…) fresh on every call Every active library, including those in placed content, is visible to every program of the model.
The library supplies the definition; each program owns its instances. Stop → Run keeps instance state; Deploy and Reset start every instance cold.
PLCLibrary propertyTypeDefaultPurpose
NamestringemptyDisplay label
CodeST sourceemptyFUNCTION / FUNCTION_BLOCK declarations only
ActiveBooleantrueInclude this source in the model-wide library set
Ordernumber, unitless0Ascending compile inventory order

Active and Order use standard inspector editors; Name labels the source in the PLC editor title (for example CellBlocks.st). Edit opens Code in the shared PLC editor, with autosave and undo/redo. Save the document to retain the source.

A PLC Library selected in the editor: the inspector shows its Code, Active and Order, and Edit has opened the source with a FUNCTION_BLOCK and a FUNCTION in the PLC editor

All programs see all active model libraries, including placed content. The runtime sorts by Order, then source identity, then scene path; signatures are collected before bodies, so forward references work. Order does not allow same-name overrides.

  1. Add a PLCLibrary component to a model node and choose Edit.
  2. Enter this definition:
FUNCTION_BLOCK DelayCell
VAR_INPUT Enable : BOOL; Delay : TIME := T#1s; END_VAR
VAR_OUTPUT Ready : BOOL; END_VAR
VAR timer : TON; END_VAR
timer(IN := Enable, PT := Delay);
Ready := timer.Q;
END_FUNCTION_BLOCK
  1. Add a PLCProgram and open its editor:
PROGRAM Main
VAR cell : DelayCell; END_VAR
VAR_EXTERNAL Start : BOOL; Ready : BOOL; END_VAR
cell(Enable := Start, Ready => Ready);
END_PROGRAM
  1. Deploy and Run the program. Bind Start/Ready to model signals.

The instance retains Delay = T#1s until a call supplies another value. Read cell.Ready after a call, or copy it with Ready => Ready. Instance initialization can override inputs, for example cell : DelayCell := (Delay := T#2s);. Direct member assignment is unsupported; change inputs through the call.

Use VAR_INPUT for retained input values, VAR_OUTPUT for readable outputs, VAR for private state, and VAR_IN_OUT for references to caller variables. Calls always use named FB parameters: := for inputs/IN_OUT, => for output copies. RETURN; exits the current invocation. Constants use VAR CONSTANT.

Every IN_OUT argument is required on every call and must have exactly the declared type. Allowed actual variables:

  • In PROGRAM: its VAR or VAR_EXTERNAL scalar.
  • Inside an FB: its own VAR, VAR_OUTPUT or VAR_IN_OUT scalar, including pass-through.

Constants, expressions, literals, FB member expressions and FB inputs cannot be IN_OUT actuals. One variable cannot serve two IN_OUT parameters of the same call. References are transient; do not bind IN_OUT in an initializer. External effects propagate through nested calls and participate in signal reads, writes and conflict checks.

Use user FBs for repeated cell logic, reusable handshakes and wrappers around standard timers/counters. Nested user and standard FB instances are independent, including reset and snapshot state. Direct/indirect recursion is rejected. MC FBs must be declared in PROGRAM, not inside user FBs.

Library type identity is the defining document + PLCLibrary NodeId + POU name, independent of display name and placement. Repeated placements of one source share its definitions; two different sources defining the same POU name cause a compile error.

Libraries, your own functions and your own function blocks work in both simulation modes. The difference is when an instance runs and what it must do to be DES-ready:

Continuous simulationDES (event-driven)
Function blocks availableStandard FBs, your own FBs and PLCopen MC_ blocksStandard FBs and your own FBs; a program with MC_ blocks goes into error (rule D5)
When an instance runsOn every scan, once per simulation tickOnly when its program scans: on start, on a change of a signal it reads, at a timer deadline, or again at the same time after its own change
Instance stateKept between scansKept between events; a change of FB state triggers another scan at the same time until the state is stable
Timers (TON, TOF, TP)Advance with simulation timeAdvance with simulation time; the deadline wakes the program
Code that changes on every scanRuns, once per tickNever settles: finding D1, not DES-ready, experiment batches refuse the model
DES checkNot applicableWalks through the bodies of your own FUNCTIONs and FBs; an FB is not DES-ready just because it compiles

Write FB logic that reacts to edges, step changes or timers, so that another call with unchanged inputs leaves the state unchanged. The rules and examples are in Writing ST for DES.