PLC Programming Exercises for Beginners: Six Worth Doing

The first program almost everybody writes is a motor start and stop with a seal-in. It works on the bench. Wired into a real panel, the same logic can leave a motor running with the stop button pressed and a broken wire nobody can see. That gap between working and correct is what these exercises are for: six of them, in the order they teach you something, each with the instruction behaviour that causes the trouble and a way to prove you got it right. Every instruction detail below comes from Rockwell publication 1756-RM018A-EN-P, September 2025, so you can check the lot.

Start with the one that matters most.

1. Start and stop, with the stop button wired normally closed

Two inputs, one output. Press start, the motor runs. Press stop, it stops. The seal-in is a parallel branch around the start button, holding the rung true after you let go, and if that were all there was to it this would be a five minute exercise rather than the one that separates people who’ve wired a panel from people who haven’t.

Here’s the part that catches everybody.

A stop pushbutton in a real panel is wired normally closed. Its contact is made when nobody is touching it, so the PLC input is on during normal running and goes off when somebody presses it. And because it is on during normal running, the instruction that tests it in the ladder is an XIC, examine if closed, not an XIO.

That reads backwards the first three times you see it. The reasoning is what makes it stick:

Stop button wiringInstruction that tests itWhat happens if the wire breaks
Normally closedXIC. The input is on while the machine may run, so rung-condition-out is set to true and the seal-in holds.The input goes off, exactly as if somebody had pressed stop. The motor stops. This is the whole point.
Normally openXIO. The input is off while the machine runs, and the XIO passes.The input stays off, which the logic reads as “nobody pressed stop”. The motor keeps running and the stop button does nothing at all.

A broken wire, a pulled ferrule, a corroded terminal. With the normally closed arrangement every one of those failures stops the machine. With the normally open arrangement every one of them quietly disables the stop button, and you won’t find out until the day somebody needs it.

That’s fail-safe design, and it’s why the ladder looks inverted.

One thing this exercise does not give you. A stop button in PLC logic is not a safety stop, and an emergency stop belongs in hardware, or in a safety relay or a safety controller, on a circuit that does not depend on the program scanning at all.

Build it, understand it, and don’t conclude you’ve built a protective device.

Advertisement

2. A TON that does what you actually asked

Run the motor from exercise 1, but only start it three seconds after the start button is pressed.

The TON is a non-retentive timer that accumulates time while it’s enabled. Four facts are worth memorising, and three of them will come up in your first week.

  • The time base is always 1 millisecond. The manual’s own example: for a 2 second timer, enter 2000 for .PRE. There is no time base selector. A three second delay is 3000.
  • .DN and .TT are not the same bit. .DN is set when the timing operation is complete and stays set. .TT is true only while timing is in process. Driving an output from .TT gives you a pulse that lasts exactly as long as the delay, which is occasionally what you want and almost never what a beginner meant.
  • .EN holds rung-condition-in from the last time the instruction executed. Not the current rung state. If the rung is not scanned, .EN is stale.
  • Writing to .DN pauses the timer. Straight from the manual: “When enabled, timing can be paused by setting the .DN bit to true and resumed by clearing the .DN bit to false.” Very few people know that, and it explains some otherwise baffling behaviour in code somebody else wrote.

A timer doesn’t count scans. It works out elapsed time arithmetically, as ACC = ACC + (current_time – last_time_scanned), which is why a 3000 ms preset takes three seconds whether your scan is 2 ms or 40 ms. On a CompactLogix 5380, ControlLogix 5580, Compact GuardLogix 5380, GuardLogix 5580 or ControlLogix 5590 there’s a second form of the same instruction, TIMER_T, which uses the TIME data type for .PRE and .ACC and resolves to microsecond fidelity instead of milliseconds.

Same instruction. Different structure.

And here’s how to fault a controller on your first day: a negative preset. A .PRE below zero raises a major fault, type 4, code 34. So does a negative .ACC.

3. Count parts, then deal with the counter filling up

A photo-eye on a conveyor. Count boxes. Turn on a light at 100 and let the operator reset it.

CTU counts up each time rung-condition-in transitions from false to true. So a photo-eye blocked for four seconds counts once, not four thousand times, and that transition-driven behaviour is the whole reason the instruction exists.

The COUNTER structure holds more than most people use:

MemberWhat it is
.CUThe count up enable. Holds rung-condition-in from the last execution.
.DNSet when the counting operation is complete, meaning .ACC has reached .PRE.
.OVOverflow. Set when the counter increments past 2,147,483,647.
.UNUnderflow. Set when a counter decrements past -2,147,483,648.
.PREThe value .ACC must reach before the instruction indicates done.
.ACCThe number of transitions counted.

