Download as pdf or txt
Download as pdf or txt
You are on page 1of 32

Programming in List on a Mitsubishi PLC

- by antony - 2009/10/19

This is a tutorial written for 2 sets of people. First its intended for those just starting out who
have at least learned how to use the basics of their editing software in order to enter a simple
program. They should already understand the basic concepts such as x0 is an input, y0 is an
output. It’s also intended for advanced users of Ladder who are curious about List. Hopefully
it’s not too difficult for the former or too simplistic for the latter. I'm not an experienced tutorial
writer, so apologies in advance! ;)

You're bound to have a better grasp of PLC coding and the best ways to approach problems if
you understand how the PLC reads and executes your code.

RELAYS VS THE PLC


First of all, despite the fact that the PLC was designed as a direct replacement for relays, its
logic is actually quite different. Relays are 100% parallel logic. Every single part of a relay
control system operates simultaneously. If you were to draw several rungs on a relay diagram
and put one coil on each line with no contacts on any of the lines, every relay would energize at
the same time when power was applied. If you add contacts to each line and the contacts on a
line change at some time, the coil on that line is instantly affected. This makes relay logic
blindingly fast by nature (its only the relay's mechanical limitations that make it slow) but it’s
often a source of trouble. There can be a race effect where different logic states occur if this
relay closes faster than that relay this time but not the next time. On the other hand, the PLC is
sequential in operation. One thing happens at a time. In happens in the order you dictate and its
the same order every time. In fact, the entire PLC program doesn't exist as far as the PLC itself
is concerned. Only the single piece of code that it happens to be examining at any one time
matters.

Here's how it works:


First the PLC's operating system examines the state of all of the external wiring inputs. It
records this data to an area of memory called the "input image". This image or record of the
inputs is what will be used for input reference while executing your code. The real inputs are
not used. The PLC then looks at your code starting at the beginning and progresses through it.
The PLC only keeps track of a single logic result as it’s reading your code. This result will be
equal to 1 (true) or 0 (false). There are complications to this such as when the operating system
must read ahead during complex logic or when certain things require stacked results but its true
for the most part. As it reads your code, it will update any changes to the outputs by writing to
an area of memory called the "output image" rather than the actual outputs themselves. When it
reaches the end of your code, it then turns the real outputs on or off by copying the output
image memory to the actual output registers. This start to finish cycle is called a "scan" and
repeats endlessly over and over. In summary, the inputs are read once as a group, then your
code is executed and then the outputs are updated as a group. Without this cycle method, inputs
changing midway during your program could cause strange results and you couldn't change
your mind about outputs before finally turning them on or off for real. With the scan method,
we have an almost imaginary world inside the program where we can do what we want with no
interference or consequences. It’s only at the end of each scan that we have to worry about
reality.

-1-
BOOLEAN LOGIC
This is at the heart of the PLC's operation. You need to know this.
There are other ways of looking at PLC logic that perhaps are more intuitive than the pure
Boolean method but you still must understand it and have it in your arsenal of tools if you are
going to have more than a basic ability with PLC's. Unfortunately, this is a scary subject to the
uninitiated but stand fast! It’s really not that hard to grasp. Just remember, it’s the basis of all
things digital. Even good old relays are digital devices that lend themselves well to Boolean
logic.

Boolean logic uses 2 states to represent things. Something can be on (equal to 1) or it can be off
(equal to 0).
We perform what are known as "logical" operations in Boolean. Things like "logical AND" and
"logical OR" (I'll use uppercase to denote a logical operation).

logical AND means "if both things equal 1 then the answer is 1"
or in other words:
0 AND 0 = 0
0 AND 1 = 0
1 AND 0 = 0
1 AND 1 = 1

Logical OR means "if either thing equals 1 then the answer is 1"
or in other words:
0 OR 0 = 0
0 OR 1 = 1
1 OR 0 = 1
1 OR 1 = 1

Logical NOT (also called "invert") means "invert the item, make it the opposite, the current
value is NOT what I want"
or in other words:
NOT 0 = 1
NOT 1 = 0
You perform a logical NOT on something when you know you want the opposite result.

So now if we said given that X=1 and Y=1, you'd know that X AND Y = 1 and also that X OR
Y=1
or given that X=0 and Y=1, you'd know that X AND Y = 0 but X OR Y = 1.
Or, to get tricky, given that X=0 and Y=1, you'd know that NOT X AND Y = 1 but X OR NOT
Y=0
You should read and re-read this until you understand it. It’s important.

When something is equal to 1 we say that the result is "true". When something is equal to 0 we
say that the result is "false".

In proper Boolean, there is a defined order for performing operations just like in math where
multiplication is performed before addition. In Boolean, AND operations are performed before
any OR operations. In fact, the short form method of writing Boolean uses the times symbols
"x" or "*" to represent AND while the plus sign "+" is used for OR. (eg. 1+0=1 is the same as
writing 1 OR 0 =1). The "times" symbol expresses the fact that AND has precedence over OR.

-2-
You don't have to worry about this in the PLC. It simply performs the operations in the order
they are presented. Just be aware that it’s a deviation from what goes on outside of the PLC
arena.

PROGRAMMING
To program the PLC we have several options in the way of languages. The two common ones
are Ladder and Instruction List. There are many tutorials that discuss Ladder so we'll stick with
the one most near and dear to my heart: "Instruction List". List is a "mnemonic" or text-based
language. It’s exactly like the Assembler languages used to program microprocessors in their
native language. A native language is one that the processor directly understands. You type a
"mnemonic" which is simply an abbreviation consisting of a few letters to represent a
command, and the editing software on the PC sends the corresponding code number to the
PLC. There are no interpretations or changes made other than the fact that you type in letters
and symbols and the PLC reads numbers. When working with a PLC, you are not really
programming the processor. There is a high-level operating system on-board that is
programmed to “be” a PLC but the net affect to you as a programmer is identical to working
directly with a processor. In other words, you are about to become an Assembler programmer!
Pretty exciting, right? ;)

Mitsubishi uses mostly obvious mnemonics such as LD to mean "load the accumulator", AND
to mean "AND", OR to mean "OR" and OUT to mean "send the result to the output image".
These and the following may seem like gibberish to you at first but plough through it. There is
a bit of a learning curve and then the sun breaks through the clouds!

LDI (Load Inverted; more commonly thought of as Load Not) means "perform a NOT
operation on the following value, then load the accumulator with the result".
AND means "perform an AND operation".
ANI (And Not) means "perform a NOT operation on the following value, then do an AND"
eg. given that X1=1 and Y1=0, X1 ANI Y1 =1 because although Y1 contains a zero, it is
first inverted to a 1. The AND operation is performed as 1 AND 1 which = 1.
ORI (Or Not) means "perform a NOT operation on the following value, then do an OR
eg. given that X1=0 and Y1=0, X1 ORI Y1 =1 because although both contain zeros, Y1 has
first been inverted to a 1. The OR operation is performed as 0 OR 1 which = 1.

WHAT THE PLC SEES


People generally think of the PLC as being more complex in its method of reading lines than it
really is. They picture it reading an entire Ladder rung like they would and then making a
decision at the end as to whether or not to turn on the output. It actually never makes a decision
when performing basic logic such as AND, ANI, OR, ORI. It just keeps track of the current
state of affairs in a reserved memory location known as the Accumulator or just "A" for short.
This is an old, tried and true processor method that the PLC's operating system emulates.

Example:

If we were to write some standard English control logic as such:

if x1 is on and x2 is on or y1 is on and y2 is off then turn on y10 else turn y10 off.

-3-
and then rewrote the same thing for the PLC it would look like the code below. The comments
show how the PLC executes it.

LD x1 ;the PLC "loads" the Accumulator (A) with the value of x1 (ie. the value of x1 is
moved into A).
AND x2 ;the PLC performs A AND x2. The result is placed in A.
OR y1 ;the PLC performs A OR y1. The result is placed in A.
ANI y2 ;the PLC performs A AND NOT y2. Result is placed in A.
OUT y10 ;the PLC "outputs" the value of A into the output image memory location
reserved for y10.

As you can see, no decisions were made. The PLC didn't even turn the output on or off. It just
moved the result to the output image when it was told to! Later, at the end of the scan, the
entire output image will be copied to the real output registers. If there ends up being a 1 in a
register, the associated output will magically turn on. If it contains a zero, it will turn off. The
turning on, turning off part is done by the hardware. The operating system has nothing to do
with it.
The PLC doesn't even perform the operations in the proper order according to the rules of
Boolean logic. It simply AND's and OR's things as presented.
This is how the PLC with a simple and comparatively slow processor can scream through your
code at such speed. Its efficient and only concerned with simplicity.

When we start a new "series" or collection of statements in List or begin a new rung in Ladder,
what we are really doing is telling the PLC that we want to start over and it should not use any
previous results. In other words, we want it to "Load the accumulator" with the first value
rather than perform an operation with the old value from the previous line. Loading the
accumulator with the new value overwrites whatever was already there.

STARTING SIMPLE
Okay, so now lets back up and start simple:

You want a motor to come on but only if you turn on a selector switch. So you connect a switch
to x0 on the PLC and you connect the motor's contactor coil to y0.
Now what? First we name the inputs and outputs. Never, ever, ever, use the raw I/O names in a
program. Its fine for describing things to your friends in snippets of code about how to do
something... but don't use x0, y0, etc in a real program. It’s hard to read, it’s hard to debug and
it’s hard to change. Okay, so we'll call x0 "switch" and y0 "motor". Right?

Here's how your program will look:

LD SWITCH
OUT MOTOR

That was pretty easy, no? To make it easy to read, instead of thinking "LD", think "IF" and
instead of OUT, think "then" or "turn on".
In your head it becomes:

if switch
then motor

-4-
What if you want the motor to shut off if it gets too hot? Oops, that's right, we have overload
contacts we have to monitor. So lets put them into x1 and call them "overload". Typically, we
want the motor to only turn on if the overload contacts are closed. Same as the switch. So now
we have:

LD SWITCH
AND OVERLOAD
OUT MOTOR

Now someone adds a special sensor on the machine and tells you the motor must turn off if the
sensor turns on.

LD SWITCH
AND OVERLOAD
ANI SENSOR
OUT MOTOR

So now in English, this would read...


If switch (was that supposed to be open or closed?) and we have an overload... no, wait! If we
don't have an overload... and the sensor is not on (not open or not closed?)... hmmm.... this is
getting confusing!!

We've only got 4 lines of code and already its unclear exactly what we are trying to do. Time
for some more RULES!

NAMING CONVENTIONS
Name your inputs and outputs according to what they do when they are "active". That's an
important word. Forget "open" and "closed" for a minute. Think "active" and "inactive". Every
item has a purpose or you wouldn't be connecting it in the first place. You must always name
an item according to its purpose. It will be “active” when its fufilling its intended purpose. The
purpose of the switch we used was to turn on the motor or make it run. We should have called
it something like "RUN". Even better would be to call it "RUN'SEL" (for Run Selector). Notice
I used 2 words separated by an apostrophe. We are only allowed a single word but often two or
three make the purpose clearer. The apostrophe is a good way of cheating your 1 word into
several. The more traditional underscore also works but it’s easy for your eye to miss it and a
tired and worn printer will often drop it. Now you know the following about RUN'SEL:

If the real switch in the field is active then our input called RUN'SEL is active
(x0=on),and its
name tells you what the intended result should be (RUN).

It doesn't matter how that was achieved in the field ie. normally-open or normally-closed
contacts. An input is only active if you have a live electrical signal coming to it.
Now, how about our overload contacts. Their purpose in life is to detect overloads. They
become "active" when an overload occurs. So they can properly be called "Overload" contacts.
Since we have decided to use normally-closed contacts from the overloads, we have a problem.
The signal into the PLC will be OFF (inactive) when the overloads are active. In other words,
the input should be named "NO'OVERLOAD" because when the input is active, the overload
contacts are inactive and there is no overload.

-5-
A better method is to use a slash in front of the name which is read as "NOT". This is just my
personal idea, stolen from Boolean, but it works really well. The slash tells you that the input is
inverted (inactive when the input is on). So "/OVERLOAD” is read as "not overload". The
field device is called "Overload" but the input on the PLC is called /OVERLOAD. When you
see the slash, it tells you the field device is using normally-closed contacts. Otherwise,
everything is from normally-open contacts. Beautiful, no?
Let's see where we are now (the comments show how YOU would read it):

LD RUN'SEL ;”if run’sel”


AND /OVERLOAD ;”and not overload”
OUT MOTOR ;”out motor”

That's better. We need a name for the sensor. Let's say that when its active, it’s telling us that
the machine is busy and the motor must remain off. Let's call it BUSY.

LD RUN'SEL ;”if run’sel


AND /OVERLOAD ;”and not overload”
ANI BUSY ;”and not busy”
OUT MOTOR ;”out motor”

In English: If the run selector switch is on and there is no overload and the machine is not busy
then turn on the motor.

You can see how important the names are when reading List. They are everything. Another
benefit of the "slash" is when you have a line like "LDI /OVERLOAD", you can cancel out the
2 "NOTS" in your head and it makes more sense. Instead of saying "If-not not-overload", its
just "If overload". It means the same thing!

ORDER OF OPERATIONS
I suspect this is the area where most people give up. They don't understand how combinations
of OR and AND are seen by the PLC. And it can soon become very confusing to read.
Complex Boolean is actually more clearly displayed in Ladder format than it is in List. But List
can manage it, and Ladder is not very useful for displaying non-Boolean operations such as
math and the higher functions. So the challenge is to make your List readable when doing
Boolean so that you can take advantage of the rest.

First thing to remember is that the PLC completes each statement as it reads them. It doesn't
read the entire collection of lines at one go. For those familiar with Ladder, its like saying that
the PLC reads one contact and adds it to its sum in the Accumulator, forgets that the contact
exists and goes on to the next contact. It doesn't read the entire rung at once. If it encounters an
AND, its the same as if you have a contact in series with everything that came before. If it
encounters an OR, it’s like a contact in parallel with everything that came before. On a Ladder
diagram, the AND is always in series with the ENTIRE rung. The OR is always in parallel with
the ENTIRE rung (in other words, its a new line that starts back at the left rail). That being the
case, how the heck can we do anything?!

There are a couple of methods for telling the PLC to hang on to a result for later use. Just like
on your calculator where you have the Memory feature. On your calculator you might add
some figures together, place the result into the Memory, do some multiplying with new figures

-6-
and then finally add the result to what you previously put in the Memory. We can do the same
thing on the PLC in several different ways.

Write out a series of statements such as follows:


LD RUN'SEL
AND /OVERLOAD
ANI BUSY

Don't complete the series by using an OUT statement. Now start a new series:

LD HIGH'SEL ;high-speed selector switch

The PLC knows you are not done with the first series because you haven’t "used" the result yet
in an output type of statement. When it encounters the new LD statement, it puts the old result
into a temporary storage area called a stack. It knows you will need it later.

Now carry on:


LD HIGH'SEL ;high-speed selector switch
OR LOW'TEMP ;low temperature sensor
ANB

That last command was "AND BLOCK". It means pull the old value from storage and then
AND it with the current value in the Accumulator. In other words, "I want the old series (the
old block of code) to be true AND I want the new series (new block of code) to be true before
performing any outputs”. You could also have used ORB. It means "If the old series is true OR
if the new series is true then...". Now, you follow with whatever output code you wish. Let's
put it all together:

