ControlLogix5000: Timers on Rungs

I thought the output of the first timer (while not finished timing yet) would make the rest of the rung FALSE.

that would "make sense" - but it's incorrect ...

if the "rung condition" coming INTO a TON instruction is TRUE – then the "rung condition" going OUT of the TON instruction would also be TRUE ... this is regardless of whether the timer is "done" or not ...

more specifically, you need to use the status of the timer's STATUS bits (Done, Timer Timing, Enabled) in order to get the TRUE/FALSE logic conditions that you're looking for ...
 
Last edited:
EDIT: "Someone" is always replying at the same "time" as me!(I started and then got called to something...what's new?)

To re-iterate what Ron is pointing out...

ASF said:
...In AB PLC's, most instructions other than your standard XIC/XIO and comparators are what you might describe as "straight through" instructions - i.e. if the rung-in condition is true, so is the rung-out condition. This is useful, because it allows you to put several instructions in series as we're describing. The timer is included in this - if you felt so inclined, you could put 20 timers all in series and they would all start and stop their timing operations together.

Colt Hero said:
Really? Now I'm confused! I thought the output of the first timer (while not finished timing yet) would make the rest of the rung FALSE. Wouldn't the timers to the right have to be FALSE-enabled timers to start their timing?...

This ties in a little with what I was banging on about in relation to the "bits" hanging of the right-hand side of the Timer instruction...

For quick reference, if you look at my last screenshot above. When the rung-condition-in to the timer instruction is TRUE, what happens? The Timer instruction is ENABLED. Hence the EN bit will be set TRUE. The graphical representation links the output of the Timer instruction to the rest of the rung via its EN bit, as you can see. So, once the Timer instruction's rung-condition-in is TRUE, and the EN bit is TRUE, the Timer instruction's rung-condition-out is automatically TRUE, always.

This is where I was suggesting it would be more useful if we could tie the rung continuity to either the EN or DN bit on the right-hand side of the Timer instruction. This way we could choose whether we want a "passive" or an "active" Timer instruction, with regard to the rung-condition after the Timer.

Regards,
George
 
Ron and George have answered for me already, but yes, it works differently to the way you thought.

A quick tip for you as you delve more and more into Rockwell PLC's. These few "rules" have helped me understand and write code better, if you remember these and think about the code in these terms, you might find it becoming more intuitive:
1. Forget "on" and "off"; instead think about things in terms of "rung in condition" and "rung out condition"
2. Every single instruction on every single rung is executed exactly once per scan, from left to right and top to bottom, no matter what is happening on the rung before it*
3. PLC's never look backwards**

*There are exceptions to this rule of course: if the subroutine is not being called, or if JMP/LBL (jump and label) instructions or an MCR instruction are involved. These programming methods should (in general) only ever be used as a weapon of last resort, and very sparingly. So, for what I'd consider "well written" code, rule 2 is correct enough for most applications

**Again, there are exceptions, like JMP/LBL, but again, as a general rule...

Read on for a little more detail on each of my "rules" and why they're helpful (to me, at least)

1. Forget "on" and "off"; instead think about things in terms of "rung in condition" and "rung out condition"

Imagine a rung of ladder logic with a range of XIC, XIO, TON, MOV, OTE, OTL, OTU, or any other instructions on it. Each instruction on the rung has two different ways of operating; one way when it is scanned with the rung-in condition TRUE, and once when it is scanned with the rung-in condition FALSE. In addition, each instruction also sets a rung-out condition, which may be based on the rung-in condition, the status of any tag associated with that instruction, internal instruction parameters, or a combination of several of those things.

For example, an XIC instruction operates as follows:
- With rung-in condition TRUE: if associated tag is also true, set rung-out condition to TRUE; if associated tag is FALSE, set rung-out condition to FALSE
- With rung-in condition FALSE: set rung-out condition to FALSE, regardless of the state of the associated tag
- Then, the rung-out condition of that instruction becomes the rung-in condition of the next instruction

Now consider the OTE and OTL instructions:
- An OTE scanned when the rung-in condition is TRUE will set a bit to 1, and set the rung-out condition to TRUE
- An OTE scanned when the rung-in condition is FALSE will set a bit to 0, and set the rung-out condition to FALSE
- An OTL scanned when the rung-in condition is TRUE will set a bit to 1, and set the rung-out condition to TRUE
- An OTL scanned when the rung-in condition is FALSE will do nothing to the bit, and set the rung-out condition to FALSE
If you look at the help files for each instruction, you'll see that it gives detailed descriptions of how each and every instruction operates with both a true rung-in condition, and a false rung-in condition. It will also tell you how the rung-out condition behaves. As a general rule, most (if not all) output instructions (any instruction that acts on a tag - OTE's, MOV's, math instructions, timers...) have a very straightforward method: rung-out condition = rung-in condition. They just pass the rung status straight through to the next instruction, which is why it is possible to put multiple output instructions in series.

2. Every single instruction on every single rung is executed exactly once per scan, from left to right and top to bottom, no matter what is happening on the rung before it.
Each and every instruction on a rung is scanned and executed, even if you put an AFI right at the start of the rung. When you think about it, it has to be this way, because when you "break the circuit" to a timer, the timer still has to do certain things (like turning off the .DN bit, and resetting the accumulated time to zero). As per rule one, think about it as "rung-in condition" and "rung out condition". No matter what happens earlier in the rung, each instruction is scanned and will perform its specified action - that action, as we've seen, is dependent on the rung-in condition to the instruction. Remember: putting an "always off" at the start of the rung does not disable the rung. It merely ensures that every instruction on the rung is scanned and executed with a false rung-in condition. OTE's will still turn off bits. Timers will still turn off .DN bits. And PLC's will still crash if you feed a MOV instruction with an out-of-range array pointer while you're overseas in a third world country trying to troubleshoot remotely with terrible internet access (three guesses as to how I learned this lesson).

This rule is also relevant when considering its exceptions: if you scan an OTE with a true rung-in condition, and then stop scanning the rung altogether (e.g. stop calling the subroutine), the bit associated with that OTE will not turn off. It doesn't turn off just because it's not being "powered" any more; the bit is only ever turned off by an instruction commanding it to do so - which could be an OTE scanned with a false rung-in condition, or an OTU scanned with a true rung-in condition. If the bit is an output controlling a pump, and you stop calling its subroutine, that pump will never stop. This is one of may reasons that conditionally calling subroutines is (in general) very bad programming practice.

3. PLC's never look backwards

Consider the following rung:
Code:
|    Bit_1               Bit_1     Bit_2    |
|-----| |----------------( U )-----(  )-----|
|
To look at it simplistically, you might say "bit 2 will never turn on, because as soon as bit 1 comes on it turns itself back off". But remember: PLC's never look backward. Again, read the rung left to right with a rung-in and rung-out condition mindset. To start with, let's assume Bit 1 is false.
1. XIC is scanned with rung-in condition TRUE (because it's connected to the main "power rail"). Associated bit is FALSE, so rung-out condition is set to FALSE
2. OTU is scanned with rung-in condition FALSE. It therefore takes no action with regard to Bit 1, and sets rung-out condition to FALSE
3. OTE is scanned with rung-in condition FALSE. It therefore sets Bit 2 to zero/false, and sets rung-out condition to FALSE

So, at the end of the rung, the only action we have taken is to set Bit_2 to FALSE.

Now lets say that at some point, a HMI sends a signal saying "set bit 1 to TRUE". Let's see how the rung executes this time:
1. XIC is scanned with rung-in condition TRUE (because it's connected to the main "power rail"). Associated bit is TRUE, so rung-out condition is set to TRUE
2. OTU is scanned with rung-in condition TRUE. It therefore sets Bit 1 to FALSE, and sets rung-out condition to TRUE.
Remember, the PLC doesn't at this point "look back", and realise that the start of the rung is now false - it just continues on, left to right, as always.
3. OTE is scanned with rung-in condition TRUE. It therefore sets Bit 2 to one/true, and sets rung-out condition to TRUE

So, at the end of the rung, we have taken two actions: we've set Bit_1 to FALSE and Bit_2 to TRUE.

Now, let's execute the rung again:
1. XIC is scanned with rung-in condition TRUE (because it's connected to the main "power rail"). Associated bit is FALSE, so rung-out condition is set to FALSE
2. OTU is scanned with rung-in condition FALSE. It therefore takes no action with regard to Bit 1, and sets rung-out condition to FALSE
3. OTE is scanned with rung-in condition FALSE. It therefore sets Bit 2 to zero/false, and sets rung-out condition to FALSE

So, at the end of the rung, the only action we have taken is to set Bit_2 to FALSE.

At the end of all this, what we've effectively done is created a one-shot: whenever Bit_1 gets set to TRUE, Bit_2 is set to TRUE for a single scan. This technique is very commonly used when programming HMI pushbuttons, but it only makes sense if you remember that a PLC thinks like Edna Mode:
Edna Mode said:
I never look back, darling. It distracts from the now
I hope something in there was useful for you!
 
All good A.

However, and hopefully not to deviate too far off topic, but this is the second thread in recent times where I feel I am somewhat defending the programming method of "calling" subroutines, or conditional subroutine calls...

ASF said:
...If the bit is an output controlling a pump, and you stop calling its subroutine, that pump will never stop. This is one of may reasons that conditionally calling subroutines is (in general) very bad programming practice.

I think this method is getting a raw deal here when Folks are saying it's "bad", "very bad", or "bad practice". For me, it is a valid method and has its uses. There is nothing wrong with using it, in my opinion, once it is implemented correctly. If "you", the "programmer", stop calling the subroutine at a point in the operations where it may cause a control issue such as "something never stopping", then that, in my opinion, is poor and/or untested programming, period. It is not, in my opinion, directly caused by having used a conditional subroutine. It is caused by not structuring the overall program correctly. Devices which you, the programmer, require to be in a particular state, ON/OFF, Stopped/Started, Home/Not Home, etc., before the function of a conditional subroutine is terminated, is your responsibility. It does take a certain degree of higher level thinking or planning. You cannot lazily implement it without due consideration of likely real World process permutations.

I have quite a few programs in existence out there in the real world chugging along nicely for many years with this type of conditional subroutine programming. I would not ever call it "bad" to use this method, but I would definitely call it "bad" for a programmer to not implement it correctly.

Place the blame squarely where it belongs, I say?

G.
 
For me, it is a valid method and has its uses. There is nothing wrong with using it, in my opinion, once it is implemented correctly.

This reminds me of the discussion around the GOTO instruction in C. I would risk saying that 90% of teachers or even programmers will tell you it's bad practice without an understanding of why it's considered bad practice and when it is a good practice that should be used instead.

Personally, I don't like calling functions conditionally, I can understand that there is a place for them and when implemented right there's nothing inherently wrong with them, but I personally don't see a gain in creating the conditions you refer in the logic versus running it unconditionally and have the logic embedded inside.
It also greatly helps with processing screen feedbacks enclosed in the block/routine.

But ultimately, you are right, if you understand what you are doing and use it correctly, there's nothing wrong with it.
 
All good A.

However, and hopefully not to deviate too far off topic, but this is the second thread in recent times where I feel I am somewhat defending the programming method of "calling" subroutines, or conditional subroutine calls...



I think this method is getting a raw deal here when Folks are saying it's "bad", "very bad", or "bad practice". For me, it is a valid method and has its uses. There is nothing wrong with using it, in my opinion, once it is implemented correctly. If "you", the "programmer", stop calling the subroutine at a point in the operations where it may cause a control issue such as "something never stopping", then that, in my opinion, is poor and/or untested programming, period. It is not, in my opinion, directly caused by having used a conditional subroutine. It is caused by not structuring the overall program correctly. Devices which you, the programmer, require to be in a particular state, ON/OFF, Stopped/Started, Home/Not Home, etc., before the function of a conditional subroutine is terminated, is your responsibility. It does take a certain degree of higher level thinking or planning. You cannot lazily implement it without due consideration of likely real World process permutations.

I have quite a few programs in existence out there in the real world chugging along nicely for many years with this type of conditional subroutine programming. I would not ever call it "bad" to use this method, but I would definitely call it "bad" for a programmer to not implement it correctly.

Place the blame squarely where it belongs, I say?

G.


That's why I prefaced "very bad" with "in general". There are of course valid reasons to do so, but my post was aimed at the OP, who is clearly a beginner-intermediate AB user. I would recommend beginner-intermediate users avoid conditionally calling subroutines wherever possible.

An advanced AB programmer such as yourself has the experience to know when a conditional subroutine is good practice and when it is not. If I came across a program that you had written using conditional subroutine calls, I suspect I'd probably look at it and agree that it was the best tool for the job, and that it's a good practice solution. If I came across the program written by our friend in the other thread you're referring to, where an output was staying on because of a conditional subroutine call, I suspect I'd probably develop a twitching eye and express the very strong opinion that this use of conditional subroutine calls is very bad practice.

Ultimately, my opinion on the subject is that a programmer should consider conditional subroutine calls to be generally bad practice, until they have enough experience with the platform to understand when they are and are not appropriate. It'll make for fewer headaches for both the programmer, and anyone else who maintains their code.
 
EDIT: "Someone" is always replying at the same "time" as me!(I started and then got called to something...what's new?)

To re-iterate what Ron is pointing out...





This ties in a little with what I was banging on about in relation to the "bits" hanging of the right-hand side of the Timer instruction...

For quick reference, if you look at my last screenshot above. When the rung-condition-in to the timer instruction is TRUE, what happens? The Timer instruction is ENABLED. Hence the EN bit will be set TRUE. The graphical representation links the output of the Timer instruction to the rest of the rung via its EN bit, as you can see. So, once the Timer instruction's rung-condition-in is TRUE, and the EN bit is TRUE, the Timer instruction's rung-condition-out is automatically TRUE, always.

This is where I was suggesting it would be more useful if we could tie the rung continuity to either the EN or DN bit on the right-hand side of the Timer instruction. This way we could choose whether we want a "passive" or an "active" Timer instruction, with regard to the rung-condition after the Timer.

Regards,
George


That sounds like an FB Timer in an RLL program. ;)

I agree though, it would be convenient.
 
I know full well that this isn't going to change anyone's mind about anything - especially about how convenient it would be for the software to allow us to "connect" to the [so called] "bits" on the TON instruction ...

but ...

if you're forced to explain what's really going on to someone who's desperately trying to get a handle on Ladder Logic - then the screenshot below has proven VERY helpful to me over the years ...

the main idea is that the little things that most people consider to be "bits" on the TON instruction are really just handy little "status flags" that reflect what's going on in the actual "bit/boxes" located in the processor's memory ... sort of like the indicator lamps on the dashboard of a car ... your oil pressure is too low - etc. ...

Rockwell doesn't take advice from me as to how they should design their software - but here's one way that I'd seriously consider handling this particular issue ...

party on ...
.

STATUS_FLAGS.PNG
 
Last edited:
Ron,

The only flaw to that is the convention that stuff to the left of the function block is inputs and stuff to the right is outputs. Inputs to a function block are thongs necessary to perform the function. Outputs from the function block are things that happen as a result of performing the function. Personally I would lengthen the block vertically, add the pass-through rail as you show but keep the EN, TT, and DN nodes on the right.
 
Ron,

The only flaw to that is the convention that stuff to the left of the function block is inputs and stuff to the right is outputs. Inputs to a function block are thongs necessary to perform the function. Outputs from the function block are things that happen as a result of performing the function. Personally, I would lengthen the block vertically, add the pass-through rail as you show but keep the EN, TT, and DN nodes on the right.

There are likely a dozen better ways to handle this better than the way the Logix 5000 / Studio 5000 software currently does but from Ron's screenshot the way Rockwell uses the enable flag to "tie" the instruction into the rung does confuse many students when trying to learn/understand the operation of the timer and when other instructions are after the timer it makes it even more confusing for people.
 
Greetings Steve ...

thank you – and I appreciate your comments ...

but - the point that I apparently failed to make clear is this ...

I only bring up this particular way of explaining what function the little doodads on the TON instruction perform – whenever it becomes necessary to talk about them ... and in many of my "boot camp" style classes this discussion never even comes up at all – so this is a "to be used only as needed" lesson ...

picture Monday morning – where the students have already entered about fifteen rungs of Ladder Logic code into their processors (we call that the "Walkthru" exercise) – and now we've moved into the "Talkthru" exercise where we go through the sample code rung-by-rung and explain how each piece of the puzzle works ... (TON timers; CTU and CTD counters; ONS oneshots; and so on) ...

usually the students who come into the class having ZERO previous experience have no trouble at all with those little gadgets on the side of the TON instruction ... I tell them that these are "status flags" like the indicator lamps on the dashboard of a car – and life goes on ... no problem ...

but ...

some of the students in the same class might have several years of previous PLC experience – and they tend to ask questions along these lines:

"but they're shaped like OUTPUTS" ...
"they're on the OUTPUT side of the rung" ...
"they turn GREEN-ON-THE-SCREEN like outputs" ...
and so on and on ...

all I'm interested in at this point of the class is getting past the "wrong" way of looking at these little status flags – and getting the focus back onto more important ideas ... consider that we've only got five days to cover a LOT of ControlLogix stuff – and even though those are twelve-hour days – we ALWAYS run out of TIME before we run out of STUFF ...

so ...

once I sort of "nail down" what the little flags are used for – then we can get back to more important ideas – and correct some of the common MIS-conceptions that some of these "years-of-experience" students have brought into the class with them ... such as:

green-on-the-screen means TRUE ... (that's WRONG!)
green-on-the-screen represents "power flow" ... (that's WRONG!)
an XIC instruction "Examines a switch for a closed condition" ... (that's WRONG!)
and so on and on ...

so ...

my purpose in posting my "here's something that works for me" explanation back in Post #23 was to give some guidance to "those who already KNOW" – when forced to explain the concepts to "those who DON'T know") ... this method has helped me over the last 30 years or so – and now that I've only got a few more classes to teach before I really do retire – I think I'll just stick with what I've proven to work ...

again – I appreciate your suggestions – and anyone who wants to use some of my methods but modify them to better fit their needs – then I wholeheartedly endorse that approach ...
 
Usual hair splitting commences! & sorry for the O.T....

My oh so subtle point is getting a little lost I feel in the middle of this. Now I'm not talking here about what any of us prefer. This is to do with calling something (pardon pun), in general or otherwise, a bad practice, which I feel strongly is not.

ASF said:
That's why I prefaced "very bad" with "in general". There are of course valid reasons to do so, but my post was aimed at the OP, who is clearly a beginner-intermediate AB user...

My good friend, general or otherwise, and whatever about the whole post, you did not qualify that particular statement I quoted as it being a "bad practice" if a novice uses it incorrectly. You qualified it with a particular programming error which you stated is a reason why you feel it is in general "bad programming practice". That statement in particular is what got my attention. It suggested to me that you were saying, similar to others, that it is always a bad practice and that no one should use it, not just novices. That is how it reads. My point is that it is not the fault of the method that it does not work, it is the fault of the programmer not using it correctly.

I always like the motoring analogies...

We do not say that driving is a bad practice. Dangerous yes. But not a bad practice in itself. We might say that novices driving unaccompanied is a bad practice. We might say that experienced drivers driving complacently is a bad practice. But the task of driving, in itself, is not a bad practice.

ASF said:
...I would recommend beginner-intermediate users avoid conditionally calling subroutines wherever possible...

You have now tried to further clarify your meaning and I agree "mostly" with the above. Advising novices to avoid using it is good advice in my opinion. But I would say avoid it until you are comfortable enough to start using it where it may suit the application. And not avoid it "wherever possible". That still sounds more like "avoid it like the plague"?

ASF said:
Ultimately, my opinion on the subject is that a programmer should consider conditional subroutine calls to be generally bad practice, until they have enough experience with the platform to understand when they are and are not appropriate. It'll make for fewer headaches for both the programmer, and anyone else who maintains their code.

I do wish you'd stop calling it a "bad practice", that is all my friend. It is not, in itself, generally or specifically, a bad practice. I am pinning that one firmly to the mast.

If I program using Function Block Diagram (FBD) tomorrow and I make some fundamental errors, which might cause me or others headaches, does that automatically make using FBD a bad practice? Surely not, I would say. The bad practice here, and here alone, lies solely, in my opinion, with the programmer implementing this method, which, in itself, is a perfectly valid and supported method of programming. If, by experience, many of us have found that several situations, where conditional subroutines were used, ended up with headaches abounding, then what does that tell you, honestly?

Parallel to the driving analogy...

I would say - It is bad practice for a novice or beginner programmer to use any advanced features, such as conditional subroutines, before they understand the fundamentals. That does not mean they should never use these methods. It implies that they should learn first, or if using now, thread carefully and be aware of the pitfalls that usually come with using any advanced feature.

I would also say - It is bad practice for intermediate or advanced programmers to use any advanced features, such as conditional subroutines, where they do not implement them properly, taking into consideration likely or known permutations that may result in adverse effects (headaches).

But, again, and under no circumstances, would I ever say that using conditional subroutines, which is fully IEC 61131-3 supported, is itself a bad practice, no matter who may use it.

Learn your trade people and don't blame the tools just because you are not qualified to use them.

At "some" point in the future, I would hope, this "3AM Bubba" we keep talking about will seize to exist, or at least dwindle out a bit. If we never train "some" of them and we keep "dumbing" it all down, then we are all stagnated. There will be a generational experience abyss. Train them or restrain them. Something else to ponder - what would we all do if the Standards in time decided that Relay Ladder Logic (RLL) is going the way of Instruction List (IL)? Would we all be trying to wrap RLL code in Structured Text (ST)?...
Code:
¦--I I--I/I---(Bubbastyle)--¦

This is why I do what I do here, and in detail. I want users to know what exactly they are doing so they can become proficient, and not just getting "something" done. But I want them to have the full toolset at their disposal, and in this case, I feel, that should include using conditional subroutines, whether now, or in the future.

So wherever I see it, I will strongly counter the practice of Forum members advising novices or others not to use this perfectly valid method of programming.

(Another pending pun...)

Calling all State Machines, rise up with me!

G.
 
....
Now consider the OTE and OTL instructions:
- An OTE scanned when the rung-in condition is TRUE will set a bit to 1, and set the rung-out condition to TRUE
- An OTE scanned when the rung-in condition is FALSE will set a bit to 0, and set the rung-out condition to FALSE
- An OTL scanned when the rung-in condition is TRUE will set a bit to 1, and set the rung-out condition to TRUE
- An OTL scanned when the rung-in condition is FALSE will do nothing to the bit, and set the rung-out condition to FALSE

I have to pick up on this as an incorrect interpretation....

None of the "output" type instructions set the rung-out condition to anything, they simply pass the current rung-in condition to the rung-out condition, without change.

Analysis of the above statements reveals they are essentially "correct", but it must be made clear that the "setting" of the rung-out condition to TRUE or FALSE is not performed by the instructions themselves, but by the fact that no "output" type instruction ever changes the current rung logic condition.
 
...the "setting" of the rung-out condition to TRUE or FALSE is not performed by the instructions themselves, but by the fact that no "output" type instruction ever changes the current rung logic condition.
Thanks daba. I thought that was the case (that there are no output instructions that do anything other than pass the rung-in condition to the rung-out condition) but I wasn't 100% certain, so figured I'd hedge my bets (y)
 

Similar Topics

Good day everyone. if you have a logic for 3 pumps (lead/lag/off), would you please email it to me? I really appreciate it!
Replies
7
Views
157
Looking to see if anyone has setup a ControlLogix Via Ethernet to a Omega Temperature controller CNi16D33-EIT-AL. Omega sent me an i-Server users...
Replies
0
Views
955
Can a ControlLogix PLC communicate over Ethernet using TCP/IP? I need to interface to an existing (proprietary) system, sending TCP/IP 'frames'...
Replies
12
Views
4,099
OK, (some of) you guys know by now that I'm not a PLC programmer, so I'm not really familiar with how a well-structured PLC program is typically...
Replies
2
Views
1,451
If I define an INT or DINT for, say ... a BitFlag word ... is there any way to name each bit in that flagword with a unique name? It would seem...
Replies
17
Views
3,860
Back
Top Bottom