How to simulate a FOR..NEXT loop?

New2PLCs

Guest
N
In a processor like the MicroLogix 1500 which does not have a built-in FOR..NEXT loop instruction (I've seen some web sites that indicate that some processors do have this instruction), how does one simulate this functionality? NOTE: I want to loop within a scan.

In the AB ML 1500 manual, I noticed in the section on shift registers it said something about using JMP, LBL and CTU to loop if you wanted to shift more than once per scan. But I couldn't figure out how to get those to work as a loop. I bet there's a way to get RSLogix to output the rungs of what I tried in ASCII so that I could post it, but explaining it might be easier. I just had a LBL on a line with a CTU and later, after the logic I wanted to loop, a JMP going back to the original label. To exit the loop, I examine the CTU done bit and jump to a label on the line after the other JMP instruction. Thanks,

-Don
 
You put the label earlier in the ladder logic than the jump instruction. The reason you need the counter is to make sure that you have a way to exit the loop. Getting stuck in an endless loop could have disastrous consequences, since the I/O aren't getting updated while the program is looping.

It's been my experience that there are very few places where it's a good idea to loop within a PLC program. When you're accustomed to programming in other languages, you tend to try to program the PLC using the tools that you already know how to use. I'm confident that there are ways to accomplish what you want to do without looping. Remember, the PLC already loops back to the beginning of the program without you having to do anything.
 
Use a LBL, and JMP backwards through the code. Initialize a "counter" before the LBL, and increment it through the JMP. Like this:


N7:0 IS THE I IN "FOR I=1 TO 20". SETTING THE COUNTER TO ZERO HERE MEANS THAT IT WILL START AT ONE ON THE NEXT RUNG.
+---- CLR -+
----------| N7:0 |
+----------+
<BR><BR>
INCREMENT THE COUNTER EACH PASS THROUGH THE FOR-NEXT LOOP.
Q:0 +-- ADD -+
--|LBL|--------| N7:0 |
| 1 |
| N7:0 |
+--------+
<BR><BR>
PUT WHATEVER CODE YOU WANT HERE. WITH INDIRECT ADDRESSING USE N7:0, OR SOME FUNCTION OF IT.
<BR><BR>
THE "NEXT" OF THE FOR-NEXT
+--- LES -+ Q:0
---| N7:0 |-----(JMP)
| 20 |
+---------+

 
Note that the CTU won't increment except on a false-to-true transition. You will need to force this in your loop by resetting the counter's enable bit - most easily done with an unconditional OTU.
The ADD instruction, as shown in Allen's example, does not require a transition.
Conditioning the (looping) JMP with the LES comparison or XIO of a counter done bit saves using more JMP's and LBL's. The counter's accumulator can also be used for indirect addressing.
 
Steve,

Read the thread entitled "Energy Management System". If you can show me how to program my final attack on the problem (in the last post from me) without looping, I will bow to you as PLC God. (If you can do it in any manner, you will rank as a minor deity in my book.)

Allen,

You know, I've was playing around with similar logic to do that without the JMP and LBL instructions, with each scan being on iteration in the loop. All I have to say to defend myself for not thinking of that on my own is "I'm a noobie!" :)

Gerry,

That's the missing ticket I needed for doing it with the LBL, JMP, and CTU instructions. I didn't see how to achieve the desired result in the way the AB manual mentioned. I guess it doesn't make much difference, but the way Allen suggested seems simpler to me and I'll probably use it. Thanks. :)

-Don
 
Indirect or Indexed addressing

Gerry said:
The counter's accumulator can also be used for indirect addressing.

Actually that is indexed addressing. In indirect addressing N7:0 would be initialized to the start of the array and the LES block should compare with the start of the array plus 20. In the above example, indirect addressing could only be used if the data or array start at 0.
 
Don:

As Steve pointed out, unless you have to have each compressor evaluated every scan, you don't need the for-next loop. If you can stand a slight delay (up to 500 msec), then take my code, delete the LBL and JMP instructions, and move the CLR instruction to where the JMP is.

On the first scan, N7:0 will be zero, until it hits the ADD, and the logic will be scanned using n7:0=1. On the next PLC scan, N7;0 will be =2, and so forth, until it hits 20, at when it will go back to zero.