LD RUN'SEL
AND /OVERLOAD
ANI BUSY

LD HIGH'SEL
OR LOW'TEMP
ANB
OUT MOTOR

In English: If the run selector switch is active and we have no overload and the machine is not
busy... if the high selector switch is active or the low temp sensor is active... if both of those
series of things are true then turn on the motor.

Make sure you use a blank line to separate the two series. It keeps things readable.

When you have seriously twisted logic to express, and even the handy ANB, ORB won't
manage it, there is an all-powerful stand-by at your disposal. Its called MPS for "Memory Point
Store". It’s exactly like the one on your calculator. No different. You should avoid it like the
plague in most cases because it can lead to code that’s difficult to read. There are times,
however, when it’s exactly what the doctor ordered. Usually, it’s better if you repeat sections of
code or store your own result with its own descriptive name rather than using MPS.

-7-
---

We'll be using numbered as opposed to named I/O for the examples. Don’t get used to it and
definitely don't be discouraged by it. Numbers work best for showing you how the code works
but they're terrible at showing you what it's actually doing. Your own code (with proper I/O
names) will be much easier to follow.

Experienced programmers will find the initial stuff a bit on the basic side but please, keep
reading. It gets better. The more advanced topics will rely upon terminology and phrases
introduced in the basic ones so I suggest you don't skip. I can pretty much guarantee you'll find
a knowledge nugget or two somewhere in the following pages (double your money back, void
where prohibited).

