ST Guru's I need help here

TheWaterboy

Lifetime Supporting Member + Moderator
Join Date
May 2006
Location
-27.9679796,153.419016
Posts
1,940
I am trying to Insert a value into the Total register of an already running totalizer. I can do it one step at a time in the tag database but I am trying to automate it for a single button press from the operator.
Here's the Totalizer
tot dia.jpg

Here is the trigger bit from the operator that would call the ST
trigger bit.jpg

Nothing too weird so far.

Here is the ST called "ResetCurrentTotalizer" I am trying to make work
Code:
// Intent...
// Copy .OldTotal to storage location
// Insert Specified Value into .Total
// .ProgResetReq will move .Total into .OldTotal so need to put .OldTotal back
// then Reset all the control bits


//Capture OldTotal
	ST_Var1:=JunkOldTotal;
(*
REPEAT
//Write to Totalizer Reset Value Register
	JunkTotalizer.ResetValue:=JunkResetValue;
//Assert Reset bit - Writes JunkResetValue Value to .Total
	JunkTotalizer.ProgResetReq:=1;
UNTIL JunkTotalizer.ProgResetDone
END_REPEAT;
*)
//Write Old Total back to totalizer
	JunkTotalizer.OldTotal:=ST_Var1;
//Clear the Reset Requests
	JunkProgResetReqST:=0;
	JunkTotalizer.ProgResetReq:=0;
//Increment a test counter
	JunkST_Runs:=JunkST_Runs + 1;

After failing to make it work in FB I tried ST. I have played with several iterations of this, the above being my last for today, and while this is not the example, I can get the total to reset to a specified value but can't re-populate the .OldTotal back to what it was.

This last piece of code using REPEAT... UNTIL faulted the processor so its obviously looping and not the answer.

I can't walk through the ST and the watch window doesn't work on this version of firmware (17.2) anyway (Grrr)
 
So even though I call JunkTotalizer constantly in the main code, I have to call it within the Repeat section because the Repeat is the ONLY thing running?

I just re-read read the book which states that the controller does not execute any other statments until the loop is completed, but I didnt consider that it wouldnt call the totalizer code. I guess it is serious about not executing ANYTHING else.

The book also says I should consider using IF...THEN instead, likely for this very reason, but I couldn't see how to make that construct work in this case.
 
Still Need ST Guru . . .

Still no Joy. the reason it faults now is that I cant get the ProgResetDone bit to go true.
I placed the first three lines of the REPEAT above the REPEAT as a test and still failed.
The Loop watchdogs out if it relies on the .ProgResetDone bit so I added the counters to break it out sooner.

Shouldn't I be able to manipulate the totalizer like this? What else am I missing here?

Code:
[SIZE="2"]//Goal: Input an operator specified value into a running totalizer "Current Total"
//Copy .OldTotal to storage location
//Insert Specified Value into .Total
//.ProgResetReq will move .Total into .OldTotal so next I need to put .OldTotal back where it was.
//Reset all the control bits

ST_Var1:=JunkOldTotal;//Capture .OldTotal into register for later use.

REPEAT
    JunkTotalizer.ResetValue:=JunkResetValue; //Write to Totalizer Reset Value Register
    JunkTotalizer.EnableIn :=0;	//Disable Totalizer (Didn't help) 
    JunkTotalizer.ProgResetReq:=1;  //Assert then Clear Reset bit - Writes Reset Value to .Total
    JunkST_Loops:=JunkST_Loops + 1; //Diag Counter
       IF JunkTotalizer.ProgResetDone THEN
           JunkST_DoneLoops := JunkST_DoneLoops + 1; // ZERO Done loops recorded - Totalizer Reset is never going done.
        END_IF;
    JSR (_Totalizers_and_Scaling); //Jump out to totalizer Function block and rescan
UNTIL JunkST_Loops > 1900 //about 800 ms	//Used this instead of line below to prevent faulting processor while waiting. 
//JunkTotalizer.ProgResetDone //Reset Complete, Exit Loop <<< This Never Happens
END_REPEAT;
    JunkTotalizer.ProgResetReq:=0; //Clear initiating Bit
	JunkProgResetReqST:=0;//Clear the Reset Requests
	JunkTotalizer.OldTotal:=ST_Var1;//Write Old Total back to Totalizer
	JunkTotalizer.EnableIn :=1;	//Restart totalizer ( Needed?) 
	JunkST_Runs:=JunkST_Runs + 1; //Diag Counter[/SIZE]
 
In post 1 "JunkEnable" is =0 and tied to EnableIn.
Maybe JunkEnable needs to be kept high and then the direct reset of the EnableIn flag in the ST prior to the FB call will get the transition you need.
I've not worked with the TOT instruction much, but it looks like what you have should work on just one iteration.
I'll try to recreate this on my test logix rig tomorrow. Is this Control or CompactLogix?
 
ProgOper set

From what can tell, you need to have the ProgOper bit set in order to get the ProgResetDone bit to turn on and complete the process. If you do not set the ProgOper bit then the ProgResetDone bit will never get set.

