PLC-LadderLearn

Structuring a program: POUs, function blocks, UDTs

A real machine is not one long list of rungs. IEC 61131-3 gives you three tools to keep it readable, and PLC-Ladder compiles, draws and simulates all three. This page walks through a small conveyor line built with them; you can open it in the workbench and run its tests.

1 · Programs (POUs) split the machine into parts

A program organisation unit (POU) is one PROGRAM, FUNCTION_BLOCK or FUNCTION. Give each part of the machine its own program: here the line has Infeed, Station and Outfeed, each with its own inputs and outputs (declared with addresses such as %IX0.0) and its own ladder.

2 · Function blocks: define once, use per device (Rockwell: AOI)

What Rockwell calls an add-on instruction (AOI) is a function block: logic plus its own memory, defined once and instantiated once per device. MotorBlock holds a start / stop seal-in, an interlock, a running-feedback timer that latches a fault, and a SimMode input that makes the feedback follow the command so the line can be simulated without real contactors. All three programs use it, each with its own instance.

TYPE ConveyorStatus :
STRUCT
    Running : BOOL;
    Fault : BOOL;
    Parts : INT;
END_STRUCT
END_TYPE

FUNCTION_BLOCK MotorBlock
VAR_INPUT
    StartCmd : BOOL;     (* start request: pushbutton, HMI or sequence *)
    StopCmd : BOOL;      (* stop request *)
    Interlock : BOOL;    (* TRUE = permitted to run (E-stop, guards, overload) *)
    Feedback : BOOL;     (* running feedback from the contactor auxiliary *)
    SimMode : BOOL;      (* TRUE in simulation: the feedback follows Run *)
    Reset : BOOL;        (* clears a latched fault *)
    FeedbackTime : TIME; (* how long the feedback may take, e.g. T#2s *)
END_VAR
VAR_OUTPUT
    Run : BOOL;          (* the contactor coil *)
    Running : BOOL;      (* Run confirmed by the feedback *)
    Fault : BOOL;        (* no feedback in time, latched until Reset *)
END_VAR
VAR
    FeedbackTimer : TON;
END_VAR
Run := (StartCmd OR Run) AND NOT StopCmd AND Interlock AND NOT Fault;
Running := Run AND (Feedback OR SimMode);
FeedbackTimer(IN := Run AND NOT (Feedback OR SimMode), PT := FeedbackTime);
Fault := (FeedbackTimer.Q OR Fault) AND NOT Reset;
END_FUNCTION_BLOCK

3 · User data types (UDTs): group what belongs together

A TYPE ... STRUCT groups related signals. Every program here keeps a ConveyorStatus with Running, Fault and Parts, reached member by member (Status.Parts := PartCounter.CV;). The ladder and the Signals panel show the dotted names, and an HMI connected over OPC UA sees nodes such as Status.Running.

PROGRAM Station
VAR
    RunCmd AT %IX1.0 : BOOL;
    PartSensor AT %IX1.1 : BOOL;
    CountReset AT %IX1.2 : BOOL;
    StationMotor AT %QX1.0 : BOOL;
    Motor2 : MotorBlock;
    PartCounter : CTU;
    Status : ConveyorStatus;
END_VAR
// the same MotorBlock again: one definition, one instance per belt
Motor2(StartCmd := RunCmd, StopCmd := NOT RunCmd, Interlock := TRUE, Feedback := FALSE,
       SimMode := TRUE, Reset := FALSE, FeedbackTime := T#2s);
StationMotor := Motor2.Run;
PartCounter(CU := PartSensor AND Motor2.Run, RESET := CountReset, PV := 100);
Status.Running := Motor2.Running;
Status.Fault := Motor2.Fault;
Status.Parts := PartCounter.CV;
END_PROGRAM

4 · Tests that prove it

The example comes with scenario tests that the simulator runs on every change:

  • Infeed: Start runs the infeed motor, it keeps running when Start is released, and Stop stops it.
  • Station: The station motor follows RunCmd.
  • Station: Parts are counted only while the station motor runs; CountReset clears the count.
  • Outfeed: A full outfeed stops the belt, and Start does not restart it until the outfeed clears.

What is supported, exactly

Function blocks: inputs, outputs and local variables, timers, counters and other blocks inside, no recursion and no VAR_IN_OUT. Structs: members BOOL, INT, DINT, REAL, TIME or a one-dimensional array of those, one level of nesting, used member by member (not inside function blocks yet). Anything else is refused with the line and the reason, never converted wrongly.

Open the conveyor line in the workbenchCreate a free account