Our focus will be on the Mitsubishi FX series but the concepts apply more or less on all plc's.
Before using anything you learn here though, do yourself a favour by checking your manuals
and testing your code. Take anything I say (or anyone else says) with several grains of salt. My
mistakes don't have to be yours too.

The Really Easy Stuff


Okay, let's see how List compares with Ladder while writing some code.
Feel free to try any of the examples in your editing software. Just be aware that if you switch
between List and Ladder views without having an output on each rung (most of the examples
don't), you'll receive an error. All you need to do is add an output to the end of the List code.
AllRighty then...

We'll start at the beginning of a rung (good choice huh?).

First we type: LD X0
X0

No surprises there. As you can see, we have begun a new rung with a normally open contact.
We always have to start with the LD (or LDI) command.

-8-
Now let's add: AND X1

X0

X1
The AND command places a contact in series with all of the preceding logic. So far "all"
consists of that single X0 contact we previously placed.

You can perform AND as many times as you like and every new contact will be placed in
series with all of the preceding logic. That's because when the plc reads a contact, all of the
preceding logic has already been reduced to a single result held in the accumulator (remember?
Part 1?). The plc is simply going to perform a logical AND with the accumulator and your new
contact.

AND X2
AND X3
X1

X2
X0

X3

No mystery there, right?


At this point, the accumulator holds the value of the output of X3.

-9-
Now try: OR X4

X0

X2

X3
X1
X4

Whoa! What the heck happened there? Unlike a logical AND, an OR command will place a
contact in parallel with all of the preceding logic or in other words, in parallel with your entire
rung. We're back to that accumulator thing again. The plc performed a logical OR with the
accumulator and your new contact.

AND X5 ; places a contact in series with all of the preceding logic.


X0

X1

X2

X3

X5
X4

The accumulator now holds the value of the output of X5.

- 10 -
OR X6 ; places a contact in parallel with all of the preceding logic.

X3
X1

X2

X5
X0
X4
X6

We could go on forever. I'm told I do sometimes.

Really Smart PLC Rule #1:


AND, ANI, OR & ORI commands always operate on all of the preceding logic.
ie. They are always in series or parallel with the entire rung up to the current point in the logic.

So Far So Good
If you've followed along patiently to this point, you will probably agree that so far it's
embarrassingly simple. After all, you're pretty smart. I guess it's time to tackle the things that
are not so obvious. First off, one of the most common things you'll encounter is the need to
place a few contacts in series with each other followed by some contacts that are in parallel
with each other but still in series with the first ones.

Like this:
X2
X0

X1

X3

X4
X5
X6

X0 to X3 are in series. X4 to X6 are in parallel with each other and, as a group, are also in
series with X0 to X3.

You simply can't do this in List using nothing but your basic AND and OR. In Part 1, we talked
about using the ORB ("Or Block") and ANB ("And Block") commands. We'd have to use them
here.

- 11 -
Something like:

LD X0
AND X1
AND X2
AND X3

LD X4
OR X5
OR X6
ANB

Note: Do a quick review of Part 1 if you don't understand the use of ANB... or what the heck,
just read a bit further.

This is where people start to complain. Such a simple construct in Ladder yet in List we are
already having to resort to using 2 separate blocks of code joined by ANB…. (the complaints
are occasionally followed by rioting in the streets, looting, setting of fires, etc).

Since this is in fact a common logic sequence, it's worth letting you in on a little secret.
Although you have probably drawn exactly such a diagram in Ladder and would be just as
likely to build it that way using relays, as far as the plc is concerned, you've been doing it
backwards all along. Huh? Yup. Try putting the OR'd contacts first and see what happens.

Like this:
X4

X0

X2
X1

X3
X5
X6

- 12 -
Now write that in List and you get:

LD X4
OR X5
OR X6
AND X1
AND X2
AND X3

See? No ANB. You just made it a lot more readable. You also made it shorter. It now requires
less memory to store the program and you made it execute faster. Even more important, you
learned one of the reasons why List might be a good idea. Using Ladder, you tend to think like
a human (and that can't be good). If you are using List, you see what the plc sees and you have
a better opportunity to write code that is efficient. Before anyone gets upset with me, I will
quickly add that the efficiency of code is usually not that critical compared to readability,
maintainability and other factors. On the other hand, it's never a bad thing. There are times
when efficiency is very important.

Everyone tends to make this AND before OR mistake. The good old 3-wire start/stop circuit
taught in every electrical class is probably to blame. A good controls electrician has this seared
into his brain. The series-wired stop buttons always came first followed by the parallel-wired
start buttons & holding contacts. But now we are inside the plc.

In a plc, we need to take advantage of Rule #1 rather than being ruled by it. The following new
rule helps us do just that.

Really Smart PLC Rule #2:


If a string of logic contains a set of series contacts and a set of parallel contacts:
add the series set last if you want the two sets to be in series;
add the parallel set last if you want the two sets to be in parallel.
Note: This is really just an expansion of rule #1.

- 13 -
In the previous example, we avoided the ANB by putting the series set last. We had a set of
series contacts and a set of parallel contacts and we wanted them in series with each other.
Exactly what Rule #2 said to do. If we had wanted them in parallel we would have reversed it
like this:

LD X0
AND X1
AND X2
X1

X3
X2
X0

AND X3
OR X4
OR X5
X4

OR X6
X5
X6

ANB/ORB
Sooner or later we will have to resort to ANB/ORB. So let's do some practice with those. We'll
minimize their use by keeping our Really Smart PLC Rule #2 in mind.

First of all, remember that using LD will always begin a new "block" of code (what we called a
"series" of statements in Part 1; "block" is the official, tech term). In effect, using the LD
command in the middle of a rung suspends the logic you are working on and temporarily
begins a new rung at the left rail. You end up with two blocks; the old unfinished one and a
new temporary one. The reason we want to do this is so that when something applies to "all of
the preceding logic" it will only be referring to what's in this new block. For now, the old block
will be ignored. When you are ready, the new one can be connected to the old by using ANB or
ORB.

Pictures! We need pictures!

LD X0 ;start block #1
OR X1

produces this:

Block
X0

#1
X1

- 14 -
Now let's add another LD statement (to get a new block) followed by OR.
Altogether we have:

LD X0 ;start block #1.


OR X1

LD X2 ;start block #2.


OR X3
X0

Block
#1
X1
X2

Block
#2
X3

Note that both blocks were left "open" (ie. there are no OUT or other output type commands
that would produce a connection to the right hand rail).

If we add an ANB at the end of our code, the two blocks will be placed in series like this:
X0

X2

ANB
X1

X3

- 15 -
If we instead use an ORB, we'll parallel them like this:

X0
X1

ORB
X2
X3

Using ORB in this example was rather pointless. We could have just OR'd all the
contacts together in the first place and avoided the use of ORB.

Here's a better example showing the use of ORB:

LD X0 ;start block #1.


AND X1

LD X2 ;start block #2.


AND X3
X0

X1
X2

X3

- 16 -
Now add ORB and you'll get:

X0

X1
ORB
X2

X3

Common sense might have told you the last drawing could be coded as…

LD X0
AND X1
OR X2
AND X3

when in fact, that would have produced this:


X0

X3
X1
X2

Just remember that common sense will also insist that the world is flat.
So if you're not exactly giving Ptolemy a run for his money, this would be a good time to go
back and review (starting with Part 1). Assuming you are happy with the concept of a spherical
planet, let's ride forth…

When do you need ANB/ORB?

Really Smart PLC Rule #3:


Use ANB/ORB when you need to apply logic that only operates on some of the preceding logic.

Identify the logic section of interest and then separate it out by surrounding it with LD &
ANB/ORB.
If you need to do an AND but only want the contact to be in series with some of the preceding
logic, you need an ORB.
If you need to do an OR but only want the contact to be in parallel with some of the preceding
logic, you need an ANB.

Example of AND needing an ORB:

- 17 -
X0

X1
ORB
X2

X3
We only want X3 to be in series with some of the preceding logic
(ie. in series with X2, but not X0 or X1).

Here it is in List:

LD X0
AND X1

LD X2 ;marks the start of the "some" stuff.


AND X3 ;this AND tells us we need an ORB.
ORB ;places the X2-X3 block in parallel with the X0-X1 block.

Example of OR needing an ANB:


X2
X0

X3

ANB
X1

X4

We only want X4 to be in parallel with some of the preceding logic


(ie. in parallel with X3, but nothing else).

Here it is in List:

LD X0
OR X1

LD X3 ;marks the start of the "some" stuff.


OR X4 ;this OR tells us we need an ANB.
ANB ;places the X3-X4 block in series with the X0-X1 block.

AND X2

Notice I didn't include the 'AND X2' until after the ANB. I left it until the end as a separate
operation. I didn't have to really but Rule #2 says I should. In more complex code, it'll help
keep things clearer if you develop this habit. Keep the contents of blocks you'll be joining as
short and simple as possible.

- 18 -
Okay, our next example is going to get nasty. I can almost guarantee your response will soon
be "Holy Cow! This just isn't worth it" (actually, you may have been thinking that for a while
now). I'll be the first to admit that learning to write clear, readable code is easier if "Ladder
only". So why bother with all of this? Well, once you get used to it, you'll find that List has the
following strengths:
1) It's quicker to type than it is to draw (and in Ladder you still have to fill in names and
constants anyway).
2) Comments, names and constants are clearer and more readable.
3) You can see more of your program at one time on the screen and have more control
over the layout.
4) Printouts are more compact and can be edited in any word processor quite easily.
5) More efficient code. Faster execution. Less memory required .
6) Complex functions are more readable.
7) Women will find you more attractive.
None of these will make much of an impression (well, maybe the last one), until you start to
use a lot of advanced functions. Let me give you an example. I recently wrote a program to
control a rolling tube bender. There was nothing extraordinary about it yet there were sections
that contained over fifty math functions in a row. In Ladder, these appeared as endless
horizontal lines, each one ending way over on the right-hand side of the screen in a box full of
misarranged numbers. In List, it was very clear and obvious what was going on. It looked and
read more like proper math. It's also worth pointing out that although the program was over
3000 steps in length, it contained only 15 block joins and a single MPS/MPP pair. That's
because it was written in List. You shouldn't judge List by the mess you sometimes see when
you auto-convert Ladder into it.