This information is found in the instruction help.

Resetting the TOT Instruction
When ProgResetReq transitions to set while ProgOper is set, the following happens:

OldTotal = Total

Total = ResetValue

ProgResetDone is set

If ProgResetReq is cleared and ProgResetDone is set then ProgResetDone is cleared

When OperResetReq transitions to set while ProgOper is cleared, the following happens:

OldTotal = Total

Total = ResetValue
 
Last edited:
Modified and working

Here is a copy of your code that I have modified and verified that it functions without errors.
Code:
// Intent...
// Copy .OldTotal to storage location
// Insert Specified Value into .Total
// .ProgResetReq will move .Total into .OldTotal so need to put .OldTotal back
// then Reset all the control bits


//Capture OldTotal
	ST_Var1:=JunkOldTotal;


//Write to Totalizer Reset Value Register
	JunkTotalizer.ResetValue:=JunkResetValue;
//Assert Reset bit - Writes JunkResetValue Value to .Total
	JunkTotalizer.ProgOper:=1;
	JunkTotalizer.ProgResetReq:=1;

//Write Old Total back to totalizer
	If JunkTotalizer.ProgResetDone then
		JunkTotalizer.OldTotal:=ST_Var1;
		//Clear the Reset Requests
    	JunkTotalizer.ProgOper:=0;
		JunkTotalizer.ProgResetReq:=0;
		//Increment a test counter
		JunkST_Runs:=JunkST_Runs + 1;
		JunkProgResetReqST:=0;
	end_if;
 
Last edited:
Code:
// Intent...
// Copy .OldTotal to storage location
// Insert Specified Value into .Total
// .ProgResetReq will move .Total into .OldTotal so need to put .OldTotal back
// then Reset all the control bits


//Capture OldTotal
	ST_Var1:=JunkOldTotal;
So far so good, you recorded the old value

Code:
REPEAT
Oh no. You must not be familiar with loops. For loops are the safest, While and Do-While are dangerous (REPEAT is a Do-While). It is exactly as if you copied and pasted everything in the loop over and over an infinite number of times making an infinitely long routine. When the UNTIL condition is true, it finally jumps out of the loop. If that doesn't go true in time, the PLC will fault out.

I can tell you right now, there is no reason to be looping a single function, you would loop if you had JunkResetValue[100] and didn't want to copy and past the code 100 times, and then you would use a FOR loop that specifically cycled through 0 to 99, not a REPEAT loop.

Code:
//Write to Totalizer Reset Value Register
	JunkTotalizer.ResetValue:=JunkResetValue;
//Assert Reset bit - Writes JunkResetValue Value to .Total
	JunkTotalizer.ProgResetReq:=1;
UNTIL JunkTotalizer.ProgResetDone
You never call the JunkTotalizer function. The PLC is stuck in this loop, it isn't running your other code. ProgResetReg may be true, but it isn't going to make ProgResetDone go TRUE without JunkTotalizer();

Even with JunkTotalizer(); being called, many functions actually execute acyclically after the program finishes going through the code and before it starts from the top again. There is no guarantee that calling the function in the loop will actually cause the function code to run.

Even if calling the function did cause the function code to fire while still stuck in the loop, if the function takes too long to finish, it will trip the PLC's watchdog timer.

In short, you should be using an if statement, not a loop.
Code:
END_REPEAT;

//Write Old Total back to totalizer
	JunkTotalizer.OldTotal:=ST_Var1;
//Clear the Reset Requests
	JunkProgResetReqST:=0;
	JunkTotalizer.ProgResetReq:=0;
//Increment a test counter
	JunkST_Runs:=JunkST_Runs + 1;
None of this stuff will ever happen, because you are forever stuck in the loop waiting for a Done bit that will never go true until the PLC watchdog faults out.


What I would do:

Code:
IF(JunkProgResetReqST) THEN
    ST_Var1:=                         JunkOldTotal;
    JunkTotalizer.ResetValue:=  JunkResetValue;
    JunkTotalizer.ResetReq:=    1;
    JunkTotalizer();

    IF(JunkTotalizer.ProgResetDone) THEN
        JunkTotalizer.ResetReq:=    1;
        JunkTotalizer.OldTotal:=     ST_Var1;
        JunkProgResetReqST:=       0;
    END_IF
END_IF
 
Thanks to all , lots to absorb here . . .

bmacattack33
Maybe JunkEnable needs to be kept high
The enable bit is held high always. If memory serves, I had it disabled there because of the fault that was occurring (and the straws at which I was grabbing.)
This is on compactlogix l32E


gscure
Code:
JunkTotalizer.ProgOper:=1;
^^^.ProgOper is an OUTPUT from the totalizer. How are you able to SET that bit?

CapnWincky
Yea, I was warned about the REPEAT. Just as the code at the bottom of this post, I just couldnt make it work with an IF. Rookie mistake not to put a loop exit in there like I did after finding the fault cause.

You never call the JunkTotalizer function
sure I did, Inside the loop to make sure I kept looking for the FB to process.
Code:
REPEAT
...     END_IF;
    JSR (_Totalizers_and_Scaling); <<<< RIGHT HERE
