Tag Archives: PLC Programming Patterns

PLC Program State Diagram : CASE Structures in Structured Text

There are several ways to implement a PLC program state diagram. One of the best ways is using a CASE structure in Structured Text. This statement is specifically true for PLC programs that need to handle a state -to-multi-state system. The benefit of good state-based organization makes troubleshooting easier. It also helps with readability and maintainability of a program.

IEC61131-3 helps with organizing PLC programs

The IEC61131-3 software model helps the organization and sequencing. It defines the  ability to ‘divide and conquer’ a larger system down to individual program units ( program organization units or POU’s in 61131-3 lingo). Also, the ability to have multiple tasks helps organize the sequence of the execution of program units. The standard also specifies Sequential Function Chart as the environment to organize a PLC program.

Having said that, if you are to build a sequence with a point -to-multipoint state diagram, a CASE structure in Structured Text is probably the most effective way to do it. We shall examine this in a little more depth.

Why CASE structure in ST?

  1. When one state executes, all other states do not. This is unlike the ladder diagram environment where a rung is within the execution path even if the logic within it is not currently active.
  2. Any state can be transitioned to any other state and vice versa.


PLC program sequence with multiple states
Some systems require for one state to be able to transition to multiple other options for states.

Example: While running, a machine has to operate several different sequences:

  • one sequence for when there is a power loss condition
  • a different sequence when a jam is detected
  • another sequence when an analog input goes below a threshold

This does not mean that the entire program has to be in Structured Text

One  of the benefits of the 61131-3 standard is that each program organization unit can be written in a different language. The I/O interface can be written in ladder diagram. This helps maintenance folks provide the first line of troubleshooting by checking I/O statuses.The main program operation can be written with the step/state based Sequential Function Chart. The RUN operation with all the logic

There is much confusion on the internet and probably in perception among PLC programmers about which language is best for a step/state based program. Ladder diagrams have been around for a long time which has led to much bias towards it. Also, it is relatively easy for maintenance personnel to work with it. However, all facts considered, it is not the best for organizing a state based system. The preference for ladder ( besides the above points) is also strongly tied to the way one of the major PLC programming platform is/was structured.

Moving forward,  a mixed  programming language approach is best. It helps speed up troubleshooting and development of PLC programs. It also will cover better analytics and data handling in PLC’s with the usage of arrays.


What would a CASE structure for a Multi-State PLC Program Look Like?

The frame of one might look like follows:

Frame of a State Diagram with a CASE Structure in ST
Frame of a State Diagram with a CASE Structure in ST

There are going to be programmers who use SFC for state diagrams. Then there is a part of the community who  ( for various reasons) will be using ladder logic. If there is a point to be made for any of these selections, submit your thoughts in the comments section below.



CODESYS Tip:Updating variable sets quickly

Some of the guys at the office just got back from a SoMachine Motion CODESYS session in Germany. One of them noted a CODESYS tip/trick to change the variable name prefixes or suffixes that will save programmers a lot of time and tedious work.

Holding down the Alt key allows for a vertical highlighting feature. 

CODESYS Tip: Highlighting multiple variables vertically
Highlighting multiple variables vertically

From the example above:

Changing the word ‘Read’ to ‘Write’ can be done in one quick update for the entire list:

CODESYS Tip: Type out replacement for highlighted variable
Type out replacement for highlighted variable

This is useful for common parts of a variable name, like above. Other examples may include:

  • Change user defined data type names on a set of assignments.
  • Adding a prefix to a mirror set of variables- e.g. SCA to variables shared with a SCADA system.

Look out for:

‘Copy and paste’ ( Ctrl-C, Ctrl-V) is a large source of PLC program bugs and errors. Several articles on programming cover the ‘copy and paste’ issues in depth. A cool feature like this Alt-key highlighting might feed the problem.

As such, practice caution. Saving a few minutes in tedious work is good as long as it doesn’t cause hours of troubleshooting later. Follow through with a visual check to pick up errors. Copy and paste does not negate the need for System 2 thinking which is the conscious and logical thinking instead of the subconscious and automatic thinking.

Having said that, this is one CODESYS trick I wished I had learnt a few years ago. Thank you, Jared.





PLC Programming Patterns- The Debounced Threshold/Limit

Patterns in PLC Programming: The threshold + timer function – Debounced Threshold

PLC programs are frequently made up of the same sets of functions or patterns of logic. These patterns perform commonly required control routines. Examples include threshold detection for alarm purposes, input/output mapping and scaling functions, to name a few. These combination of functions make up re-usable patterns or function sets that form the building blocks of a PLC program.

Repeated usage of some functions in a PLC programming environment holds true to the universal 80/20 rule ;20% of the functions available in a programming environment( such as timers and logic functions) would probably be used to build 80% of PLC programs.

The debounced alarm/threshold pattern is one of these commonly required PLC programming patterns. This pattern is probably better written in ladder diagram   (instead of any of the other 61131-3 languages), for two reasons:

  • Maintenance personnel will be able to view the status of the process/monitored variable, associated timer and output all in the same place
  • It can be programmed in 2 rungs of ladder compared to more than 10 lines of code.

The ladder diagram version could look something like this:


Note: An Auto/Manual Reset Provision is built into the Alarm Reset Timer rung.



The following pattern is the debounce pattern for detecting limit breaches along with a timer, written in Structured Text for the CODESYS environment. As described above, the structured text version takes more space and possibly looks more intimidating specifically to someone who is used to the ladder environment.


The plain text version of the structured text version is attached below:

PROGRAM DeBounced_Limit


irProcessValue : REAL; (*Process value scaled from analog input signal*)

rProcessLowLimit : REAL; (*User defined process value low limit alarm threshold*)

qxLowLimitAlarm : BOOL;(*Low limit alarm bit*)

LowLimitAlarmTimer : TON; (*Process value low limit alarm trigger debounce timer*)

LowLimitAlarmResetTimer : TON; (*Process value low limit alarm reset debounce timer*)

LowLimitDebounceT : TIME; (*Process value low limit alarm trigger debounce time*)

LowLimitResetDebounceT : TIME; (*Process value low limit alarm reset debounce time*)

xAutoReset : BOOL;(*User enabled alarm auto reset function*)

ixUserReset : BOOL;(*User triggered alarm reset function for manual reset*)


(*If value is lower than low limit, start timer, else reset timer*)

IF irProcessValue < rProcessLowLimit THEN

LowLimitAlarmTimer(in:=TRUE, PT:=LowLimitDebounceT);




(*If timer lapses, trigger alarm bit*)

IF LowLimitAlarmTimer.Q THEN



(*If value is higher than low limit, start alarm reset timer, else reset debounce timer*)

IF irProcessValue > rProcessLowLimit THEN

LowLimitAlarmResetTimer(in:=TRUE, PT:=LowLimitResetDebounceT);




(*If timer lapses, and system permits auto-reset, reset alarm bit*)

(*If the system does not permit auto-reset, add user invoked reset bit here*)

IF LowLimitAlarmResetTimer.Q AND (xAutoReset OR ixUserReset) THEN