Regardless of the type or level of programming you are doing today, chances are you'll be
doing different things tomorrow. Being able to comfortably switch between List and Ladder
will allow you to take advantage of the strengths of each.

Personally, I write everything in List and use Ladder to double-check sections that don't "feel"
right. I get a second perspective from Ladder that can be invaluable. You may end up using the
opposite approach or perhaps you'll write Boolean in Ladder and switch to List for math and
similar functions. Regardless, if you wish to have List available to you, you need an
understanding of its features and rules. Besides, I'll be really ticked if after all the typing I just
did, you decide it would be a great time to try out the delete key on your new keyboard.

So, assuming both you and this document still exist…

Let's try a complex example.


First we'll translate the ladder diagram shown below exactly as it's drawn. We'll even do it in
the order suggested by the contact numbers (X0, X1, X2, etc).

- 19 -
J4
X0

X1

X4

X5

Y0
J3
X2

X3

X6

X7

X10
J1 J2

X11
Here's the List:

LD X0
AND X1

LD X2
AND X3
ORB ; see J1 (joins the X2-X3 block with the X0-X1 block).

LD X4
AND X5

LD X6
AND X7

LD X10
OR X11
ANB ; see J2 (joins X10-X11 block with the X6-X7 block).

ORB ; see J3 (joins the block created by J2 with the X4-X5 block).
ANB ; see J4 (joins the block created by J3 with the one created by J1).
OUT Y0

