One-Shots on a ControlLogix: ONS, OSR and the Rung That Fires Twice
A batch counter on a reel changer reads 412 when the shift log says 11 reels ran. The routine sits in a 100 ms periodic task, so 401 spurious counts is forty seconds of something firing ten times a second — and the machine spends about that long standing still with Reel_Ready on between reels. The rung has an ONS in it, the ONS sits correctly ahead of the CTU, and by every conventional reading that rung is right.
The bug is not on that rung.
It is on a rung eleven lines further down that happens to use the same storage bit.
All five of these instructions run on every current Logix family — CompactLogix 5370 and 5380, ControlLogix 5570, 5580 and 5590, and the Compact GuardLogix and GuardLogix controllers alongside them — and all five behave the same way, because everything a one-shot knows lives in one bit. ONS does not have internal state and neither do OSR and OSF: the storage bit is the whole memory, it holds the rung condition from the last time that instruction executed, and the instruction compares this scan’s condition against it. Give two instructions the same tag and each one overwrites the other’s memory of the past, which is how a rung ends up firing on every scan rather than once.

Nothing is wrong with either rung on its own. The fault is in the tag name typed into both of them.
What the shared bit actually does, scan by scan
Follow it through once and it stops being mysterious.

Five rows and nine scans. The one that matters is the fourth, because a false rung does not leave the storage bit alone — it clears it.
Scan 1 has both conditions false, so both rungs clear os_bit and nothing counts. On scan 2, Reel_Ready comes on: rung 3 finds its condition true and os_bit false, so it fires, the rest of the rung goes true, the CTU counts, and the instruction sets os_bit true on the way out. Eleven rungs later, rung 4 executes with Purge_Cmd false — and the execution table for a false rung says the storage bit is cleared to false. So os_bit ends scan 2 at zero, exactly as it started, and on scan 3 rung 3 looks at a true condition and a false storage bit and concludes, correctly by its own rules, that a transition just happened. It fires again.
And it keeps firing on every execution for as long as Reel_Ready stays on, which on a machine waiting for an operator is minutes.
That is the mechanism. It produces a count that climbs once per execution of the routine, which at a 100 ms period is 10 a second and is why the number is 412 rather than 22.
The manual prints a warning above every one of these operand tables, in the same words each time: unexpected operation may occur if output tag operands are overwritten, or if structure operands are shared by multiple instructions except where it says otherwise. That warning is not decoration and it is not only about structures.
A one-shot’s storage bit is exactly the operand it is describing.
Where duplicate storage bits come from
Nobody types the same tag twice on purpose.
They arrive by copy and paste, which is the obvious route and the easiest to find. They arrive from an Add-On Instruction that declares its storage bit as a Local rather than passing it in, so every call site shares one — worth checking if your AOI does edge detection anywhere inside it. They arrive when a routine is called from two JSR instructions in the same scan, which is subtler: the one-shot’s contract is one shot per false-to-true transition of its own rung condition, so a second call in the same scan with the condition still true does not fire, and the shot silently moves to whichever call site happens to see the rising edge.
And they arrive when one routine is scanned by two tasks, at which point the storage bit becomes a race.
The last one deserves a flat statement: a routine containing one-shots should be called from exactly one place.
If you inherit a project and want to know which one-shots are safe, the tool is the cross-reference, not reading.
Right-click the storage bit. More than one instruction in that list is the bug, found before it costs you a day. Cross-referencing a tag in Studio 5000 is the thirty-second version of that.
One naming rule stops this whole class of problem.
Name the storage bit after the thing it is watching — os_ReelReady, not os_bit and not oneshot_3 — and a pasted duplicate becomes visible in the rung it was pasted into, because the name no longer matches what is on the left of it.
ONS against OSR: what comes out the other side
These two are not interchangeable and the difference is where the result goes.
ONS makes the remainder of the rung true for one scan. There is no output bit; the rung condition itself is what carries the shot, so everything to the right of the ONS executes once and everything on a different rung knows nothing about it. OSR sets a named output bit true for one scan and takes two operands to do it, a storage bit and an output bit.
That output bit is an ordinary BOOL and can be examined anywhere: one edge, conditioning five instructions across three routines.
OSF is the falling-edge version of OSR, same two operands, and it fires when the rung goes from true to false.
Choose on that basis rather than on habit.
If the edge is consumed on the rung that detects it, ONS is fewer tags and fewer things to get wrong. If the edge is needed somewhere else, OSR is the honest way to carry it, and the alternative people reach for — an ONS driving an OTE that other rungs examine — works but leaves the reader one indirection away from understanding it.
There is one thing neither of them does, and it catches people moving from ladder into Structured Text: ONS, OSR and OSF are ladder-only instructions. Not available in Function Block, not available in Structured Text, in as many words under Available Languages. The ST and FBD equivalents are OSRI and OSFI, and they are the right answer rather than a workaround. Both use the FBD_ONESHOT data type, whose whole structure is four members: EnableIn and InputBit going in, EnableOut and OutputBit coming out. The description is one sentence — if InputBit is true and it was false the last time the instruction was scanned, OutputBit is set, otherwise it is cleared — and the previous value lives inside the backing tag instead of in a bit you named, which is the whole difference and the reason the ST versions do not have this article’s problem. If you are writing ST and find yourself comparing a bit against a copy of itself from last scan, you have hand-rolled an OSRI and you should use the instruction.
Prescan is the reason none of this fires on the first scan
Here is the detail that explains why one-shots behave at all across a download.

