toggle logic in 'c' language

naishadgosai

Member
Join Date
Aug 2005
Location
surat,gujarat
Posts
39
hello,
i need a toggle logic (means one of push button get pressed & released ,say M0.0 bit get set(1).and for 2nd time pressed and released,say M0.0 bit get reset(0).its going on for many times.)
in a "c" language.
if u can give pls reply uregently....
 
Theres plenty of examples of using toggle logic here. As for a doing it in 'C'. The simpliest form is something like this.
"bolOffOn = NOT bolOffOn;" where bolOffOn is defined as a boolean.
After that just use a If, Then statement to turn on and off the controller bit.
 
First a note... the common C NOT-Symbol ("!") can be easily assigned to the word NOT.

When used as a teaching tool, the purpose of this exercise is to illustrate the difference between static-state evaluations and dynamic-state evaluations (ie, transitions). Plus a little more...

In this case, we are evaluating the static-state of the output and the dynamic-state of the pushbutton.

If the output is NOT ON when the pushbutton is operated, then turn the output ON.
If the output IS ON when the pushbutton is operated, then turn the output OFF.

A quick response by an inexperienced novice might be...

//LINE-1//
{ Push_Button -AND- NOT Output } => SET Output

//LINE-2//
{ Push_Button -AND- Output } => RST Output


First, let's understand the difference between... --( ), --(SET), and --(RST)

--( )
An output of this type needs "cause" to be ON ("1").
If the "cause" is not present then that output goes "NOT ON" ("NOT 1").
Possible results: ON or "NOT ON" (ON or OFF)
(Note: The logical opposite of "ON" is "NOT ON". However, only because we are talking about the state of a bit which can have only one of two states, we can also say that the opposite of ON includes OFF. As an exercise, consider the relationship between Closed and Opened.)

--(SET)
An output of this type needs "cause" to perform a "SET" (Write a "1" to the particular bit).
If the "cause" is not present, then a SET operation is not performed.
Possible results: SET or "NOT SET"
(Note: The logical opposite of "SET" is "NOT SET"... AND, "NOT SET" does NOT equal RST!)

--(RST)
An output of this type needs "cause" to perform a "RST" (Write a "0" to the particular bit).
If the "cause" is not present, then a RST operation is not performed.
Possible results: RST or "NOT RST"
(Note: The logical opposite of "RST" is "NOT RST"... AND, "NOT RST" does NOT equal SET!)

Let's understand one other thing...

When the program examines the state of an output, it does NOT look at the actual PLC Output to that device. While code is being processed, if code causes a change in the state of an output bit, that change is NOT applied to the actual output device... not yet. Instead, the change is made only to an "Image Table" of the PLC outputs.

During the Ladder portion of a scan, the state of any particular output bit in the "Output Image Table" might change many times. This has no effect whatsoever on the actual PLC outputs... at least, not until the ladder is completed and it is time to "update" the actual PLC outputs. When ladder evaluation is done, the processor copies the status of the resulting "Output Image Table" to the actual PLC outputs. Only then does a change in the status of a particular output bit affect an actual PLC output.

The point being, while evaluating ladder, the program is examining and manipulating bits in the "Output Image Table"... not the actual PLC outputs.

So now, let's play "Be the Computer" and exercise the code to see what happens...
Let's begin with both the Push_Button (PB) and the Output (OUT) OFF...

//LINE-1//
{ Push_Button -AND- NOT Output } => SET Output

//LINE-2//
{ Push_Button -AND- Output } => RST Output



Evaluating Line-1:
PB is OFF so the result is NOT SET Output. The Output-bit is left as is (OFF).

Evaluating Line-2:
PB is OFF so the result is NOT RST Output. The Output-bit is left as is (OFF).

End of ladder-evaluation:
The Output-bit is OFF and so the actual PLC output is left as it was... OFF.

Several thousand scans later... Now, let's push the button and begin the next scan...