Another method of not doing the looping is to use subroutines. You could create LAD 4 for the processing of any (N7:0) compressor, and then pass a number to N7:0 just before the JSR, like this:

+--- MOV -+
---+---| 1 |
| | N7:0 |
| +---------+
|
| +--- JSR -+
+---| U:4 |
+---------+
<br><br>
+--- MOV -+
---+---| 2 |
| | N7:0 |
| +---------+
|
| +--- JSR -+
+---| U:4 |
+---------+
<br><br>
et cetera



Not as elegant, perhaps, but it works too. This technique works better than For-Next if there are specific compressors that you DON'T want evaluated - disable the rung, and you don't execute the subroutine (which means that any outputs that the subroutine has enabled, remain enabled - something to be VERY careful of).

One more possible solution to your problem: Just what is the consequence of exceeding the load limit? Will a breaker trip, or is it just the cost of electricity? My energy bills always go up in summer, because i've balance the cost of electricity with the cost of comfort. I'm not saying to be intentionally wasteful, but if that MaxLoad is set in stone, there will be days when even the VPs get "hot under the collar" (pun intended).

You know you've got a no-win situation (unless you're lucky and a 50% duty time is sufficient for each compressor to keep everyone cool). At the very least, put the MaxLoad in a register, rather than a hard-coded number, so that you can (if needed) expose it to an HMI, and adjust it up if things just get too miserable.
 
Peter,

I'm not sure what you mean. What's the difference: you can initialize the counter's accumulator value just as you would N7:0, no? Would you mind explaining, please? Thanks,

-Don
 
Re: Indirect or Indexed addressing

Peter Nachtwey said:


Actually that is indexed addressing. In indirect addressing N7:0 would be initialized to the start of the array and the LES block should compare with the start of the array plus 20.

Indexed addressing manipulates S:24. To use indexed adressing, you would write N7:0, or the counter .ACC to S:24, and then reference any address with a '#' sign.

My example was "FOR i=1 to 20". If I had wanted, say 5 to 25, I would have done a MOV of 4 in the initialization rung, and a LES of 25.

In the above example, indirect addressing could only be used if the data or array start at 0.

In my original example, the array actually starts at one, not zero, because the pointer is incremented from zero to one on the next rung, prior to it being used in any addressing scheme.
 
Indirect or Indexed Addressing

Allen, I usually put my code before the increment so the arrays can begin at 0. Incrementing before the code does start the array at 1.

New2PLC. I dread explaining this. Let's say there is an array of compressor runtimes for four compressors at N7:101 to N7:104.

To sum the run times using indexed addressing:

clr N7:0 INDEX
clr N7:1 SUM = 0
lbl q:0 mov N7:0 S:24 LOAD INDEX INTO S:24 INDEX REGISTER
add #N7:101,N7:1,N7:1 SUM = SUM + ARRAY[INDEX]
add N7:0 1 N7:0 INDEX = INDEX + 1
les N7:0 20 JMP Q:0 IF INDEX < 20 THEN REPEAT

Notice the # in front of the N7:0. That means that S:24 is added to N7:101 to form the effective address

To sum the run times using indirect addressing:

mov 101 N7:0 POINTER = 101
clr N7:1 SUM = 0
lbl q:0 add N7:[0],N7:1,N7:1 SUM = SUM + [POINTER]
add N7:0 1 N7:0 POINTER = POINTER + 1
les N7:0 105 JMP Q:0 IF POINTER < 101

Notice the [ ] around the 0 in N7:[0] this means N7:0 contains the address or register number of the register you really want to access.
 
I agree with Steve and Allen. It is generally NOT necessary or a even good idea to use a for-next loop in ladder logic. Unlike high level languages, the very structure of ladder logic is desigend for evaluating repetitive logic, making for-next loops redundant. Besides, it is much easier to troubleshoot successive rungs evaluated once per scan than to troubleshoot the logic in a for-next loop where intermediate results are undoubtedly not accessible.

And, as many regulars here know, I firmly believe that good prgramming, by definition, must be easy to troubleshoot!
 
Peter,