Here’s the exercise that teaches the real lesson. The CTU doesn’t stop at .PRE. It keeps counting, so .DN comes on at 100 and stays on at 101, at 5000, and all the way up to 2,147,483,647, at which point .OV sets and the value wraps. So build it, watch .ACC sail past .PRE, and then go and add the RES that clears it. A counter with no reset anywhere in the program is one of the most common things you’ll find in a first project, and it works perfectly until the shift it doesn’t.

Advertisement

4. One shot a recipe load

Load six setpoints into a machine, once, when the operator presses Load. Not every scan for as long as the button is held.

The ONS instruction “makes the remainder of the rung true each time rung-condition-in transitions from false to true”. Put it between the button contact and the MOV instructions, and the transfer happens on one scan only. Then break it deliberately, because that’s the fastest way to understand it: move the whole rung into a subroutine, and call that subroutine only when some other condition is true.

The one shot now misbehaves, and the reason is worth working out for yourself before you read on. A ONS keeps a storage bit that, in the manual’s words, “retains the rung-condition-in from the last time the instruction was executed”. Executed, not elapsed. If the routine isn’t scanned for ten seconds, the instruction has no idea anything happened in between. Conditional subroutines and edge-triggered instructions do not mix, and this is true of ONS, OSR, CTU and every other transition-driven instruction.

5. Latch an alarm, and find out why it will not clear

Set an alarm bit when a pressure switch trips. Keep it set after the pressure recovers, so the operator has to acknowledge it.

That’s what OTL is for. The manual is precise about the behaviour: OTL “sets the data bit to true. The data bit remains true until it is cleared, typically by an OTU instruction. When the rung condition is changed to false, the OTL instruction does not change the status of the data bit.”

Read that last sentence again. A false rung does nothing. The bit stays set.

Which is exactly what you asked for, and also the trap: an OTL with no matching OTU anywhere in the program gives you a bit that can never be cleared except by hand in the tag editor. Write the OTU rung at the same time as the OTL rung, always, even before you know what will drive it.

Compare that with OTE, which “sets or clears the data bit based on rung condition”. OTE follows its rung both ways. OTL and OTU do not.

6. Break it on purpose: two outputs on one tag

This one is short, and it is the most useful thing on the list.

Take a working program and add a second OTE, somewhere further down, writing to the same tag as an existing one. Then watch the output ignore everything the first rung asks of it. Ladder solves top to bottom, so the last OTE scanned is the one that decides the bit at the end of the scan, and every rung above it writing that same tag is wasted work. Nothing warns you at download time.

The tag just obeys whichever rung sits nearest the bottom.

It’s called a duplicate destructive bit. Create one deliberately now and you’ll recognise it in thirty seconds rather than in an afternoon.

Where to actually run these

You do not need a controller on a bench.

Rockwell’s own instruction manual lists Studio 5000 Logix Emulate alongside the physical platforms, so a project written against an emulated controller uses the same instruction set as the real thing, which is the whole point. plctr has walkthroughs for setting up the Logix Emulate virtual PLC and downloading a program to the emulator. If you’d rather have something with no vendor attached at all, the CODESYS Development System V3 is listed on the CODESYS store at €0.00 plus VAT with “no license is required”, currently version 3.5.22.30, released 23 July 2026, and the setup bundles a demo of the CODESYS Control Win SL SoftPLC. Their licence terms describe demo software as “free of charge but limited by time and/or functionality”, so check what the current limits are before you plan a long evening around it.

Frequently asked

Why is the stop button an XIC when it stops the machine?
Because it’s wired normally closed, so the input is on during normal running. The instruction tests the input, not your intention.

Should I start with ladder or structured text?
Ladder, if you’ll be working on machines that already exist. Most of the installed base is ladder, and the instructions above are ladder-only: TON, CTU and ONS aren’t available in structured text or function block.

How long should a first program be?
Short enough to hold in your head. Exercise 1 is four rungs. Past fifteen and the problem hasn’t been broken down far enough.

What is .PRE in seconds?
It is not in seconds. The time base is always 1 millisecond, so a 2 second timer needs a .PRE of 2000.

My counter reached the preset and kept counting. Is it broken?
No. .DN sets when .ACC reaches .PRE and the counter carries on regardless. Add a RES, or compare .ACC yourself.

Advertisement

Next step

Do exercise 1 again from a blank routine, without looking at what you wrote the first time, and wire the stop button normally closed in your head as you go. Then read your own rungs and ask which of them would still be safe with one conductor cut. The instruction-by-instruction detail behind these is in XIC and XIO bit instructions with ladder examples and timer and counter instructions. A worked start and stop program is in the RSLogix motor start and stop program, the one shot family is covered in using one shots ONS, OSR and OSF, and when you want a bigger machine to aim at, star delta motor starting is the classic next one.

Primary source: Rockwell Automation, Logix 5000 Controllers General Instructions, publication 1756-RM018A-EN-P, September 2025, chapters 2 and 3.