Paste or import your IEC 61131-3 ST code and instantly get a clean state or flow diagram, automatic validation, and export to 6 formats. Built for PLC engineers and system integrators.
PLC state machines live as long CASE blocks — hard to review, harder to hand over.
From source code to a shareable diagram in three steps.
Type or paste your Structured Text into the editor, or import a .txt file. Syntax highlighting helps you right away.
The state variable is detected automatically. Choose the diagram type that best fits your machine.
Get a diagram, a validation score with checks, and an overview of every state and transition — ready to share.
Pick an example and switch between state and flow — these are real diagrams generated by the tool, right here.
A compact four-state machine — the quickest way to read a diagram.
PROGRAM PRG_TrafficLight
VAR
xEnable : BOOL; // Master enable for the intersection
xPedestrian : BOOL; // Pedestrian request button
iStep : INT := 0; // State machine step
xRed : BOOL; // Red lamp output
xYellow : BOOL; // Yellow lamp output
xGreen : BOOL; // Green lamp output
xWalk : BOOL; // Pedestrian "walk" lamp
fbStepTimer : TON; // Phase timer
END_VAR
CASE iStep OF
0: // RED
xRed := TRUE;
xYellow := FALSE;
xGreen := FALSE;
xWalk := FALSE;
fbStepTimer(IN := TRUE, PT := T#5s);
IF xEnable AND fbStepTimer.Q THEN
fbStepTimer(IN := FALSE);
iStep := 10; // Go to green
END_IF;
10: // GREEN
xRed := FALSE;
xGreen := TRUE;
fbStepTimer(IN := TRUE, PT := T#8s);
IF fbStepTimer.Q THEN
fbStepTimer(IN := FALSE);
iStep := 20; // Time to clear the intersection
END_IF;
20: // YELLOW
xGreen := FALSE;
xYellow := TRUE;
fbStepTimer(IN := TRUE, PT := T#3s);
IF fbStepTimer.Q THEN
fbStepTimer(IN := FALSE);
IF xPedestrian THEN
iStep := 30; // Serve waiting pedestrians
ELSE
iStep := 0; // Back to red
END_IF;
END_IF;
30: // WALK
xRed := TRUE;
xYellow := FALSE;
xWalk := TRUE;
fbStepTimer(IN := TRUE, PT := T#6s);
IF fbStepTimer.Q THEN
fbStepTimer(IN := FALSE);
xWalk := FALSE;
iStep := 0; // Back to red
END_IF;
END_CASE;
PROGRAM PLC_PRG
VAR
// System Control Inputs
xStartKnop : BOOL; // Starts the batch process
xStopKnop : BOOL; // Pauses the process safely
xNoodstop : BOOL; // Emergency Stop (Active LOW)
xResetKnop : BOOL; // Resets faults
// Process Feedback Sensors
rActueelGewicht : REAL; // Current tank weight from load cells [kg]
rDoelGewicht : REAL := 500.0; // Target weight for raw material [kg]
xNiveauHoog : BOOL; // High level switch sensor (safety backup)
xNiveauLaag : BOOL; // Low level switch sensor (tank empty indicator)
// Actuator Outputs
xVulVentiel : BOOL; // Control valve for filling raw material
xMengMotor : BOOL; // Motor control for the tank mixer
xAfvoerVentiel : BOOL; // Control valve for discharging final product
// Internal State Machine Variables
diStap : DINT := 0; // Current step indicator for state machine
diVorigeStap : DINT := -1; // Tracking for ENTRY logic execution
xFoutActief : BOOL; // System fault flag
sStatusMelding : STRING; // Human-readable status message
// Process Timers
fbMengTimer : TON; // Timer for the mixing duration
fbVulTimeout : TON; // Safety timeout if filling takes too long
END_VAR
// =============================================================================
// GLOBAL SAFETY INTERLOCKS (Executed every cycle)
// =============================================================================
IF NOT xNoodstop THEN
diStap := 100; // Immediate jump to Emergency Stop State
END_IF;
// =============================================================================
// MAIN STATE MACHINE
// =============================================================================
CASE diStap OF
0: // IDLE STATE
sStatusMelding := "0 - System Idle. Awaiting Start.";
xVulVentiel := FALSE;
xMengMotor := FALSE;
xAfvoerVentiel := FALSE;
// Transition Condition
IF xStartKnop AND NOT xStopKnop AND NOT xFoutActief THEN
diStap := 10; // Proceed to Initialization
END_IF;
10: // INITIALIZATION
sStatusMelding := "10 - Initializing Process and Verifying Sensors.";
// Reset process timers
fbMengTimer(IN := FALSE);
fbVulTimeout(IN := FALSE);
// Transition Condition (Verify tank is ready and empty)
IF NOT xNiveauHoog THEN
diStap := 20; // Proceed to Filling
ELSE
xFoutActief := TRUE;
diStap := 90; // High level fault on startup
END_IF;
20: // FILLING RAW MATERIAL
sStatusMelding := "20 - Filling Valve Open. Dosing Material.";
xVulVentiel := TRUE;
// Run safety filling timeout
fbVulTimeout(IN := TRUE, PT := T#45s);
// Transition Conditions
IF rActueelGewicht >= rDoelGewicht THEN
xVulVentiel := FALSE;
diStap := 30; // Weight reached, go to Mixing
ELSIF fbVulTimeout.Q OR xNiveauHoog THEN
xVulVentiel := FALSE;
xFoutActief := TRUE;
diStap := 91; // Timeout or Overflow Fault
ELSIF xStopKnop THEN
xVulVentiel := FALSE;
diStap := 50; // Pause requested
END_IF;
30: // MIXING PROCESS
sStatusMelding := "30 - Mixing Agitator Running.";
xMengMotor := TRUE;
// Run mixing timer (e.g., 15 seconds)
fbMengTimer(IN := TRUE, PT := T#15s);
// Transition Conditions
IF fbMengTimer.Q THEN
xMengMotor := FALSE;
diStap := 40; // Mixing done, go to Discharge
ELSIF xStopKnop THEN
xMengMotor := FALSE;
diStap := 50; // Pause requested
END_IF;
40: // DISCHARGING TANK
sStatusMelding := "40 - Discharge Valve Open. Emptying Tank.";
xAfvoerVentiel := TRUE;
// Transition Conditions
IF NOT xNiveauLaag AND rActueelGewicht <= 5.0 THEN
xAfvoerVentiel := FALSE;
diStap := 0; // Tank is empty, return to Idle
ELSIF xStopKnop THEN
xAfvoerVentiel := FALSE;
diStap := 50; // Pause requested
END_IF;
50: // PAUSE STATE
sStatusMelding := "50 - Process Paused by Operator.";
// Keep all actuators safely off during pause
xVulVentiel := FALSE;
xMengMotor := FALSE;
xAfvoerVentiel := FALSE;
// Transition Condition (Resume or Abort)
IF xStartKnop AND NOT xStopKnop THEN
// Retain timers and jump back to previous execution state
IF rActueelGewicht < rDoelGewicht THEN
diStap := 20; // Resume Filling
ELSE
diStap := 30; // Resume Mixing
END_IF;
END_IF;
90: // FAULT: STARTUP HIGH LEVEL OVERFLOW
sStatusMelding := "90 - CRITICAL FAULT: Tank high level on startup.";
IF xResetKnop THEN
xFoutActief := FALSE;
diStap := 0;
END_IF;
91: // FAULT: FILLING TIMEOUT / OVERFLOW
sStatusMelding := "91 - CRITICAL FAULT: Filling timeout or sensor high active.";
IF xResetKnop AND NOT xNiveauHoog THEN
xFoutActief := FALSE;
diStap := 10; // Re-initialize
END_IF;
100: // EMERGENCY STOP ACTIVE
sStatusMelding := "100 - EMERGENCY STOP ACTIVE. Hard shutdown.";
xVulVentiel := FALSE;
xMengMotor := FALSE;
xAfvoerVentiel := FALSE;
// Transition Condition (Only allow escape if hardware E-stop is physically cleared)
IF xNoodstop AND xResetKnop THEN
diStap := 0; // Return to Idle safely
END_IF;
ELSE
// Catch-all safety for undefined states
diStap := 100;
END_CASE;
// =============================================================================
// TIMER FUNCTION BLOCK CALLS (Executed every cycle)
// =============================================================================
fbMengTimer();
fbVulTimeout();
PROGRAM PRG_ConveyorSorter
VAR
xStart : BOOL; // Start / run request
xPartPresent : BOOL; // Photo-eye: part on the belt
xScanDone : BOOL; // Vision scan finished
xIsReject : BOOL; // Scan result: bad part
xDiverted : BOOL; // Pusher reached end position
xFault : BOOL; // Any drive / sensor fault
xReset : BOOL; // Operator reset
xBelt : BOOL; // Belt motor output
xPusher : BOOL; // Divert pusher output
iStep : INT := 0; // State machine step
fbScan : TON; // Vision scan dwell timer
END_VAR
IF xFault THEN
iStep := 90; // Jump to fault from any state
END_IF;
CASE iStep OF
0: // IDLE
xBelt := FALSE;
xPusher := FALSE;
IF xStart AND xPartPresent THEN
iStep := 10; // Part detected, start transporting
END_IF;
10: // TRANSPORT
xBelt := TRUE;
fbScan(IN := TRUE, PT := T#1s);
IF fbScan.Q THEN
fbScan(IN := FALSE);
iStep := 20; // Hold under the scanner
END_IF;
20: // SCAN
xBelt := FALSE;
IF xScanDone THEN
IF xIsReject THEN
iStep := 40; // Bad part, push to reject lane
ELSE
iStep := 30; // Good part, pass through
END_IF;
END_IF;
30: // ACCEPT
xBelt := TRUE;
IF NOT xPartPresent THEN
iStep := 0; // Part has left the belt
END_IF;
40: // DIVERT
xBelt := FALSE;
xPusher := TRUE;
IF xDiverted THEN
xPusher := FALSE;
iStep := 0; // Reject pushed off, back to idle
END_IF;
90: // FAULT
xBelt := FALSE;
xPusher := FALSE;
IF xReset THEN
iStep := 0; // Cleared, back to idle
END_IF;
END_CASE;
No code yet? Build the machine on a canvas and let the Designer write clean IEC 61131-3 Structured Text for you.
Designer & Digital Twin — account + paid plan
Split the Designer canvas and watch your machine's I/O on a live 3D or 2D twin — then run the sequence to test its behaviour.
Designer & Digital Twin — account + paid plan
Everything you need to document and review PLC logic.
States as nodes, transitions as arrows — one-to-one with your PLC logic.
Flowchart with decision diamonds and global overrides, conforming to IEC 61131-3.
Automatic score with checks for unreachable states, dead-ends and un-stopped timers.
Word, PDF, SVG, PNG, JSON and a full report.
Zoom, pan and fit the diagram, with a lock against accidental scrolling.
Full light/dark mode and switch between English and Dutch.
Share your diagram however your team works.
We do not use a database for your code. All uploaded Structured Text is processed entirely in the server's volatile memory (RAM) solely for the analysis and diagram rendering. Your industrial code is immediately and permanently destroyed the moment your session ends. Your intellectual property remains 100% yours.
What teams ask before they try it.
Leave your e-mail and we'll let you know the moment ST State Diagrammer goes public — plus the big milestones. No spam, unsubscribe anytime.
Thanks! We've received your request. We'll set up your account and e-mail you the details. Please check your inbox for a confirmation.