PLC Programming Best Practices

Writing reliable, maintainable PLC code is critical for industrial automation systems that must operate 24/7 in harsh environments. This guide covers established best practices for PLC programming using the IEC 61131-3 standard, with practical examples applicable to platforms from Siemens, Rockwell, Schneider Electric, and CODESYS-based controllers.

IEC 61131-3 Programming Languages

The IEC 61131-3 standard defines five programming languages for industrial controllers. Choosing the right language for each task is the first step toward clean, maintainable code:

  • Ladder Logic (LD) — Best for discrete logic, interlocks, and sequences that mirror relay circuits. Widely understood by electricians and maintenance staff.
  • Function Block Diagram (FBD) — Ideal for continuous process control, PID loops, and signal processing. Visual representation of data flow between blocks.
  • Structured Text (ST) — A Pascal-like text language best suited for complex algorithms, data manipulation, calculations, and state machines.
  • Instruction List (IL) — Assembly-like language, now deprecated in IEC 61131-3 Ed. 4. Avoid for new projects.
  • Sequential Function Chart (SFC) — Excellent for batch sequences, step-based processes, and recipe management. Provides clear visualization of process phases.

Code Organization

Well-organized PLC code follows a modular architecture that separates concerns and enables independent testing:

  1. Organize by Function — Group related logic into Program Organization Units (POUs): one POU per motor, valve, or control loop.
  2. Use a Main Task Dispatcher — The main program should only call subroutines, never contain control logic directly.
  3. Separate Safety from Standard — Safety-related logic must reside in dedicated safety programs with clear boundaries.
  4. Layer Your Architecture — Field I/O to Signal Conditioning to Control Logic to Supervisory Setpoints to HMI Interface.

Naming Conventions

Consistent naming makes code self-documenting and searchable. Follow these conventions:

ElementConventionExample
VariablesPrefix + Area + Equipment + SuffixxP100_Motor01_Run
Prefix: BOOLx (input), y (output), b (internal)xSensor01, yValve01
Prefix: Analogi (input), q (output), r (real/internal)iTT101_PV, rSetpoint
ProgramsP_ + Area + FunctionP_Area01_Motors
Function BlocksFB_ + Equipment TypeFB_MotorControl
Constantsc_ + descriptive namec_MAX_SPEED

Error Handling Strategies

Robust PLC programs must handle faults gracefully. Implement these patterns:

  • Watchdog Timers — Monitor communication timeouts with field devices. If no response within the configured window, set a fault flag and revert to a safe state.
  • Range Checking — Validate all analog inputs against instrument range limits. Per NAMUR NE43, values below 3.6 mA or above 21.0 mA on a 4–20 mA signal indicate wiring faults or sensor failures. Values in the 3.6–3.8 mA and 20.5–21.0 mA ranges indicate cautionary zones requiring attention.
  • Interlock Prioritization — Safety interlocks must override operator commands. Implement as normally-closed (fail-safe) where possible.
  • State Machine Recovery — Every state machine must include an explicit ERROR state with diagnostic information and a defined recovery path.

Structured Text Example: Motor Control

The following Structured Text example demonstrates a reusable motor control function block with fault handling:

FUNCTION_BLOCK FB_MotorControl
VAR_INPUT
    xStart       : BOOL;       // Start command from HMI
    xStop        : BOOL;       // Stop command from HMI
    xFeedback    : BOOL;       // Running feedback from field
    xFaultReset  : BOOL;       // Fault reset command
    tStartDelay  : TIME := T#5S;  // Max time to wait for feedback
END_VAR
VAR_OUTPUT
    yRun         : BOOL;       // Output to motor starter
    xRunning     : BOOL;       // Confirmed running status
    xFault       : BOOL;       // Fault flag
    sFaultMsg    : STRING;     // Fault description
END_VAR
VAR
    xStartPrev   : BOOL;
    tonStart     : TON;
END_VAR

// Detect start command rising edge
xRisingEdge := xStart AND NOT xStartPrev;
xStartPrev := xStart;

// Start delay timer (watchdog)
tonStart(IN := xStartPrev AND NOT xFeedback, PT := tStartDelay);

// Motor output logic
IF xFault THEN
    yRun := FALSE;
ELSIF xStop THEN
    yRun := FALSE;
ELSIF xStartPrev THEN
    yRun := TRUE;
END_IF;

// Fault detection
IF tonStart.Q THEN
    xFault := TRUE;
    sFaultMsg := "Motor failed to start within timeout";
END_IF;

// Fault reset
IF xFaultReset AND xFault THEN
    tonStart(IN := FALSE);  // Reset the watchdog timer
    xFault := FALSE;
    sFaultMsg := "";
END_IF;

// Status output
xRunning := yRun AND xFeedback;

Testing and Debugging

Testing PLC code requires a different approach than software testing:

  1. Simulate First — Use the PLC vendor simulation environment to test logic before connecting to real hardware.
  2. Force I/O Carefully — Document all forced signals and remove them before commissioning. Use a force-register log.
  3. Test Fault Paths — Deliberately trigger each fault condition to verify alarm messages, safe-state behavior, and recovery procedures.
  4. Use Trend Recording — Record critical variables during testing to analyze timing, ramp rates, and loop performance.
  5. Peer Review — Have another engineer review control logic before deployment. ASP OTOMASYON enforces peer review on all safety-related code.

Commissioning Checklist

StepTaskStatus
1Verify all I/O point-to-point wiringPending
2Confirm signal conditioning and scalingPending
3Test all interlocks and safety functionsPending
4Validate alarm messages and prioritiesPending
5Tune PID loops (start with conservative gains)Pending
6Remove all forced I/O signalsPending
7Backup final program and document versionPending
8Train operators on new functionalityPending

Clean PLC code is not just about making it work — it is about making it maintainable for the next engineer who will modify it at 3 AM during a production outage.


References & Further Reading

  1. IEC 61131-3: Programmable Controllers — Programming Languages — International standard defining Ladder Diagram, Structured Text, Function Block Diagram, Sequential Function Chart, and Instruction List for PLC programming.
  2. Siemens TIA Portal Documentation — Official Siemens engineering framework for S7-1200/S7-1500 PLC programming with IEC 61131-3 language support.
  3. Rockwell Automation Studio 5000 Logix Designer — Official Rockwell Software for ControlLogix/CompactLogix PLC programming, configuration, and diagnostics.
  4. CODESYS Development System — Official IEC 61131-3 integrated development environment used by ABB AC500, Schneider Electric, and WAGO controllers.
  5. Schneider Electric EcoStruxure — PLC and SCADA Platform — Official documentation for Schneider Electric's PLC programming environment and industrial software ecosystem.