The prescan column is doing all the work. Note that ONS and OSR come out of it one way and OSF comes out the other way.
ONS and OSR set the storage bit true during prescan, and the manual says why in plain words: to prevent an invalid trigger during the first scan.
Think for a moment about what would happen without that line in the execution table. The controller goes to Run with a bit already true — a bit that has been true since before the download, because the sensor it comes from has not moved — and the one-shot, with a storage bit initialised to false, sees a false-to-true transition that did not happen. Every rising-edge one-shot in your project would fire on the first scan after every download. On a machine that means every recipe loads, every counter increments, every fault log entry writes. Setting the bit true in prescan makes the instruction start out believing the condition was already true, which for a condition that was already true is correct.
OSF is initialised the opposite way for exactly the same reason, because for a falling edge the dangerous initial assumption is the other one.
So the instructions are safe on the first scan.
What is not automatically safe is whatever you built on top of them, and that is where people go wrong in the other direction. A one-shot that does not fire on the first scan means initialisation logic that depends on an edge never runs after a download, and the machine comes up with a sequence step of zero and no recipe loaded and no obvious cause. That is what S:FS exists for, and it is the right tool for it: see the PLC first scan bit for the pattern. Do not try to make a one-shot do that job by pre-clearing its storage bit in a fault routine, which is a thing people try and which produces a project where the same instruction means different things depending on how the controller got to Run.
The dead end: it is almost never contact bounce
When a count runs away, the first suspect is always the input.
It is a reasonable suspect. A dry proximity switch, a relay contact without a snubber, a reed switch on a cylinder with a slow rod — all of them genuinely chatter, all of them genuinely produce extra counts, and the input filter time is a real setting people genuinely need to change — a 1756-IB16 offers 0 ms, 1 ms and 2 ms, and the 0 ms default is the one that lets a bouncing contact through. So an afternoon goes into scoping the field wiring and tuning filter times, and the count still runs away.
Two things tell you it is the logic and not the wire.
The first is the shape of it.
Bounce gives you a small integer of extra counts per real event — two instead of one, occasionally four — and the extras are clustered around the real edge. A shared storage bit gives you a count that climbs continuously while the input is steady, at something like the scan rate, and it does not climb at all while the input is off. The second is that a shared storage bit produces counts when nothing moved, which no amount of contact bounce can do. Put the counter accumulator on a trend for thirty seconds with the machine stopped.
A flat line clears the logic. A ramp of 300 counts convicts it, and tells you the task period as a bonus.
And if the one-shot is on a safety reset, none of the above is the interesting question — the interesting question is whether the reset is an edge at all, which is covered properly in a safety reset that is a rising edge, not a level.
What to check next
Cross-reference every one-shot storage bit in the project, in one pass, and write down any that appear more than once. It takes about ten minutes on a medium project and it is the only check that finds this class of fault before it finds you. Then look at how the routines containing them are called, because two JSR instructions to the same routine, or one routine scanned by two tasks, will produce the same symptom with no duplicate tag name anywhere to find. The instruction-level view of the same family on the older platform is in using one-shots in RSLogix 500, and the companion question for the other stateful ladder instructions — what happens to them when the rung goes false and what prescan leaves behind — is in TON, TOF and RTO on a false rung.