Function Blocks: Building Reusable Automation Components
FUNCTION: Computation Without Memory
A FUNCTION in IEC 61131-3 takes inputs, performs a calculation, and returns a single result. Functions have no internal memory: same inputs always produce the same output.
FUNCTION ScaleAnalog : REAL
VAR_INPUT
nRawValue : INT; rEngLow : REAL; rEngHigh : REAL;
nRawLow : INT; nRawHigh : INT;
END_VAR
ScaleAnalog := rEngLow +
(INT_TO_REAL(nRawValue - nRawLow) /
INT_TO_REAL(nRawHigh - nRawLow)) *
(rEngHigh - rEngLow);
END_FUNCTION
Functions are ideal for mathematical scaling, unit conversion, clamping values, and checksum calculations. Because they have no memory, they cannot contain timers, counters, or persistent state.
FUNCTION_BLOCK: Computation With Memory
A FUNCTION_BLOCK (FB) retains internal data between calls. Each instance has independent memory, making it perfect for motors, valves, PID controllers, and communication handlers.
FUNCTION_BLOCK FB_Motor
VAR_INPUT
bStart : BOOL; bStop : BOOL;
bReset : BOOL; bOverload : BOOL;
END_VAR
VAR_OUTPUT
bRunning : BOOL; bFaulted : BOOL; bReady : BOOL;
END_VAR
VAR
bLatched : BOOL;
END_VAR
IF NOT bOverload AND bLatched THEN bFaulted := TRUE; bLatched := FALSE; END_IF;
IF bReset AND bFaulted THEN bFaulted := FALSE; END_IF;
IF bStart AND NOT bFaulted THEN bLatched := TRUE; END_IF;
IF bStop OR bFaulted THEN bLatched := FALSE; END_IF;
bRunning := bLatched;
bReady := NOT bFaulted AND NOT bRunning;
END_FUNCTION_BLOCK
Each physical motor gets its own instance. Changing the logic inside FB_Motor fixes every motor in the plant simultaneously.
PROGRAM: The Top Level
A PROGRAM is the top-level unit called by the PLC runtime each scan cycle. Programs instantiate function blocks and coordinate overall machine logic.
PROGRAM Main
VAR
fbMotor1 : FB_Motor;
fbMotor2 : FB_Motor;
END_VAR
fbMotor1(bStart := bStartAll, bStop := bStopAll,
bReset := bFaultReset, bOverload := bOL1);
fbMotor2(bStart := bStartAll AND fbMotor1.bRunning,
bStop := bStopAll, bReset := bFaultReset,
bOverload := bOL2);
END_PROGRAM
A well-organized project has a main program for orchestration, an I/O mapping program, individual function blocks per device type, and an alarm handling program.
Building a Motor Control Function Block
Extending FB_Motor with feedback monitoring and fault codes for HMI display:
FUNCTION_BLOCK FB_MotorAdvanced
VAR_INPUT
bStart : BOOL; bStop : BOOL; bReset : BOOL;
bOverload : BOOL; bFeedback : BOOL;
tStartupTime : TIME := T#5s;
END_VAR
VAR_OUTPUT
bRunning : BOOL; bFaulted : BOOL;
nFaultCode : INT; // 0=OK, 1=overload, 2=no feedback
END_VAR
VAR
bCommandRun : BOOL; tonFB : TON;
END_VAR
IF bCommandRun AND NOT bOverload THEN
nFaultCode := 1; bFaulted := TRUE; bCommandRun := FALSE;
END_IF;
tonFB(IN := bCommandRun AND NOT bFeedback, PT := tStartupTime);
IF tonFB.Q THEN
nFaultCode := 2; bFaulted := TRUE; bCommandRun := FALSE;
END_IF;
IF bStart AND NOT bFaulted THEN bCommandRun := TRUE; END_IF;
IF bStop THEN bCommandRun := FALSE; END_IF;
IF bReset AND NOT bCommandRun THEN bFaulted := FALSE; nFaultCode := 0; END_IF;
bRunning := bCommandRun AND bFeedback;
END_FUNCTION_BLOCK
Libraries: Reusing Blocks Across Projects
Proven function blocks are packaged into libraries for reuse. A typical library contains motor control blocks (DOL, Star-Delta, VFD), valve control blocks (on-off, analog), sensor processing (scaling, filtering, fault detection), communication blocks (Modbus RTU/TCP), and utility blocks (edge detection, flashing lights, debounce).
Treat PLC libraries like software releases with version numbers and documentation for every block including inputs, outputs, and usage examples.
Practical Example: A Custom Factory Control Library
A filling nozzle block for a packaging factory opens a valve, accumulates flow, and signals completion when the target volume is reached:
FUNCTION_BLOCK FB_FillingNozzle
VAR_INPUT
bEnable : BOOL; rTargetVolume : REAL; rFlowRate : REAL;
END_VAR
VAR_OUTPUT
bValveCmd : BOOL; bComplete : BOOL; rFilledVolume : REAL;
END_VAR
VAR
rAccumulated : REAL;
END_VAR
IF bEnable AND NOT bComplete THEN
bValveCmd := TRUE;
rAccumulated := rAccumulated + (rFlowRate * 0.001);
IF rAccumulated >= rTargetVolume THEN
bValveCmd := FALSE; bComplete := TRUE; rFilledVolume := rAccumulated;
END_IF;
ELSIF NOT bEnable THEN
bValveCmd := FALSE; bComplete := FALSE; rAccumulated := 0.0;
END_IF;
END_FUNCTION_BLOCK
Using this for an 8-nozzle filling machine:
VAR
afbNozzles : ARRAY[0..7] OF FB_FillingNozzle;
END_VAR
FOR i := 0 TO 7 DO
afbNozzles[i](bEnable := bStartFill,
rTargetVolume := rRecipeVolume,
rFlowRate := arFlowSensors[i]);
abValveOutputs[i] := afbNozzles[i].bValveCmd;
END_FOR;
Eight nozzles, each independently controlled, all using the same proven block. Improve the algorithm once, and the change applies to every nozzle on every machine that uses this library.
Summary
IEC 61131-3 provides three organizational units: FUNCTION for stateless calculations, FUNCTION_BLOCK for stateful device control with independent instances, and PROGRAM as the top-level entry point. Function blocks are the foundation of modular PLC programming, allowing you to write motor, valve, and sensor logic once and reuse it everywhere. Packaging proven blocks into versioned libraries ensures consistency and reduces development time across an entire plant.