I'm sorry, I should have made it clear that I know the difference between indexed and indirect addressing. Your first post still doesn't make sense (to me.) In his example Allen shows the structure of a loop and mentions using indirect addressing. Then, Gerry showed how to do it the way I originally asked about, using a counter, and says you can use the counter accumulator for the same type of indirect addressing functionality. Then you say it's really indexed addressing. Sorry to be so thick, but I don't see what you meant.

-Don
 
Don,
I think you've got a handle on the problem and know how to do what you want. This may have been a rare mis-fire on Peter's part.

As for the concept of 'dumbing down' your programs to supposedly make them easier to understand or troubleshoot, I am strongly opposed. Following this maxim, one would avoid not only loops, but indirect and indexed addressing, subroutines, etc. for fear of confusing the unwashed masses. And without the tools, one would avoid many potential applications. Rather akin to burning books. It is arrogant to assume that electricians are incapable of learning anything new or that they are not even interested. Besides, getting equivalent functionality to a 'banned' technique will more than likely be 'long-winded' and bug-prone and genuinely difficult.
 
New2PLC,
When I saw N7:0 set to 0 I assumed ( oops ) that Gerry really meant indexed as opposed to indirect address. Setting N7:0 allows one to access arrays or data using indirect addressing starting at 0 or 1 depending on whether the index is pre incremented or post incremented. I always start arrays at 0 and post-increment pointers or indexes because this is often more efficient than starting arrays at 1 in many cases where the array is a power of 2 long. In my narrow thinking, didn't consider the other options such as starting the array at 1 and pre-incrementing like Allen does. Oops again.
 
so For/Nxt loops are bad now?

I too believe and try my hardest to make programs easy to follow. I can't tell you how many times I have reduced multiple confusing rungs using redundant contacts down to 1 or two rungs of logic. It has been my experience however, that just using coils and contacts DOES NOT necesarily make a program easier to understand. IN FACT if I come across a FOR/NXT routine that is written correctly, I find it much easier to comprehend. Why, because a For/Nxt routine has boundaries. You can easily determine what the programmer was trying to accomplish by writing that section of code. The hardest part of reading programs written by others is not in figuring out how a rung of logic works, but trying to figure out WHY or WHAT the programmer was trying to accomplish by writing it. (Which is why I can't emphasize enough... that you should write comments explaining what you were trying to accomplish when writing a particular section of logic, rather then trying to explain that a false to true transition of B3/0 latches coil B3/30 and loads N7:0 into the FIFO stack N7:[N8:0] where N8:0 is the pointer into the indexed array. If I want to understand how an instruction works, I'll look it up in a book. TELL ME WHAT YOU WERE TRYING TO ACCOMPLISH!!!

Excuse me, I was just venting there for a second. Probably all of the Heinekens. But seriously, you will find that a section written with a FOR/NXT loop may appear difficult at first, but you will come to long for them after trying to decipher a program that is badley written with all XIO XIC OTE instructions where 80% of the contacts or coils will never come in to play.

One example of a good use for For/Nxt loops is to replace the god awful AB file intstructions like the FAL, FSC, and FBC that only operate every other scan. A For/Nxt loop is awesome for this. And since I am venting..... What in the hell was Rockwell smoking when they created the average (AVE) instruction.
 

Similar Topics

Hi there, I'm doing some extensive testing and commissioning with a slew of new Emerson PACSystems RX3i PLCs. It would be convenient to...
Replies
5
Views
80
Hello, I have a small application with a S7-1200 CPU 1212 and a KTP400 Basic HMI. When i am connected to the PLC with my PC i would like to...
Replies
1
Views
515
Hello everyone, i would like to test and run os server in pcs7 v8.2 project without rear PLC.i used plcim on ES and nettoplcsim and adjust the...
Replies
4
Views
1,302
Hi all, Im new to Allen Bradley software, so i was given a existing studio 5000 plc program. i already know how to use emulator and rslinx but as...
Replies
2
Views
1,362
I want to run a simulation of a program uploaded from a rockwell PLC, but I can't configure the CPU on the emulate to match the actual CPU.
Replies
10
Views
2,147
Back
Top Bottom