You'll note that we held off using some of the block commands until the end. We had to in
order to join blocks in the correct order. ANB/ORB always operate on the two most recently
created blocks. You are allowed to have several blocks outstanding before you have to perform
a join. The FX series allows a maximum of eight. Doing it this way, you have to be careful not
to join the wrong blocks together. It's also rather confusing.

By re-arranging things, we could have kept most of the block commands "inline" and made
things a little easier to read (and less error prone). This is a much better technique.

Like this:

LD X0
AND X1

- 20 -
LD X2
AND X3
ORB ; see J1 (joins the X2-X3 block with the X0-X1 block)

LD X6
AND X7

LD X10
OR X11
ANB ; see J2 (joins X10-X11 block with the X6-X7 block).

LD X4
AND X5
ORB ; see J3 (joins the X4-X5 block with the one created by #J2).

ANB ; see J4 (joins the block created by #J1 with the one created by J3).
OUT Y0

We still have an area that could be improved. Have a close look at X6, X7, X10, & X11 on the
drawing. Look familiar? Remember our Really Smart PLC Rule #2? Oh, you already saw that
and were just being polite? I'm impressed. The rule tells us that by placing X6 & X7 after X10
& X11 we can eliminate the J2 block command. Very nice.

Here's the final version (you don't really believe that do you?).

LD X0
AND X1

LD X2
AND X3
ORB ;see J1 (joins the X2-X3 block with the X0-X1 block).

LD X10
OR X11
AND X6
AND X7 ;we no longer need the block join at J2.

LD X4
AND X5
ORB ;see J3 (joins the X4-X5 block with the X10-X7 block).

ANB ;see J4 (joins the block created by J1 with the one created by J3).
OUT Y0

This version will work the same as the other two but they'll each produce different diagrams in
your Ladder editor (go ahead, fire up Medoc, GX or whatever and play).

- 21 -
Notice the blocks joined by ANB both end in ORB and the blocks joined by ORB all end in
AND. This tells us we've done a good job (according to the next rule).

Really Smart PLC Rule #4:


Both blocks being joined by ANB should end in OR, ORI or a block join (ANB/ORB).
Both blocks being joined by ORB should end in AND, ANI or a block join (ANB/ORB).

Notice it says that both of the blocks being joined must qualify. That's a key point. Breaking
Rule #4 doesn't make your code illegal. It just means you haven't written it in the best possible
way. You might be using a block join when it's not needed. You could even be including an
AND that would be better added after the join is completed. The rule is unforgiving. Also note
it doesn't recognize LD as a proper block end so you know at least two contacts are needed in
each block you are attempting to join.

If we had followed this rule in the first place, the last version of our example would have
appeared automatically without requiring the two revisions. Interestingly enough,
Rule #4 even insists that you obey rule #2. Could be a conspiracy.

There is still the issue of that final ANB in our last version. A bit confusing isn't it?
When quickly scanning the code, you have no idea what that ANB is referring to.

Here's a method that is a lot more readable (never believe that "final" version stuff).

LD X0
AND X1

LD X2
AND X3
ORB ;combine this block with the previous one.
OUT M0 ;assign an internal relay to record the result so far.

LD X4 ;start over fresh.


AND X5

LD X10
OR X11
AND X6
AND X7
ORB ;combine this block with the previous one.

AND M0 ;add in the result from way back.


OUT Y0

In the real world, you'd give M0 a nice, descriptive name so that when you use it, you'll know
exactly what it refers to. You can't give ANB a name at all. It's well worth flipping back to the
page with the first version and comparing. There's a pretty dramatic difference isn't there?
Which one would you rather work with five years from now when you've forgotten what this
machine even looks like?

- 22 -
OUTPUTS
We haven't yet dealt with outputs in Part 2. It's hard to write a program that does anything
without them. It's even harder to use them properly unless you know a few tricks. I'll now take
you to the grand heights of advanced output design. Or not…

There are three types of output connections that one can make.
I call these Simple, Cascaded and Divergent outputs.

So, you're saying to yourself "Oh Gawd. He's making up terms and definitions now. He just
wants this to be complicated" (yeah, I heard you). There is a purpose here. Many people, when
writing in List, don't even realize that cascaded outputs are legal. Also, if you don't know the
difference between cascaded and divergent outputs, you'll often create divergent ones by
mistake. And divergent outputs can lead to horrors such as MPS which should be avoided like
prison time or processed cheese.

Simple Outputs
You have a simple output when you have only one or, if there are several, they are directly
connected together. There are no contacts between any of the outputs. Nothing mysterious
here.

LD X0
X0

OUT Y0
Y0

OUT Y1
OUT Y2
Y1
Y2

Cascaded Outputs
You have cascaded outputs when you have more than one output and each uses all of the logic
of the preceding output and then extends that logic with more of its own.

- 23 -
Note: There are NO contacts at these
points
LD X0
OUT Y0
X0

Y0
AND X1
OUT Y1
AND X2
X1 OUT Y2

Y1
X2

Y2
X1 extends the logic of Y0. X2 extends the logic of Y1. Note the extension logic leading to
each lower coil from the upper coil connects directly to the upper coil. There are no contacts
between that connection point and the upper coil (see arrows).

The logic leading up to a set of cascading outputs can be built without resorting to anything
other than LD/AND/OR, etc and, if needed, ANB/ORB. The extension logic added for each
new output is built using only AND/ANI. (once you place even 1 output, you are no longer
allowed to use ANB/ORB). In reality, you should be able to also use OR in the extension logic
but the ability has been disabled in the plc. For a look at why, see Water Flows Downhill (in the
Other Stuff section at the end of this document).

Divergent Outputs
You have divergent outputs when you have more than one output and each uses only some of
the logic of the preceding output. Each output may, but is not required to, extend that logic with
more of its own (remember this last part, Rule #6 is all about it).

There MUST be contacts


here
X0

x3

Y0
X1

x4

Y1

Points of divergence

There MAY be contacts


x2

Y2

here

Note that X3 is sitting between the higher coil (Y0) and the connection point leading to a lower
coil (Y1). Y1 does not use all of the logic that Y0 does. Y1 totally ignores X3. The output of
the X0 contact is what I call a "point of divergence". It's like a fork in the road. The logic splits
into 2 different routes. Each half of the fork ends in a coil that is not seen by the other.

- 24 -
So what? Well picture the plc merrily processing everything in your program up to and
including X0 in the normal manner. Then it looks at X3 and outputs Y0. Everything is rosy.
Remember, at this point (like all points) none of the preceding logic exists anymore. All we
have is the current result in the accumulator. This result includes the effect of X3.
Unfortunately, we still have to process the logic leading up to Y1 but that's not supposed to
include X3! Basically, we now need the plc to back up a bit (to the point of divergence) and
then execute the branch to Y1. Hmmm. Sorry... plc's don't do that.

Really Smart PLC Rule #5:


PLC logic never flows backwards.

In order to build a set of divergent outputs, you have to use MPS (Memory Point Store) or
some other method of saving the value of the accumulator when you come to the place where
the multiple output paths separate (the point of divergence). Later, when it's time to execute the
second branch, you can recall that value from storage and use it to modify the accumulator.
Whenever you see a point of divergence in your code, you know you need to stick an MPS
there (or similar). This is the only time MPS is used in a program.

The Evil MPS


I'm not going to go into too much detail on MPS since it's all in the manual. If you don't
understand it, don't worry about it; use the alternate method described below. Let's just quickly
say this: If you write MPS, the plc will store the value of the accumulator at that point in the
program. MPS operates on a stack that is 12 storage locations deep (in the FX series). Each
time you write MPS (Memory Point Store), you shove the previous values deeper into the
stack. You read the topmost value with MRD (Memory Read). This loads the accumulator with
the value read. If instead you read the stack using MPP (Memory Point Pop), you load the
accumulator with the current value and then bring the next value up to the top. Subsequent uses
of MRD will read that "next value". You must completely empty the stack before leaving a
rung or you'll generate an error. In other words, for every MPS there must also be a MPP. You
can have any number of MRD's.

Having said that, you shouldn't use MPS except in very obvious circumstances. All too often,
you'll see MRD or MPP used many lines below the MPS. Now you have to search up through
the code to figure out what is being referenced. A better method is to assign an internal relay
(eg. OUT M0) to that point in the logic instead of using MPS at all. End the rung right there
and start over using a contact from the internal relay. You can now give that relay a very
descriptive name and refer to it as often as you wish without worrying about matching MPP's
with MPS's. Your rungs will be shorter and simpler too.

The main reason that MPS exists is for use by the Ladder editing software itself. When you
write in Ladder, the editor must convert your code into List because that's what gets sent to the
plc. The editor's conversion makes grand use of MPS (especially since unlike you, most people
don't know about divergent versus cascaded outputs). It needs a temporary method like MPS
because it's not at liberty to use internal relays (they belong to you) and it would do a lousy job
of naming them anyway.

The Point of all of this


Simple outputs are obvious. They'll usually take care of themselves. Cascaded outputs are nice.
The code looks good and it executes quickly. Divergents are not really devil spawn but we do

- 25 -
want to know when we've made them by mistake. If you start looking, you'll be surprised how
many times they could have been written as cascades with just a little bit of effort. Especially
when written in Ladder. Which brings us to:

Really Smart PLC Rule #6:


If a divergent output does not have logic between itself and the point of divergence, it's an
indication that things could have been re-ordered as a cascade.

Proper divergent outputs.


Point of
divergence
X1
X0

Y0
X2

Y1

It codes as:

LD X0
MPS
AND X1
OUT Y0
MPP
AND X2
OUT Y1

Divergent outputs that should be rewritten as cascaded:

Point of
divergence
X1
X0

Y0
Y1

It codes as:

LD X0
MPS
AND X1

- 26 -
OUT Y0
MPP
OUT Y1
Note that MPP is followed immediately by OUT.
This is an indication that it should be rewritten as:

Same as above but with cascaded outputs.

This is NOT a
Point of divergence
X0

y1
x1

y0

It codes as:

LD X0
OUT Y1
AND X1
OUT Y0

Not only can some divergents be re-written as cascades, simple outputs need looking at too. For
instance, when first exposed to List, many people are tempted to write code with repetitive
logic such as:

LD X0
OUT Y0
LD X0
AND X1 Simple Outputs with Repetitive
OUT Y1 Logic
LD X0
AND X1
AND X2
OUT Y2

They wouldn't have done it like that in Ladder and there's no rule that says they have to do it
that way in List. We could have accomplished the same result like this:

LD X0
OUT Y0
AND X1 Same Logic with Cascaded
OUT Y1 Outputs
AND X2
OUT Y2

- 27 -
You don't have to end a block of code just because you've reached an output.
You CAN keep going! Of course, there are many times when repeating some of the logic
(perhaps via an internal relay) will actually be a good idea. It allows you to break things up into
sections and separates ideas. Knowing what your options are is the first step towards writing
optimal code.

- OTHER STUFF -

Reversing Your Logic or "What I really meant was..."


Let's say you've just completed a long, involved piece of artwork (a masterpiece of logic) that
views things from the perspective of "if all things are on then do something". After looking at
it, you realize that although the result is correct, it doesn't explain things in the best possible
way. What you really wish you'd written was the same logic but expressed as "if some things
are off then don't do anything". Before you start a mind-numbing revision (or worse, start
unloading the dishwasher) there is a simple "no thinking required" method for doing it. Which
leads us to...

Really Smart PLC Rule #7:


If you invert every contact, logical operation and output in a logic sequence, there will be no
change in the operation of the outputs.

A full inverse is where you invert both the contact and the operation in one shot.
It works like this:
LD & LDI are the full inverse of each other (we only have a contact).
AND & ORI are the full inverse of each other (both a contact and an operation).
OR & ANI are the full inverse of each other (both a contact and an operation).
ANB & ORB are the full inverse of each other (we only have an operation).
OUT & INV OUT are the full inverse of each other (we only have an output).

example:
LD X0 ;if x0 is on
AND X1 ;and x1 is on
OR X2 ;or x2 is on
OUT Y0 ;then turn on y0.

is the same as...

LDI X0 ;if x0 is off (full inverse of LD)


ORI X1 ;or x1 is off (full inverse of AND)
ANI X2 ;and x2 is off (full inverse of OR)
INV ;then don't
OUT Y0 ; turn on y0.

Note the use of INV ("Invert"). It takes the value of the accumulator and inverts it. Some plc's
offer a ready-to-go inverted version of OUT (usually called something similar to OUT_NOT)
but it's NOT there in the FX series (pun intended). Fortunately, we can mimic it by using INV
followed by OUT. Having to use INV may not be as efficient as OUT_NOT but it is very
versatile since we can use it for other things anywhere in our code. The bad news is it's NOT
available on the FXON & FXOS.

- 28 -
As you can see, this type of logic reversal is quite easy to perform in List. If you try the same
thing in Ladder, you'll find it's a lot more difficult especially with complex logic.

IF/THEN/ELSE
If/then/else is a very heavily used feature in almost every computer language ever developed.
eg. in Pascal one could write this:
If (Beer = 0) or (Chips = 0) then GetGroceries
Else WatchTV;

If the first line is true (ie. beer & chips really are equal to 0), the statement following the word
"then" will execute but the statement following "Else" will not. If the first line is not true, then
only the statement following "Else" will execute.

We can do similar on the plc using INV. In fact, you can quite literally think "else" when using
INV in this manner.

LDI BEER ;if no beer


ORI CHIPS ;or no chips
OUT GET_GROCERIES ;then get groceries
INV ;else
OUT WATCH_TV ; watch TV

As a side note, the above is a good example of cascaded outputs. Nonetheless, I don't
recommend using it on your next job application.

An alternative to using INV here would be to replace it with LDI GET_GROCERIES. I prefer
INV as it more closely associates the two possible results together. Instead of a cascade, LDI
would start a new rung.

Notice how easy it is to read the code when you put meaningful names in place of the I/O
numbers we've been using. It works well. I'll refrain from comments such as "Ladders are for
changing light bulbs" if you'll admit List is not as bad as you thought.

Water Flows Downhill (but Ladder doesn't know that)


I mentioned earlier that you are not allowed to use OR (or ORI) with cascaded outputs. I'll try
and explain that here.

Have a look at the following diagram.


X0

Y0
X0

Y1

- 29 -
If this were wired with real relays in the real world, both Y0 and Y1 would always be on. It
doesn't matter whether X0 is on or off; one of the contacts will always power up both coils.
There is no point to this circuit but it illustrates the idea.

This is how you would code it in order to obtain the same behavior:
LD X0
ORI X0
OUT Y0
OUT Y1

Now check out this code. It's a set of cascaded outputs where the upper output is extended
using ORI.
LD X0
OUT Y0
ORI X0
OUT Y1

Under the current rules of engagement, this should convert into the same drawing as we have
above but its operation is very different from the relay version.

Remember that once something is executed, the plc forgets about it. All it keeps is the current
result in the accumulator. If X0 is on, it will turn on Y0. After that, in line 3 of the List, we are
in effect saying "if the accumulator is on OR if X0 is off then turn on Y1. No matter what it
decides to do about Y1, it will never go back and change Y0. Y0 has been handled and
forgotten about. Y0 will only go on if X0 is on. Y1 will go on no matter what. Guess what?
Kaboom! One major pitfall for someone translating a relay diagram into a plc program. Rather,
I should say, it's only a pitfall for someone who thinks that just because both versions will
convert in their head to the same ladder diagram, he can use either version of List to represent
the relays. However, if you let your editor auto-convert this List into Ladder, it will either
"correct" it for you (Medoc Dos) or get very confused (GX Developer).

Medoc will change the cascaded outputs into simple ones as in the first example.
LD X0
ORI X0
OUT Y0
OUT Y1

This should convert back again into the same drawing as we have above (it does).
Written this way, Y0 & Y1 will operate the same as the real relays. But it has a different
meaning than what we told it we wanted. Personally, I think it's unforgivable that Medoc has
the audacity to change this code without so much as a warning. GX is not much better. It
refuses to convert it but doesn't tell you why or what the problem is. Just sort of hangs there in
limbo. Not exactly good behavior.

If you send the cascaded version to the plc without converting it to Ladder, it will generate an
error that makes no sense ("Number of LD/LDI instructions is more than ANB/ORB
instructions"). It really should operate the way we described above (the Kaboom method). It is
correct and might even be a useful bit of logic for you. On the other hand it could be quite the
opposite of what you (or the next guy to read your code) were expecting. Worse, viewing it in
Ladder will either cause changes that may become permanent or, make you look unprofessional

- 30 -
when it fails to convert. Mitsubishi simply made it an illegal combination without fully dealing
with the situation. In any event, it's good to be aware of the issue. It also illustrates something
I've been gently hinting at for some time:

PLC logic never flows backwards. Did I mention that?

While we're on the subject, take note that if you had a different situation and needed to use an
ANI instead of the ORI in the cascaded version, you'd avoid all of the problems. The Ladder
editors would be happy and all will work exactly like everyone expects. Y1 would never go on
in this particular example but you get the point.

This whole cascaded OR thing is not really the fault of List, the plc or even the Ladder
language. The problem lies with the Ladder editing software. Current editors have no way to
draw it that isn't misleading. They could easily have used a downward pointing arrow (or a
diode) instead of a solid vertical line. Until they figure this out and make cascaded OR's legal,
you have no choice in the matter. You can't use them. Not something you'll miss anyway.

The moral of this is that it's worth having a plc in the shop for testing purposes. If you don't
have access to one, before heading out to a client's site, at least attempt a conversion in GX
before deciding that everything is hunky-dory. Medoc users have no recourse other than
caution.

*************************************
**********

QUICK SUMMARY OF THE RULES

Really Smart PLC Rule #1:


AND, ANI, OR & ORI commands always operate on all of the preceding logic.

Really Smart PLC Rule #2:


If a string of logic contains a set of series contacts and a set of parallel contacts:
add the series set last if you want the two sets to be in series;
add the parallel set last if you want the two sets to be in parallel.

Really Smart PLC Rule #3:


Use ANB/ORB when you need to apply logic that only operates on some of the preceding logic.

Really Smart PLC Rule #4:


Both blocks being joined by ANB should end in OR, ORI or a block join (ANB/ORB).
Both blocks being joined by ORB should end in AND, ANI or a block join (ANB/ORB).

Really Smart PLC Rule #5:


PLC logic never flows backwards.

Really Smart PLC Rule #6:


If a divergent output does not have logic between itself and the point of divergence, it's an
indication that things could have been re-ordered as a cascade.

- 31 -
Really Smart PLC Rule #7:
If you invert every contact, logical operation and output in a logic sequence, there will be no
change in the operation of the outputs.

*************************************
**********

I hope I've managed to provide you with some insight into the Instruction List language. Maybe
you can even see yourself trying it out in your next project instead of automatically using
Ladder. If nothing else, perhaps seeing a different approach has deepened your understanding
of plc's and given you some ideas of your own. It's all worthwhile, right?

Some of the people reading this will be beginners so I can't end without making a couple of
comments about the need to be very careful. The machinery we work on is dangerous and it's
your job as a designer to remove as much of that danger as possible. In office software
development, a bad design is an irritant and errors can be expensive. Machinery on the other
hand, is a whole different animal. Those same problems can rip someone's arm off. Think
carefully about everything you write. Worry about the design. Get help. Ask questions. Test,
test, test. And then test some more. It's a case of Hero or Zero. There's not much in between.

That's all for now. If you have anything to add, I'd love to hear from you.
Comments and criticism (contract offers, bank drafts, etc) are all welcome.

Happy coding!

Antony
+91 99522 94792

- 32 -

You might also like