Learn PLCs free

PLC Code Organization Best Practices

How you organise PLC code matters more than which language you use. A well-organised project takes weeks to commission and minutes to debug; a poorly-organised one becomes a brownfield horror story years later. This guide covers the patterns that distinguish maintainable PLC code from spaghetti — routine structure, naming, function block reuse, code review, and version control.

Routine structure: one routine per equipment

The single most important organisational principle: one routine per equipment item.

  • Pump P-101 has its own routine that handles its start/stop, alarms, runtime totaliser, and faults.
  • Conveyor C-201 has its own routine.
  • Mixer M-301 has its own routine.
  • The main routine calls these in order, passing only mode/recipe state.

Why: changes to pump P-101 don't touch the conveyor code. Bugs can be isolated. Code review focuses on the changed routine. New engineers can understand one routine at a time.

Reuse via AOIs / Function Blocks

If you have 20 pumps with identical control behaviour, you don't copy/paste 20 pump routines. You write one reusable Function Block (Add-On Instruction in Allen-Bradley terminology) and call it 20 times with different parameters.

(* Studio 5000 ST — single AOI handles every pump in the plant *)
PumpControl_AOI(
    Tag := P101,
    Run_Cmd := Recipe.P101_Run,
    Aux_FB := P101_AUX_FB,
    OL_Trip := P101_OL,
    Status => P101_Stat
);
PumpControl_AOI(
    Tag := P102,
    Run_Cmd := Recipe.P102_Run,
    Aux_FB := P102_AUX_FB,
    OL_Trip := P102_OL,
    Status => P102_Stat
);

Benefits: bug fixes propagate to every pump automatically; the AOI/FB is the documented behaviour; new pumps need one line of code instead of a routine.

Build a library: standard FBs for pump, motor with VFD, valve, motor with soft starter, conveyor, two-position cylinder, three-position selector, etc. Reuse across projects.

Descriptive naming conventions

Tag names are documentation. Adopt one convention and enforce it.

Names should convey intent and direction

  • E_Stop_OK — TRUE means E-stop NOT pressed (system OK to run)
  • E_Stop — does TRUE mean pressed or not pressed? Ambiguous.
  • Conveyor1_RunCmd — clearly an output command, not a status
  • M01.0 — meaningless without a separate decoder spreadsheet
  • Tank1_Level_Pct — what it is, where, in what units
  • DB1.DBW10 — same data, zero documentation

Standard suffixes

  • _Cmd — output command (Pump1_Cmd)
  • _FB — feedback (Pump1_FB)
  • _Status — status word
  • _OK — boolean, TRUE = healthy
  • _Fault — boolean, TRUE = fault active
  • _Pct, _DegC, _Bar, _RPM — engineering units
  • _SP — setpoint
  • _PV — process variable

Comments at three levels

  1. Routine header — what this routine controls, what it depends on, who modified it last and why.
  2. Rung comment — why this rung exists, especially for interlocks. Reference the HAZOP item or FDS section that mandated it.
  3. Tag description — what the tag means in plant terms, including units. Visible in monitor view, HMI binding, and historian.
(* Routine: PumpControl_P101
   Equipment: Tank-1 Outlet Pump
   Last modified: 2026-04-15 by JM (MOC #2026-019)
   Reason for change: added run-on cooling per HAZOP item 4.7
   Calls: PumpControl_AOI v2.3 *)

(* Rung 8 — anti-deadhead interlock
   Per HAZOP item 4.2: pump must not run if outlet valve closed
   for more than 30 sec (overheat risk).
   FDS section: 7.3.2 *)
──┤ P101.Run ├──┤ MV-101.Open ├──┤/T_Deadhead.Q ├──( P101_Permissive )──

Version control for PLC code

  • Export to text — Studio 5000 L5X export, TIA Portal SCL/AWL export, CODESYS export. These are diff-friendly text files.
  • Git repository — one repo per project. Branch per change. Pull requests reviewed by another engineer.
  • Commit messages — link to MOC ticket, describe the change, list affected equipment.
  • Tag releases — every commissioned version gets a Git tag with the date and version number visible on the HMI.
  • Backup the binary — even with text export, keep the original .ACD / .AP19 / .project file in version control or in a parallel artefact store.

Code review checklist

Before committing or downloading a code change, work through this:

  • Does the change have a corresponding MOC ticket?
  • Does it touch only the equipment / routine the ticket scoped?
  • Are tag names descriptive and consistent with project convention?
  • Are rung comments updated where logic changed?
  • Is the routine header updated with the change date and reason?
  • Are no magic numbers introduced? (everything in named tags)
  • Are all field signals quality-checked?
  • Are interlocks tested in simulation before deployment?
  • Is the cause-and-effect matrix updated if interlock logic changed?
  • Is a peer engineer signed off?

Frequently asked questions

How should I organise a PLC project?
One routine per equipment item — pump, conveyor, mixer each get their own routine. Use AOIs (Allen-Bradley) or Function Blocks (Siemens, CODESYS) for reusable patterns. Build a library of standard FBs (pump, motor, valve, conveyor) and reuse across projects. Main routine calls equipment routines in order, passing only mode and recipe state.
What naming convention should I use for PLC tags?
Names should convey intent and direction. Use descriptive prefixes/suffixes: equipment (Pump1_, Conv2_, Tank3_), function (_Cmd for output command, _FB for feedback, _Status for status word, _OK for boolean health, _SP for setpoint, _PV for process variable, _Pct/_DegC/_Bar for engineering units). Avoid ambiguous names like E_Stop where direction is unclear; use E_Stop_OK to convey TRUE = healthy state.
Should PLC code be in version control?
Yes — every PLC project should be in Git. Export to text format (Studio 5000 L5X, TIA Portal SCL, CODESYS export) for diffability. Commit per logical change, branch per feature, peer-review every pull request, tag every commissioned version. Keep the binary file (.ACD, .AP19) in parallel storage.
How do I review PLC code?
Use a checklist: change traces to an MOC ticket, scope is limited to the targeted equipment, tag names follow conventions, rung comments are updated, no new magic numbers, field signals quality-checked, interlocks tested in simulation, cause-and-effect matrix updated if interlock logic changed, peer engineer signed off. Commercial code review tools (Versiondog, Octoplant) help automate this.
What is an AOI in Studio 5000?
AOI stands for Add-On Instruction — Allen-Bradley's name for a reusable function block. You define an AOI once with input parameters, output parameters, and internal logic, then instantiate it as many times as needed throughout the program. Equivalent to Siemens Function Blocks (FBs) and IEC 61131-3 function blocks. Critical for code reuse and library-based development.

Related guides

Free PLC simulator

Stop reading, start doing

Write ladder logic in your browser, hit Run, and watch real machine scenarios react. 12 guided lessons across 8 PLC dialects — free account, no credit card.

Practice PLCs free →