Host Engineering Forum
General Category => Do-more CPUs and Do-more Designer Software => Topic started by: Mike Nash on March 11, 2017, 08:50:50 PM
-
So far, my attempts at using the new subroutines have failed due to my wanting to put instructions there that are not compatible. Is there a list of instructions that won't work properly or at all in subroutines?
I am wondering if there is a better way to setup to do Modbus RTU read/writes to a large number of devices than an equivalent large number of MRX and MWX instructions and their associated elements. I am up to over 4000 documented elements and probably will have more to add as I get this firmed up.
Just for grins, lets say there are 50 devices (split over a pair of H2-SERIO-4s but just Port C on each SERIO is used.) That gives me 50 MRX and 50 MWX at a minimum. I don't think I see a way to use a single pair (times 2 for dual SERIOs) and index the parameters. The instructions actually do allow me to use indirect addresses for all but the success and error bits, but would it be legitimate to increment a pointer each time the success or error bit changes state?
I have already entered all of the preliminary descriptions and rungs at this point, but find I am wanting to modify some things and this means doing it manually 50 or 100 times. So is there an easier methodology with the current firmware/software (2.0.2/3)? I am not going to STAGE this simply because the actual rung count would grow a bunch and I am still up in the air on whether I find it more or less intuitive with STAGE.
The only interlocks I have are actually just "He's dead, Jim" 's so I skip them for xx seconds and then try again.
I don't want to make it hard to decipher for anyone following later though. The multiple instructions are pretty easy to understand.
-
Well, just playing in the simulator so I haven't gotten to actually try this part real world yet, but it looks doable. Indexed timers with indexed rung conditions aren't recommended! Indirect PD contacts get me a warning, but seem to work. Replacing it with a contact and Leading Edge Powerflow Modifier works with no warnings. The timer can get replaced with saving $UTC at edge and then MATH box IF'ing that with current $UTC for what I need.
So far it's looking more like 7 rungs PER SERIO for MRX and a few less than that for MWX since they share the Dead Jim handling. This versus 4 rungs PER MRX device address and 1 more PER MWX address.
It's a little less intuitive though. I did create some descriptively named memory blocks for the indexed status/control bits since the HMI won't need these.
-
Indirect PD contacts get me a warning, but seem to work. Replacing it with a contact and Leading Edge Powerflow Modifier works with no warnings.
Are you doing this using arrays to do edges? If so, edge transitions are not going to behave like you think. This is because the hidden edge state bit is NOT indexed like the element is. However, you can create your own EDGE BIT data block EB and array index those and do edge contacts by hand.
// Is X ON THIS scan, but was OFF LAST scan EB, turn on C bit
STR X[V0]
ANDN EB[V0]
OUT C[V0]
// Save off state of X into EB for NEXT scan
STR X[V0]
OUT EB[V0]
-
Indirect PD contacts get me a warning, but seem to work. Replacing it with a contact and Leading Edge Powerflow Modifier works with no warnings.
Are you doing this using arrays to do edges? If so, edge transitions are not going to behave like you think. This is because the hidden edge state bit is NOT indexed like the element is.
Yet it seemed to work. I am NOT looping however. This is all in MAIN and runs each rung in sequence. An index value is incremented and reset as needed, but only once per scan at most.
But I played some more with test logic and it does fail to work as anticipated at times. If I lock a bit on {V10=13 C[V10] C13 held true} then C14 is the bit that the LEPfM thinks is never changing although it is. This could certainly cause issues.
-
If you did all this in its own program code block and set all the V array indexes before the RUN, and EXIT when done, and monitor the program's .Done bit, you could use PD contacts in that program. Then set the V array values for the next RUN from $Main, looking for .Done, ...
-
If you did all this in its own program code block and set all the V array indexes before the RUN, and EXIT when done, and monitor the program's .Done bit, you could use PD contacts in that program. Then set the V array values for the next RUN from $Main, looking for .Done, ...
After getting all the rungs entered (did I really do that on my own time?!), I most likely will leave them as discrete instances. But if I have time with the hardware before it has to ship I hope to try an indexed version. Big if there on the time as always.
So which approach would be the snappiest? The scan time was already at 1.8mS before I even added all the add'l timers and success/fail counters (diagnostics). Granted this is not slow, but would indexed (NO loops) be faster due to reduced rung count or would the indexed elements make it a wash? Or?
I will not want to do it if it is too difficult to troubleshoot later on. I do like the layout you suggest.
-
If you did all this in its own program code block and set all the V array indexes before the RUN, and EXIT when done, and monitor the program's .Done bit, you could use PD contacts in that program. Then set the V array values for the next RUN from $Main, looking for .Done, ...
I am not getting the hang of this at all. .Done is a tricky, tricky thingy, and so is RUN. I have attached a screenshot of my attempts to understand this.
1) If a Program has RUN at all, I cannot get it to restart using it's own .Done bit (program to run transition) because .Done is already on and I don't find any way to force it off. Hence the C0 logic in $Main Rung 3. C0 must be off to on for me to get TestProg to run again.
2) Similar issue in that .Done will never be seen as transitioning off to on if TestProg makes only one pass and exits. This is why TestProg Rung 2 has to be 2 scans to exit.
3) I don't see why I get D0 incrementing 3 for every 2 increments of D1. I have moved the RUN rung from the top of $Main to the bottom with no difference. The way I am reading the help, I think I should be scanning TestProg just as often as $Main but obviously it does not. Can someone straighten me out on the scan sequence there? I'm sure it has to be the EXIT but... My thinking is the EXIT should make the .Done true for the next $Main scan (because it had to go false after the first scan of TestProg) so it should just fall right in and run again, but it must not be. Stage gives me similar headaches.
Thanks.
-
I will study when I have some time, but Stage is your friend. Seriously.
-
I will study when I have some time, but Stage is your friend. Seriously.
Maybe I am just not responding to "tough love". I have a suspicion that whatever I am not seeing with the above example is related to my "Stage fright".
I do have a program running a machine using Stage, but it was more of a struggle than I liked.
-
Maybe I am just not responding to "tough love". I have a suspicion that whatever I am not seeing with the above example is related to my "Stage fright".
Put the RUN immediately following a SG instruction, with no input logic. On the next rung following the RUN, use the .Done field to drive a JMP. The JMP can take you to another stage that will decide whether to run the program again (by jumping back to the stage with the RUN) or the JMP can jump right back into the stage you are already in (which will re-run the program). It'll work like a hose.
I do have a program running a machine using Stage, but it was more of a struggle than I liked.
DL stage or Do-more stage?
-
Elaborating a bit more: whenever I find myself struggling to rearm something edge triggered, Stage always cures it. Maybe you don't think of such things as sequences, but they really are. You fire them, wait for an unknown time for completion, determine whether you want to run again, and repeat.
The reason I asked about DL vs Do-more on stage is that I think that DL stage can cause more trouble than it's worth. Stage is a tool. When it's the right tool, there is nothing better. Do-more's stage implementation allows you to use it only where it makes sense, but DL tends to be more all in. In Do-more I almost never use stages in $Main, but frequently do in program blocks. Even then, only when it's the right tool.
-
I will skip the quotes. I have only used Stage in Do-more. It never seemed a good fit in my apps in DL.
I have to retract my statement anyway. I have not yet used it in a running machine. I have it running in a Do-more on my desk to do ASCII comms to a device.
I still don't follow the scan timing in my previous example.
I have attached another go at understanding this. The three possible choices for the EXIT are selected by C1, C2 OR C3 exclusively. C1 or C2 result in a D0/D1 result of 2.0 while C3 results in 3.0 - both are fewer increments than the 1.5 ratio of my Stage-less version. I'm not even sure why C3 works at all as it didn't without the Stage.
I also had it hang and fail to execute TestProg once after the switch to Stage, but I could not duplicate it. This is one of my hesitations.
Granted, I am doing something here that is not it's intended purpose (expecting it to execute TestProg every scan and increment) but I need to know WHY it does or doesn't work.
I suspect a subroutine would do exactly what I expect here, but the MRX, MWX are not welcome there so I would like to "get it" and be comfortable with the alternatives to straight ladder.
And on the edge triggered? CTAX... instructions gave me fits last year mostly due to failing to allow the instruction to complete before executing another (or the same one again). Lots was due to not figuring out the run to completion requirements along with the edge triggering, but maintaining, but... (Frankly I don't recall all the things I got hung on at the time. Our new BX-DM1E-36ED23 is in, but no time to play with it yet.)
Thanks for the help!
-
I'm hearing two conflicting things: "every scan" vs asynchronous instructions like CTAXnnn and MRX/MWX. I'm confused about what you are wanting to do. If you want something every scan, use a subroutine. The reason certain instructions aren't allowed in subroutines is because they can't complete in a single scan. Since they are async, they need time to complete, and I'm showing you good techniques for managing that.
As for allowing completion of stuff in stages, that's why the stage transitions on Complete and Error are built directly into the async instruction. Use them and we do the work for you. That's essentially what I'm simulating with the RUN and .Done logic, which works beautifully. I know it does seem like tough love, and I'm really sorry. We harp on this ad nauseum...but when you use them like we intend, they work very well.
I wouldn't worry too much about the one-off failure you can't dupe. The ISG initialization needs a program to run transition, and I've confused myself a dozen times over stuff like that. One of the reasons I like to limit stages to outside $Main is that it ensures that proper initialization occurs when the program block is run. If for some reason I get the program block out of shape during development, I either use a HALT or kill it from the Project Browser.
-
Just so you know there are no hard feelings, I have a functioning, indexed (not looping), dual SERIO Modbus RTU, built with programs running programs with Stages everywhere except $Main. And I did it on a Saturday for the educational value (since the discrete one was mostly done.)
I may never love these things (Stages), but considering the asynchronous instructions are "designed" to be used with Stage, I reckon I am going to have to learn to live with them. Yes, yes I can be stubborn to the point of my own detriment.
Scan time appears to be around an eighth of the time in the all discrete MRXs and MWXs version. There are 1/20th as many of each instruction. I won't know until all the slaves are up and talking (rather than just the one with the rest sitting in "time out" mostly) what the scan time will ultimately be. Understanding the indexing is harder, but editing time to add or change a feature is massively less.
And did you know a SETUPSER in the first rung of $Main wins out over any configs done in System Configuration or Dashboard? That took me awhile to find, after which I remembered putting it in the very first thing when I started. The Dashboard has quickly grown on me - I like it.
I would still like to know in the screenshots I posted previously WHY the counts increment as they do. At this point it is curiosity because it shows me I don't understand what is happening and there are no asynchronous instructions involved there.
-
They aren't really designed for Stage, per se. They are designed to accommodate the special needs of async operations in sequential programming (with and without Stage), while Stage was designed to provide a good method for sequential programming. Used collectively, they work very well, and make most of the junk just disappear.
And that's the key. It works.
There is no right or wrong answer as long as you get it to work right. I only push this because I want you to have the very best experience with Do-more. As I have said many times: It's ADC's job to get you to buy the first Do-more PLC; it's my job to make sure you buy the second.
Looking at your program now...
-
Messes with your head a bit, but it's correct.
When either of C1 or C2 is selected, the EXIT will execute after two scans. Then a couple of scans of overhead to terminate and then rearm. So each execution takes 4 scans, and will have run 2...4/2=2.
When C3 is selected, the EXIT will execute after 1 scan, with the same 2 overhead scans...3/1=3.
-
Messes with your head a bit, but it's correct.
When either of C1 or C2 is selected, the EXIT will execute after two scans. Then a couple of scans of overhead to terminate and then rearm. So each execution takes 4 scans, and will have run 2...4/2=2.
When C3 is selected, the EXIT will execute after 1 scan, with the same 2 overhead scans...3/1=3.
Thank you Bob. I did not suspect overhead scans. Even knowing this, it is still messing with my head trying to step through it on paper. I would want to single scan or fill a table or something just to "see" this. The location of the R0 calculation doesn't help. As enough counts accumulate it all averages out, but I had noticed R0 seemed erratic when first started.
I'm getting little warnings in my head now about how I need to get a better handle on programs, tasks and subroutines. Tasks and subroutines actually feel a lot "safer" at the moment. I expect a subroutine to come right back with its results and tasks to get done whenever they are good and ready, especially if yielding comes into play. I will need to be more careful in my considerations of programs running other programs.
-
Programs and tasks are essentially the same thing. Only difference is how they start and end, and programs can have stages.
The overhead scans are related to termination of the stage and of the program block. Termination is the magic that makes those pesky interlocks work right. And tasks terminate too, btw.
-
The overheads are fine, they just caught me out while trying to understand why the .Done was retriggering the RUN. And that came about due to:
If you did all this in its own program code block and set all the V array indexes before the RUN, and EXIT when done, and monitor the program's .Done bit, you could use PD contacts in that program. Then set the V array values for the next RUN from $Main, looking for .Done, ...
And lo and behold I stumbled across this thing called Stage Programming and it all came together and just worked! ;D
-
I am a big fan of Stages as well as Programs/Tasks.
A helpful little tidbit is if you right-click in the project browser and then select sort>>Code-blocks>>Sort by execution order. This allows you to see the blocks in the order that they will actually execute. When Main executes a RUN to another program block, it will execute that block when it gets to that blocks 'slice' of the scan time. There may be other blocks before it, and there may be other blocks after it. If the result of the program/task block is needed for another instruction, then I always use stage programming. It works great for monitoring exactly when I call the block, and knowing when it gets done.
BTW the .doneThisScan (sometimes with a NC) is another very useful tool for edge triggering.
Another thought on stages that can make them *seem* unpredictable. If you JMP forward, then that stage will execute in the same scan, but if you JMP to a previous Stage, then it will not execute until the next scan.
Also, in you screenshot you have a JMP to stage 0 inside of Stage 0. ;)
EDIT: I corrected my comment about JMP to a previous stage as noted by franji1 in the next post. Thanks franji1! :)
-
but if you JMP to a numerically lower Stage, then it will not execute until the next scan.
Just a quick mention that stage numbers do NOT have to be increasing, or even sequential, so the condition for it executing on the NEXT scan is based on the location of the Jumped-to SG PREDECING the JMP instruction. You could have
SG S100 // initial stage
JMP S0 // enables S0, disables S100, but remainder of S100 logic will still finish executing THIS scan
... // WILL execute THIS scan (because JMP does not physically JMP, so the logic BELOW the JMP S0 still executes THIS scan)
SG S99 // not enabled on THIS scan, so does not execute this scan
JMP S100 // ditto
... // ditto
SG S0 // executes THIS scan due to JMP S0 above inside S100 enabling S0
JMP S99 // enables S99, disables S0, so S99 will execute on the NEXT scan, regardless that its number is higher than the current S0
-
Also, in you screenshot you have a JMP to stage 0 inside of Stage 0. ;)
... or the JMP can jump right back into the stage you are already in (which will re-run the program).
I was pretty sure someone else had suggested this one. ;)
Does anyone remember playing "Mother May I?" It comes to mind with this stuff.
-
Also, in you screenshot you have a JMP to stage 0 inside of Stage 0. ;)
... or the JMP can jump right back into the stage you are already in (which will re-run the program).
I was pretty sure someone else had suggested this one. ;)
Does anyone remember playing "Mother May I?" It comes to mind with this stuff.
I missed that somehow. I have never used that trick before... Thanks!
-
And lo and behold I stumbled across this thing called Stage Programming and it all came together and just worked! ;D
You said stumbled, but the picture in my head was you having your shoelaces tied together, and being placed in dark room surrounded by boxes of Stage programming. ;) Sorry.
Maybe someday you'll use it because you like it, but as long as you get good results with whatever you choose, I'm happy.
-
Closure. The system is packed to ship and works great. Managing to read and write each device 1-2 times per second for 24 Modbus RTU devices. I was just using the slope instruction on successes with 1 second sample time and only using integers, so no exact number here. That's just one serial network, there is another running too, though with fewer devices. That's ALL devices serviced every second for 24 + 16 devices.
I was sad when the scan time hit 1.0 mS after adding all the discrete logic ladder to the indexed Modbus routines which were around 500uS scan. It bumped to 1.1mS with two Ethernet HMIs and a laptop running DmD.
And yes it does have Stages.
8)
-
Awesome. Glad it's working well.
1.1ms is hardly the end of the world, but if you have any lengthy sections of logic, you could put them into a task and insert YIELD instructions to break up the execution.
-
I was actually surprised how much the coms update rate dropped just doubling the tiny scan time. When I only had one "device" active and all the rest disabled in logic I could hit 12 times per second (tps) read/write. Adding the "digital" logic always active dropped that to 8 tps. Considering it is now 24+ tps per network with multiple "devices" all active, I'm really pleased.
I tried yielding, but there weren't any For-Nexts or goto's, etc., so it made no difference I could tell. I did find the ability to suspend the various programs execution informative.
I am quite happy with the results. There were over 240 multi-branched rungs for the logic section with 40 timers, etc. I considered indexing (not looping) these also, but felt troubleshooting would be more difficult and 40 mS to update logic status per device didn't appeal to me either.
And the 1.1 mS sadness :'( was tongue-in-cheek. :D It was just pretty amazing to see 511 uS scan time for the serial coms only.
-
And the 1.1 mS sadness :'( was tongue-in-cheek. :D It was just pretty amazing to see 511 uS scan time for the serial coms only.
I thought so. As a designer, I'm always thinking faster, but the ADC techs love to remind me that I'm way out there compared to what customers need and expect.