UNTIL JunkST_Loops > 1900

Code:
JunkTotalizer.ResetReq:=1;
^^^^You mean ProgResetReq ?

Code:
JunkTotalizer();
^^^^What will this do? My editor wont accept it

Code:
IF(JunkTotalizer.ProgResetDone) THEN
JunkTotalizer.ResetReq:=    1;
^^^^You Mean 0 ?


Based on suggestions this is the current code that does not yet work. I couldn't use CapnWincky example since the editor didn't like the line mentioned above.
the code makes sense logically and is likely what I started with but it has no effect. It doesn't error, just doesn't do what is says it should.
ST_Var1 gets filled but JunkProgResetReqST never clears and the totalizer never receives the new value into .Total.
Code:
//Capture .OldTotal into register for later use.
	ST_Var1:=JunkOldTotal; 
//Write to Totalizer Reset Value Register
	JunkTotalizer.ResetValue:=JunkResetValue;
//Assert Reset bit - Writes Reset Value to .Total
	JunkTotalizer.ProgOper:=1;
	JunkTotalizer.ProgResetReq:=1;  
If JunkTotalizer.ProgResetDone Then
//Write Old Total Back to Totalizer
	JunkTotalizer.OldTotal:=ST_Var1;
//Clear the Reset Request Bits
	JunkTotalizer.ProgOper:=0;
	JunkTotalizer.ProgResetReq:=0;
	JunkST_Runs:=JunkST_Runs +1;
	JunkProgResetReqST:=0;
End_If;
 
Destructive

TheWaterboy,

^^^.ProgOper is an OUTPUT from the totalizer. How are you able to SET that bit?

It is an output but it is a destructive bit. Since it's destructive you have the ability to change the state. I would only manipulate the bit state in this matter to fit the scenario that you have posted. Normally I would do a check to see if it was in this state to be able to perform the function. If it was not then I would write code to set it with an input from the program or the operator.

Given that you wanted the code to function automatically without user input then I wrote the code to fit those parameters.
 
Sorry, I'm not familiar with how Rockwell's ST executes functions and I assumed it would be the same way other VxWorks platforms did it. Instead of
Code:
JunkTotalizer();
use
Code:
TOT(JunkTotalizer);
That is what calling the function means; JunkTotalizer is an instance of the TOT function, and you have to call it after setting ProgResetReq and before checking ProgResetDone or the function will never process the request.

Also, yes, I meant
Code:
JunkTotalizer.ResetReq:=     0;
 
It is an output but it is a destructive bit.

Destructive yes, but what I don't understand is the role it plays in the totalizer function. I was sure it was purely to indicate the mode the Totalizer is in.

Does setting and clearing that bit really have an affect on the totalizer itself?
 
I'm pretty sure the the totalizer instruction wasn't directly scribed into the processor hardware by the hand of the almighty. Why not write your own AOI that does what you want it to do?
This is the reason I write my own PID functions and use my own state machine construct instead of a sequencer or shift instruction. I got tired of spending all my time figuring out how to make instructions do what I wanted them to do and not spending time getting my machine to do what I wanted it to do.

Keith
 
I'm pretty sure the the totalizer instruction wasn't directly scribed into the processor hardware by the hand of the almighty. Why not write your own AOI that does what you want it to do?
Keith

I like how they work normally and they are so easy to implement, but I am trying to do something to that that was not intended and you know how the Almighty gets when you go against the plan.

I'm wondering today if the SCOPE of the totalizer has any impact on this. Its Program Scoped and all my ST is in the same program. But I know you can't access it's elements from outside, even using the extended path. It has to be Controller Scoped to reach it from the outside. Maybe ?
 
Originally posted by TheWaterboy:

It has to be Controller Scoped to reach it from the outside. Maybe ?

I don't think so. As long as the ST is in the same program as the tag is scoped you should be able to do whatever you can do to it. More likely:

Originally posted by TheWaterboy:

...but I am trying to do something to that that was not intended...

That is probably the ticket. Since you aren't allowed to look under the hood you really don't know if there are any protections against any given effort. It is quite possible you just can't do what you want to do.

Keith
 

Similar Topics

Do any of you Excel gurus know of a VB code or function that will convert ASCII text into it's decimal equivalent? I'm not VB savy at all. I...
Replies
3
Views
5,859
R
I haven't mentioned this because I thought this forumn was strictly plc, but thank gosh it's not.... Currently I have 2 weg motors (400hp...
Replies
50
Views
23,977
Ok first off, i have uploaded the PLC program in a zip file, plc is a control logix. The issue i'am having is in a routine called (rtn_Pumps) i...
Replies
39
Views
10,944
I have a linux server (on prosumer hardware), debian stretch 10. There was some utility works in my area and they hit the power line. The server...
Replies
15
Views
3,217
My attempt to communicate with Foundation Fieldbus transmitters with Pactware and a new, out-of-the-box Softing FF modem are a disaster - failure...
Replies
17
Views
5,089
Back
Top Bottom