One thing you might do is to build a sequencer where all the setpoints are in file N10: for example.
Say something like this:
Start the process
START DONE_LAST RUN
----| |----+----|/|--------( )
|
RUN |
----| |----+
Fill the tank to level
RUN +--- GEQ ---+ DONE_1
----| |----| LEVEL |-----+----( )
| N10:0 | |
+-----------+ |
|
DONE_1 |
----| |----------------------+
Run Mixer for a time
DONE_1 +--- MOV ---+
------| |--------+---------| N10:1 |
| | T4:0.PRE |
| +-----------+
|
| +--- TON ---+
+---------| T4:0 |
| +-----------+
|
| T4:0/DN DONE_2
+----| |-----------( )
... and so on....
Now you can set up a bunch of setpoints for your recipes, all stored in file N11:
Recipe #1
Level = 100 (N11:0)
Mix Time = 20 (N11:1)
etc...
Recipe #2
Level = 150 (N11:10)
Mix Time = 25 (N11:11)
etc...
...and so on ....
Now, you can use the Copy command to load your N11: recipes into the N10: "usage" file.
Without indirect addressing, you would do it like so:
+--- EQU ---+ +--- COP ---+
-----| N7:0 |-------| #N11:0 |
| 1 | | #N10:0 |
+-----------+ +-----------+
+--- EQU ---+ +--- COP ---+
-----| N7:0 |-------| #N11:10 |
| 2 | | #N10:0 |
+-----------+ +-----------+
... and so on....
With indirect addressing, you don't need one rung for each recipe. You've laid your data tables out so that everything is in groups of 10. Therefore you can calculate the offset, and do the copy in one instruction, like so:
N7:0 HAS A RANGE 1-x. N7:1 WILL HAVE VALUES OF 0, 10, 20, etc.
+---------- CPT ---+
--------| N7:1 |
| (N7:0 - 1 ) * 10 |
+------------------+
+------- COP ---+
-----------| #N11:[N7:1] |
| #N10:0 |
+---------------+
If you run out of data table space (if you have 20 recipes with 40 setpoints each) you can always indirect the file number instead. You could put Recipe #1 in N11:; Recipe #2 in N12, and so on. Then your indirect addressing would be of the type N[N7:1]:0.
Another advantage to this approach would be that you could use N[N7:1]:0 in place of N10:0 in the code above, N[N7:1]:1 in place of N10:1, ect.
Yet another way to do this is with index addressing. In indexed addressing, when the PLC encounters the '#' sybmbol in front of an address, it adds the value currently residing in S:24 to the base address to come up with a new address. That is, if S:24 has a value of 20, and the PLC encounters the address #N10:0 in an instruction, it will use the value stored in N10:20, not N10:0 in that instruction.
So using indirect addressing, you could rewrite the sequencer as follows:
Point to the correct recipe
+---------- CPT ---+
----+----| N7:1 |
| | (N7:0 - 1 ) * 10 |
| +------------------+
|
| +--- MOV ---+
|-----------| N7:1 |
| S:24 |
+-----------+
Start the process
START DONE_LAST RUN
----| |----+----|/|--------( )
|
RUN |
----| |----+
Fill the tank to level
RUN +--- GEQ ---+ DONE_1
----| |----| LEVEL |-----+----( )
| #N11:0 | |
+-----------+ |
|
DONE_1 |
----| |----------------------+
Run Mixer for a time
DONE_1 +--- MOV ---+
------| |--------+---------| #N11:1 |
| | T4:0.PRE |
| +-----------+
|
| +--- TON ---+
+---------| T4:0 |
| +-----------+
|
| T4:0/DN DONE_2
+----| |-----------( )
... and so on....
A few words of caution: Not all instructions allow the use of indirect addressing. The Bit instructions (-| |-, -|/|-, -( ) ) and timers/counters especially. Also, some instructions hijack S:24 for their own purposes - the COP, FLL, and anything which automatically use the '#' symbol.
The subject of Indexed, indirect, and recipe handling comes up here regularly. Do a search of the site and you should find more info if I haven't given you enough already.