Evaluating Line-1:
PB is ON, and the output-bit in the Output Image Table is OFF, so the result is SET the output-bit. A "1" is written to the output-bit in the Output Image Table.

Evaluating Line-2:
PB is ON, and the output-bit in the Output Image Table is ON (it was just turned ON in the previous line!), so the result is RST the output-bit. A "0" is written to the output-bit in the Output Image Table.

End of ladder-evaluation:
Copy the Output Image Table to the actual PLC outputs. Notice that the particular output-bit is OFF. The code turned the output-bit ON, but then it turned it back OFF before it was time to update the PLC outputs. The actual PLC output is left as it was... OFF.

Definition: Insanity... repeating the same actions over, and over again, hoping for a different result.

You can hold the button forever... the actual output will never go ON. You can repeatedly push and release the button a million times... the result will be the same... no output!

What would happen if the order of the lines is reversed?

//LINE-1//
{ Push_Button -AND- Output } => RST Output

//LINE-2//
{ Push_Button -AND- NOT Output } => SET Output


Again, starting with the Push Button and Output OFF...

Evaluating Line-1:
PB is OFF so the result is NOT RST Output. The Output-bit is left as is (OFF).

Evaluating Line-2:
PB is OFF so the result is NOT SET Output. The Output-bit is left as is (OFF).

End of ladder-evaluation:
The Output-bit is OFF and so the actual PLC output is left as it was... OFF.

Several thousand scans later... Now, let's push the button and begin the next scan...

Evaluating Line-1:
PB is ON, and the output-bit in the Output Image Table is OFF, so the result is NOT RST. The output-bit remains as it was... OFF.

Evaluating Line-2:
PB is ON, and the output-bit in the Output Image Table is OFF, so the result is SET the output-bit. A "1" is written to the output-bit in the Output Image Table.

End of ladder-evaluation:
Copy the Output Image Table to the actual PLC outputs. Notice that the particular output-bit is ON.


Next Scan... while still holding the button...

Evaluating Line-1:
PB is ON, and the output-bit in the Output Image Table is ON, so the result is RST the output-bit. A "0" is written to the output-bit in the Output Image Table.

Evaluating Line-2:
PB is ON, and the output-bit in the Output Image Table is OFF, so the result is SET the output-bit. A "1" is written to the output-bit in the Output Image Table.

End of ladder-evaluation:
Copy the Output Image Table to the actual PLC outputs. Notice that the particular output-bit is ON.


Next Scan... button is released...

//LINE-1//
{ Push_Button -AND- Output } => RST Output

//LINE-2//
{ Push_Button -AND- NOT Output } => SET Output


Evaluating Line-1:
PB is OFF, so the result is NOT RST. The output-bit is left as it is... ON.

Evaluating Line-2:
PB is OFF, so the result is NOT SET. The output-bit is left as it is... ON.

End of ladder-evaluation:
Copy the Output Image Table to the actual PLC outputs. Notice that the particular output-bit is ON.


Next Scan... button is pushed again... the expectation is that the output will go OFF...

//LINE-1//
{ Push_Button -AND- Output } => RST Output

//LINE-2//
{ Push_Button -AND- NOT Output } => SET Output


Evaluating Line-1:
PB is ON and the output-bit is ON, so the result is RST the output-bit. A "0" is written to the output-bit. The output-bit is OFF.

So far, so good...

Evaluating Line-2:
PB is ON and the output-bit is OFF, so the result is SET the output-bit. A "1" is written to the output-bit. The output bit is ON.

Uh-oh...

End of ladder-evaluation:
Copy the Output Image Table to the actual PLC outputs. Notice that the particular output-bit is ON.

Insanity revisited...

Once you get the output ON, you can NEVER turn it OFF... without shutting down the process... and then, only if the particular bit is NOT Retentive!

CONTINUED...
 
The reason that this happens this way is because the code is evaluating static-states only. The code is acting as nothing more than a dumb switch-handler.

The code needs to have some "smarts"... it needs to have a sense of "history".

