How are user-defined functions and blocks created in CoDeSys?

Write repeated logic once and call the right kind of unit
Hello friends. In CODESYS, user-defined code is created in program organisation units (POUs). Functions (FUN) and function blocks (FB) are different structures in the IEC 61131-3 approach. UDF and UDFB may be used descriptively; the basic types selected in the editor are Function and Function block.
Function or function block?
A function suits calculations and conversions. Its ordinary local variables do not preserve state between calls. Its main result is a return value, which can be a simple type, structure or array. CODESYS also supports additional VAR_OUTPUT outputs. Therefore, declaring an output variable is not the same as assigning the function’s return value. Select the data type for the expected input and result ranges.
A function block maintains separate state in each instance. Counters, timers and device-state tracking are typical uses. You can create two instances of one FB type without one counter changing the other. The FB type is the template; the stored operating state belongs to its instance.
Creation steps in CODESYS V3.5
Select the Application object in your project and open Add Object / POU. Enter a name and choose Function or Function block. For a function, also specify its Return type. Project-wide POUs can be added in the POUs view; choose their scope deliberately.
Select Structured Text (ST) for these examples. FBD or Ladder can also be appropriate. Not every language is available for every POU type: in the CODESYS Add POU dialog, Function is unavailable when SFC is selected as the implementation language. Calling a function from an SFC action or transition is a separate matter.
Separate the editor’s declaration section from its implementation section. Comments in the examples identify which code belongs in each section. VAR_INPUT declares inputs, VAR_OUTPUT additional outputs and VAR local variables. The examples contain no physical I/O addresses.
Example 1: A linear scaling function
Create a Function named F_LinearScale with return type REAL. It calculates result = input × gain + offset. Assign the main result to the function name in the implementation section. Pass the measurement as an input parameter rather than reading a fixed hardware address inside the function.
(* Declaration *)
FUNCTION F_LinearScale : REAL
VAR_INPUT
rRaw : REAL;
rGain : REAL;
rOffset : REAL;
END_VAR
(* Implementation *)
F_LinearScale := rRaw * rGain + rOffset;
An input of 12.0, gain of 6.25 and offset of −25.0 produce 50.0. These coefficients nominally map 4–20 mA to 0–100%, assuming the input already represents milliamperes. A raw analogue register value is not a milliampere value. Scaling, sensor-break detection and out-of-range handling require separate treatment in the PLC application.
Example 2: A pulse counter with its own state
Create a Function block named FB_PulseCounter. It counts a transition from FALSE to TRUE, rather than counting every cycle while the signal remains TRUE. Reset has priority. The counter stops at the UDINT upper limit, which is indicated by xAtLimit.
(* Declaration *)
FUNCTION_BLOCK FB_PulseCounter
VAR_INPUT
xPulse : BOOL;
xReset : BOOL;
END_VAR
VAR_OUTPUT
udiCount : UDINT := 0;
xAtLimit : BOOL;
END_VAR
VAR
xPrevious : BOOL := FALSE;
END_VAR
(* Implementation *)
IF xReset THEN
udiCount := 0;
ELSIF xPulse AND NOT xPrevious THEN
IF udiCount < UDINT#4294967295 THEN
udiCount := udiCount + UDINT#1;
END_IF;
END_IF;
xPrevious := xPulse;
xAtLimit := (udiCount = UDINT#4294967295);
xPrevious remembers the instance’s input from the previous call. Call the block regularly; pulses shorter than the task cycle can be missed between scans. Fast physical pulses require suitable counter hardware. If the input is TRUE on the first call, this example counts one pulse; assess that startup behaviour for your application.
Calling the function and two independent FB instances
Declare fbLineA and fbLineB in the ordinary VAR section of PLC_PRG. Call a function by its name and a function block by its instance name. Read outputs after the call. Also confirm PLC_PRG is called by the appropriate task.
(* PLC_PRG declaration *)
PROGRAM PLC_PRG
VAR
fbLineA : FB_PulseCounter;
fbLineB : FB_PulseCounter;
xPulseA : BOOL := FALSE;
xPulseB : BOOL := FALSE;
xResetA : BOOL := FALSE;
xResetB : BOOL := FALSE;
udiCountA : UDINT;
udiCountB : UDINT;
rScaled : REAL;
END_VAR
(* PLC_PRG implementation *)
rScaled := F_LinearScale(
rRaw := 12.0,
rGain := 6.25,
rOffset := -25.0
);
fbLineA(xPulse := xPulseA, xReset := xResetA);
fbLineB(xPulse := xPulseB, xReset := xResetB);
udiCountA := fbLineA.udiCount;
udiCountB := fbLineB.udiCount;
Here, udiCountA and udiCountB are independent counters. Since xPulseA and xPulseB have not been mapped to physical inputs, they initially remain FALSE. Assigning input values alone does not execute the block; the fbLineA(...) call is required. Inputs use := in a call; an output can be connected to an external variable using =>.
Editor’s note: Preserving state between calls does not mean preserving it through a power loss. An ordinary FB instance can keep its state from the previous cycle; restart, reset and download behaviour require separate assessment. Do not apply RETAIN/PERSISTENT indiscriminately to an entire block; identify the data that actually needs retention.
Compilation, testing and reuse
Use Build to check declarations and type errors. During debugging, monitor instance inputs, outputs and internal state. Test scaling endpoints, a continuously TRUE signal, a single pulse, reset and independence between the two counters. Verify call frequency and restart behaviour separately on the target hardware.
Use explicit input/output interfaces and reduce hidden global dependencies. Evaluate error outputs in the application. Document names, units, initial conditions and reset behaviour. When moving shared code into a library, manage its version and dependencies; security settings can restrict project editing permissions.
Related CODESYS topics
What CODESYS is used for | Key features | Programming languages
Training resources | What is a PLC? | PLCs and accessories
Sources
CODESYS — Object: POU — POU creation, type selection and language restrictions.
CODESYS — Object: Function — Return values, calls and additional outputs.
CODESYS — Object: Function Block — Instances, state and input/output access.
Beckhoff — Use of function blocks — Temporary instances, encapsulation and error information.
PLCopen — Coding Guidelines — Naming, comments and reusable code.