Let's revisit the original conditional statements...

If the output is NOT ON when the pushbutton is operated, then turn the output ON.
If the output IS ON when the pushbutton is operated, then turn the output OFF.

The operative word here is... "when".
The operative phrase is... "when the pushbutton is operated"

This means... "when the pushbutton transitions from OFF to ON".

So... how to detect when the pushbutton comes ON... Some PLCs have "transition detection". This is often indicated by --|/\|-- for OFF-to-ON, and --|\/|-- for ON-to-OFF. The particular element will be true for one scan.

OK, so that will provide for allowing further evaluation in the line only when the transition occurs. That means, even if the button is held for several thousand scans, the evaluation occurs only on that scan when the pushbutton was first pressed.

Is this enough? No.

Both conditional statements are looking for an OFF-to-ON transition. When an OFF-to-ON transition occurs, it will apply to and activate both lines of code. Unless something can prevent it from occurring, this will lead to the apparent "hang" that was described... "Never ON", or, "Once ON, always ON".

Sorta, kinda like...

Imagine walking into one end of a dark room. You know that when you walk into a dark room you need to flip the light switch... so you do... the light comes ON. Then you spy another switch at the other end of the room... you go down there and flip that switch (it's a compulsive thing)... the room goes dark. Obviously, a three-way switch.

It doesn't matter which end you enter first, and it doesn't matter what the current state of the light is... for whatever reason, you have this "thing" that you have to flip both switches. So, upon entering, you flip the first switch and then you flip the other. When you leave, you go through the same ritual... both switches get flipped.

If the light in the room was OFF when you first entered then the light will go ON when you flip the first switch, and OFF when you flip the second switch... leaving you in the dark. As you leave, you again flip both switches... the light goes ON, then the light goes OFF. Except for those times when you are traveling between switches (from first code line to second code line), the light is ALWAYS OFF!

That's kinda like opening and closing the refrigerator door, over and over, hoping that this time, when the door is open, there WILL BE BEER! Damn! Let me try again... and again... and again... maybe this time... damn!

If the light in the room was ON when you first entered then the light will go OFF when you flip the first switch, and, if you can find your way, the light will go ON when you flip the second switch. As you leave you again flip both switches... the light goes OFF, then the light goes ON. Except for those times when you are traveling between switches (from first code line to second code line), the light is ALWAYS ON!

I guess that would be kinda like... there's ALWAYS BEER! WOW... that could be cool... do ya think?

When some of you normal folks go into a dark room you turn on the light switch. If light appears then you are satisfied... you ignore the other switch! Regardless of which switch you flip first, if you have light, as you expect, then you ignore the second switch.

This amounts to... when entering, it was OFF, now it's ON, ignore the other switch. When leaving, it was ON, now it's OFF, ignore the other switch.

The key to this is... if one switch is operated, ignore the other.
In context... if one code-line causes a change in the status of the output-bit, ignore the other code-line.

So, somehow, you need to prevent the second line from executing if the first line causes a change in the state of the output-bit.

You could try something like...

//LINE-1//
{ Push_Button -AND- NOT Output -AND- NOT Ignore_Line_1 }
=> SET Output, and Ignore_Line_2 (where... Ignore_Line_2 is a 1-Shot)

//LINE-2//
{ Push_Button -AND- Output -AND- NOT Ignore_Line_2 }
=> RST Output, and Ignore_Line_1 (where... Ignore_Line_1 is a 1-Shot)


If Line-1 is executed and result is SET Output, then Ignore_Line_2 will go ON... for one scan. This will indeed prevent Line-2 from executing... on this scan. The actual PLC output will go ON at the output update.

On the next scan, however, if the pushbutton is still pressed, then in Line-1, because the output-bit is ON, Line-1 is False and it will turn OFF Ignore_Line_2. Now, in Line-2, because the pushbutton is pressed, and the output-bit is ON, and Ignore_Line_2 is now OFF, the output-bit will be RST and Ignore_Line_1 will go ON... for one scan. The actual PLC output will go OFF at the output update.

On the following scan, Ignore_Line_1 is ON so...

This amounts to the output-bit toggling ON and OFF every other scan for as long as the button is pressed. This is clearly not what is expected. We need a better way...

Once a line causes a change in the state of the output-bit, we need to prevent either of the lines from executing until the next time that the button goes ON. Once a change occurs, and for as long as the button is held, ignore BOTH lines!

//LINE-1//
{ Push_Button -AND- NOT Output -AND- NOT Ignore_Both_Lines }
=> SET Output
=> SET Ignore_Both_Lines

//LINE-2//
{ Push_Button -AND- Output -AND- NOT Ignore_Both_Lines }
=> RST Output
=> SET Ignore_Both_Lines

"... and for as long as the button is held, ignore BOTH lines!"

//LINE-3//
{ NOT Push_Button -AND- Ignore_Both_Lines }
=> RST Ignore_Both_Lines


When the button is released, re-enable both lines to execute. Upon the next button press, the first line to execute will perform the particular output-bit modification and then prevent any subsequent evaluations until the button is released.

Now, if I can just get that damned refrigerator to co-operate...

(60)
 
As usual - an incredibly insightful posting from Terry. I fear for the simplicity of my reply but my first thought was:


main{}
{

int state;
int output;

state = 0;
output = 0;

while(1)
{

switch(state)
{
case 0: if(button) then
{
state = 1;
output = 1;
}
break;
case 1: if not(button) then
{
state = 2;
}
break;
case 2: if(button) then
{
state = 3
output = 0;
}
break;
case 3: if not(button) then
{
state = 0;
}
break;
}
}
}




Way back (mid 80's) I did a few machine controls entirely in 'C' on an STD bus XT type control (Microsoft C5.1) and used the 'switch/state' construct a lot for the various states of the sections of the machine. It worked great and I could just observe the state numbers to see the entire smachine state.
 
Last edited:
Sometimes I find these posts amuzing. Sometimes .....

Arrrggghhh......

Since naishadgosai used M0.0 in his example I will use bits too and process 32 bits at a time. If you want to use fewer bits then change the MaskBits.

unsigned long OutputBits, InputBits, LastInputBits;
unsigned long MaskBits = 0xFFFFFFFFFFFFFFFF; /* Mask for bits you want to toggle */

Outputbits ^= InputBits & ~LastInputBits & MaskBits;
LastInputBits = InputsBits & MaskBits;

Short, sweet and simple.
 
Peter Nachtwey said:
Arrrggghhh......

Since naishadgosai used M0.0 in his example I will use bits too and process 32 bits at a time. If you want to use fewer bits then change the MaskBits.

unsigned long OutputBits, InputBits, LastInputBits;
unsigned long MaskBits = 0xFFFFFFFFFFFFFFFF; /* Mask for bits you want to toggle */

Outputbits ^= InputBits & ~LastInputBits & MaskBits;
LastInputBits = InputsBits & MaskBits;

Short, sweet and simple.

Very nice. Just make sure "LastInputBits" is initialized to "InputBits" on the first pass thru.
 
And so... Peter...

I know that you gave naishadgosai a short, to the point, answer. And since he expressed an urgent need for the answer... I'm sure your answer is appreciated.

However, how about a little "What" and "How"? And more importantly, "WHY?"

You have quite often critized me for "confusing the rookies".

Maybe you've done so because my answers (especially to this type of question) tend to be somewhat verbose (as in "teach him to fish" rather than "give him a fish").

Or maybe it was because I used a little indirection/redirection just to make a point.

Or maybe it was because I tended to speak in terms of fundamental logical concepts (which can be handled by any adequate/reasonable PLC) as opposed to speaking in terms of vendor-specific logical functions... even though a specific vendor was mentioned.

You have said in the past, and I tend agree, "Terry is good at teaching the basics." 90% of our audience has gotta be new-guys.

naishadgosai indicated that "its going on for many times."

This indicated to me that his initial effort, in ladder, was a failure because he ran into one of the "hang" conditions I described... namely, the ON... OFF... ON... OFF... etc, every other cycle.

naishadgosai expressed an urgent need.

It appears that he tried desperately to develop the code in ladder and couldn't make it happen. That was his first mistake. After some time, somehow, he came to the conclusion that since he couldn't find a way to make the PLC behave as he expected, it was, therefore, logically impossible to force ladder to do as he needed. That was his second mistake.

For whatever reason, it appears that he came to think that the only means possible to produce the expected result was through a "C" implementation. That was his third mistake.

I explained the reason for the "hang" condition that he ran into and then went on to provided "C-type" psuedo-code that could be directly implemented as "C" (if he really knew anything about "C") or directly as common Ladder.

Certainly, my response was based on certain, reasonable assumtions (I believe my assumptions were entirely reasonable based on what was posted)... however, my response provided a means to implement a solution using either "C" or Ladder.

So... what's with the "Arrrggghhh......"
 
ooooooo... that does look quite a bit like 64-bit.

I'd call it an "ooops"... sticky-key, or electricians-shake, no doubt.
 
Either the C or the Ladder below was all the was needed.


Input LastInput Toggle
------| |--------|/|----------------( )

Output Toggle Output
------| |--------| |----------------(R)

Output Toggle
------|/|--------| |----------------(S)

LastInput
------| |---------------------------( )



When we get around to doing a Ladder editor I will include a Toggle output.
This will simplify the ladder too. I think this is a major deficiency in most ladder editors.


Input LastInput Output
------| |--------|/|----------------(T)

Input LastInput
------| |---------------------------( )



Do not forget to use the first scan bit to initialize LastInput with Input as jstolaruk suggested.

So... what's with the "Arrrggghhh......"
I could have answered naishadgosai's post within about 15-30 minutes. I don't because I often don't have the time because I doing something that demands my full attention like application support or training. I also expect others want to show off their expertise. I know Terry and many others are 'c' programmers too so I expected this question to be quickly answered. At least Bernie supplied an answer. There was probably an answer buried in Terry's post too somewhere.

I post too much as it is and I really do try to let others have a chance. However, I often see threads go astray or fail to provide an decent answer. I often see threads where the wrong question was asked so the answer were invalid.

This is a simple problem that needed only a simple answer. Toggles have been covered here many times before. The only catch here is that a 'c' example was requested.

What bothers me is I know this thread will be lost in the multitude of threads of this forum and the next person will not think to search for the key word 'toggle'. All this info will be effectively 'lost' . But now this thread is beat to death.
I see the thread about PIDs. No one searches for the key word PID. AAARRGGGHHH!!!!!
I see people talking about general rules for tuning PIDs. It isn't the PID you are tuning. It is the system and there are many types of systems so there are different rules. AARRGGGHHH!!!!

What makes mankind superior to the other animals is that we can pass on information. I am just disillusioned at how difficult this is even in the age of the internet.
 

Similar Topics

Hi, I'm just looking for a simple way to make a button in excel (via VBA I presume) to toggle a bit in RSLogix 5000. I just got FactoyTalkLinx...
Replies
9
Views
488
Hello good people! Attached is a very simplified version of a Zelio program containing what I am trying to do but it carries the same problem as...
Replies
8
Views
1,211
EDIT: I suppose i should mention, RSLogix 500 V8.40, SLC 5/04 (1747-L542C) Is there is a way to use the FFL instruction in a way that doesn't...
Replies
4
Views
847
I am trying to achieve a set/reset or toggle function withthe same input. Example: Push a button once, the motor or pump starts, push the same...
Replies
33
Views
7,996
I don't have any prior experience with MicroLogix so the Communication Toggle Button is new to me. We currently have a few MicroLogix that are...
Replies
4
Views
2,154
Back
Top Bottom