How do I address a single bit out of a word in ST?

strantor

Member
Join Date
Sep 2010
Location
katy tx
Posts
401
I'm writing a function block using Omron CX-Programmer for a CJ2M CPU. The FB is for interfacing with Slice I/O counter cards. The counter cards have 2 control words wherein writing certain bits enable/disable certain functions, and 2 status words wherein certain bits reflect certain statuses.

Simple example: if the counter enabled/disabled status bit (8) is low, I want to set the control bit (also 8) high.

In my ladder program I can access the status bits by the bit address like this:
LDNOT 3313.08 (status word bit 8 "count enabled") OUT 3206.08 (control word bit 8 "enable count")

But in my ST FB I cannot find a way to do the same:
IF StatusWord.08 = FALSE THEN ControlWord.08:=TRUE
or
IF StatusWord[8] = FALSE THEN ControlWord[8]:=TRUE

Neither of the above work, and I cannot find any functions in the manual that look promising.

One idea I had was converting the word to a string of its binary representation and then parsing out the specific character, and then converting to bool. But I can't figure out how to convert to a binary string; it seems it only wants to convert to HEX, and will not accept any formatting like 2#(SAMPLE16BITWORD) or @(SAMPLE16BITWORD) or HEX_TO_BIN(SAMPLE16BITWORD).

Here's what I have (doesn't work, converts to HEX,not BIN)
Code:
(*parse bits out of status word*)
StatusWORD:= INT_TO_WORD(StatusInt);
StatusSTRING:= WORD_TO_STRING(StatusWORD) ;
StatusSTRING_Character8:= mid(StatusSTRING,1,8);
CharacterINT:= STRING_TO_INT(StatusSTRING_Character8);
IF CharacterINT = 1 THEN 
	CountEnabled:=TRUE; 
ELSIF CharacterINT = 0 THEN
	CountEnabled:= FALSE;
ELSE
	Error:= TRUE; (*something other than binary output*)
END_IF;
 
Last edited:
If Omron's ST implementation doesn't support the
<VariableName>.<BitNumber>
like
MyStatus.2
for bit two of MyStatus, then they should support the standard ST functions of BIT_CLR(), BIT_SET(), and BIT_TST() which are used like:
MyBOOL:= BIT_TST(MyStatus, 2);

Just so you know, you shouldn't have to convert from INT to WORD and that may actually be your problem since WORD has fringe support at best for most PLC brands. Also, leading zeros might be your problem, why would you put in leading zeros?

Converting to a string that is a Boolean representation of the value and then evaluating the characters is flat insane. Stop trying to do that. Even it it worked, think of the children.
 
You might also want to try using CTRL+Space to bring up auto complete. I've never used Omron, but that is the universal shortcut for autocomplete and if you then type 'MyStatus.' it may pop up with the bit numbers to rule out proprietary formatting for such a thing.
 
If Omron's ST implementation doesn't support the
<VariableName>.<BitNumber>
like
MyStatus.2
for bit two of MyStatus, then they should support the standard ST functions of BIT_CLR(), BIT_SET(), and BIT_TST() which are used like:
MyBOOL:= BIT_TST(MyStatus, 2);
Thanks, but that's not working, nor is any variation of TST, BIT:TST, etc. There is no reference to this Bit Test in my ST manuals, or in the auto-complete list. It is valid in ladder though, go figure.

According to the Omron ST manual, "The ST language supported by CX-Programmer conforms to the IEC 61131-3 standard." I guess that could mean something as stupid as an auto manufacturer stating "The tires supported by our wheels are DOT approved."

Just so you know, you shouldn't have to convert from INT to WORD and that may actually be your problem since WORD has fringe support at best for most PLC brands.
I tried INT directly first and it didn't work; so tried word next. The code I posted is just a snapshot; one frame of motion picture picture about frustration.
Also, leading zeros might be your problem, why would you put in leading zeros?
What leading zeroes are you referring to? There weren't any leading zeroes in the code I posted.
Converting to a string that is a Boolean representation of the value and then evaluating the characters is flat insane. Stop trying to do that. Even it it worked, think of the children.
Yes I agree. it is a desperate attempt to sidestep what I can only assume is a blatant attempt by Omron to deny the functionality of accessing a bit.
 
Converting to a string that is a Boolean representation of the value and then evaluating the characters is flat insane. Stop trying to do that. Even it it worked, think of the children.

Agreed. There is a far simpler way. If a bit addressing function or syntax doesn't exist then you can always AND a word with a single bit mask. Bitwise AND is how your PLC addresses single bits behind the scenes anyways.

Value AND 1 > 0 tells you if bit 0 is set
Value AND 2 > 0 tells you if bit 1 is set
Value AND 4 > 0 tells you if bit 2 is set
Value AND 8 > 0 tells you if bit 3 is set
Value AND 16 > 0 tells you if bit 4 is set
Value AND 32 > 0 tells you if bit 5 is set
etc.

You mask value is 2n. So for bit 8, 28= 256.
Value AND 256 > 0 will be true if bit 8 is set.

But in my ST FB I cannot find a way to do the same:
IF StatusWord.08 = FALSE THEN ControlWord.08:=TRUE
or
IF StatusWord[8] = FALSE THEN ControlWord[8]:=TRUE

I'm not sure of the Omron syntax, but try an assignment instead of an IF statement.
ControlWord.8 := NOT StatusWord.8
 
Last edited:
One of the problems with IEC 61131-3 is that it makes huge portions of the spec for each language optional and goes so far as to recommend PLC makers expand functionality. That's how you end up with bare bones ST implementations on some platforms (like Rockwell, and apparently Omron) and feature rich implementations like Elau/Schneider and B&R. The bit addressing is listed as an optional thing to support, as are the standard bit functions (so are the "TYPE1_TO_TYPE2()" conversion functions, so at least you have that).

Anyway, here is a link to people talking about bits and Omron, but I don't know anything about Omron, so I don't know if it is helpful:
http://forums.mrplc.com/index.php?showtopic=13788
 
XOR with a 1 will turn a 0 to a one, and a one to a zero if that is your goal,
controlWord = statusWord XOR 1;
Most of my schooling was microprocessors and FPGA so bitwise operations are common to me, I am just recently migrating to automation and robotics so I am not sure of the syntax to do it
 
I'm not sure of the Omron syntax, but try an assignment instead of an IF statement.
ControlWord.8 := NOT StatusWord.8
Nah, no dice
Agreed. There is a far simpler way. If a bit addressing function or syntax doesn't exist then you can always AND a word with a single bit mask. Bitwise AND is how your PLC addresses single bits behind the scenes anyways.

Value AND 1 > 0 tells you if bit 0 is set
Value AND 2 > 0 tells you if bit 1 is set
Value AND 4 > 0 tells you if bit 2 is set
Value AND 8 > 0 tells you if bit 3 is set
Value AND 16 > 0 tells you if bit 4 is set
Value AND 32 > 0 tells you if bit 5 is set
etc.

You mask value is 2n. So for bit 8, 28= 256.
Value AND 256 > 0 will be true if bit 8 is set.


Consider your brilliant suggestion (thanks by the way) good and thwarted by the epic party pooper Omron; or consider me a fool. No support for bitwise functions that I can find, and I looked good and hard before resulting to the (perfectly functional) abomination below.

Turns out the text string thing is a no-go as well; no way to convert anything to a binary string :(.

If you have any regard for the children, avert their eyes now:
Code:
(*Since Omron does not permit any of the following in ST 
function block: direct addressing of bits of a word (ex: InputWord.08)
OR bitwise logic OR BIT_TST OR number conversion to a binary text string, 
I am convertinga 16 bit INT to 16 binary characters the old-school way, 
same as you would with a paper 
and pencil, with sixteen steps of division*)

Quotient[0]:= INPUT_INT;
InputBit[0]:= MOD(INPUT_INT,2);
(*repeatedly divide the input INT by 2 and store the quotients in an
INT array, and store the remainders (InputBit[]) in another INT array*)
FOR i:= 1 TO 15 DO
	Quotient[i]:= Quotient[i-1]/2;
	InputBit[i]:= MOD(Quotient[i],2);
END_FOR;

(*all code above and below are in place JUST to make this one example line possible.
Note that not only this one input and one output are needed; there are more not shown*)
 OutputBit[8] (*enable counting*):= InputBit[8] (*counting enabled*);
 (*note that the above "bits" are actually INTs; converting to BOOL would/wil require 
 an IF statement since Omron does not permit conversion of any data type to BOOL*)

OUTPUT_REAL:= 0.0; (*reset output word from last cycle's value before calculating 
an output for this cycle*)
FOR i:= 0 TO 15 DO
	OUTPUT_REAL:= OUTPUT_REAL + INT_TO_REAL(OutputBit[i])*EXPT(2.0,(i)); 
        (*conversion to REAL because Omron does not does not support EXPT for INT*) 
END_FOR;
OUTPUT_INT:= REAL_TO_INT(OUTPUT_REAL);
(*354 steps and 75 non-retain memory words just to pass a single bit through a ST FB*)

THERE HAS GOT TO BE A BETTER WAY! Or, maybe not.
 
Last edited:
Agreed. There is a far simpler way. If a bit addressing function or syntax doesn't exist then you can always AND a word with a single bit mask. Bitwise AND is how your PLC addresses single bits behind the scenes anyways.
 
TBH I think you're making a meal of this.
The AT addressing to create a UNION will let you do what you need.

For the record, TConnolly's pseudo code would work; all logical operator are, of course, supported.

My $0.02
AccessBits.jpg


Pp
 
TBH I think you're making a meal of this.
The AT addressing to create a UNION will let you do what you need.
Yes you're right. I am a difficult person and it's irritating, even to me. Any rational person would take one of the paths of least resistance:
1.Use AT addresses
2.Use an input/output array of BOOLs
3.Use BOOL inputs and handle bit addresses externally (like 3314.08 input)

But I get into my head a certain way that I want to do something and if it seems like something is getting in the way, then I am consumed by the quest to conquer it. I wish I could just let it go but it takes a pretty severe beating before I can do that; kinda like the one I'm getting right now. I'm on the verge of giving in.

For the record, TConnolly's pseudo code would work; all logical operator are, of course, supported.

My $0.02

Pp
Yes, of course, you're right.
TConnolly, I must print a retraction and acknowledge my fool status. I had initially tried your suggestion using INTs and Omron told me "AND operator not supported by INT data type" and some other error about Boolean operator. I searched the manuals for "bitwise" and the the only results were bit shift and rotate; searched the web too, and that's all I found for Omron. So I concluded that in Omronland, AND only applies to individual BOOLs. But after paraffin smacked me in the head a second time, I went back to the manuals and found that AND is supported by data types BOOL, WORD, DWORD, and LWORD. So I changed my INTs to WORDs and voila! You were right and I was wrong.

Here's my code:
Code:
out:= 0; (*reset Output word from last scan*)
(*reset bits from last scan*)
InputBit0:= FALSE;
InputBit1:= FALSE;
InputBit8:= FALSE;
OutputBit0:= FALSE;
OutputBit1:= FALSE;
OutputBit8:= FALSE;
(*determine input bits*)
IF (InputWORD AND 1) > 0 then InputBit0:= TRUE; END_IF;
IF (InputWORD AND 2) > 0 then InputBit1:= TRUE; END_IF;
IF (InputWORD AND 256) > 0 then InputBit8:= TRUE; END_IF;(*encoder enabled*)

(*simulated code, simply passing 3 bits through*)
OutputBit0:= InputBit0;
OutputBit1:= InputBit1;
OutputBit8:= InputBit8;

IF OutputBit0 = TRUE THEN out:= out+1; END_IF;
IF OutputBit1 = TRUE THEN out:= out+2; END_IF;
IF OutputBit8 = TRUE THEN out:= out+256; END_IF;

This is still more resource-intensive than I am ready to accept. 164 steps to pass 3 bits through the FB, or 43 steps per bit. If I want all 16, it's going to cost me 695 steps. Better to go back to the FOR loop.

Next I will play with the input/output array of BOOLs; I think that will compromise my goals the least.
 
The IEC specification is fanatically restrictive on ensuring types are not mixed and some operations are only possible on some types.
Bit operations on INTs and DINTs are not possible. The easy way to do this is to copy the INT to a WORD using
MyWord:=INT_TO_WORD(MyInt);
MyWord := MyWord OR SHL(0x1,n);
MyInt :=WORD_TO_INT(MyWord);
 
Isn't the verbose code you posted just...

Code:
Out := In

I claim my prize 🍻
Haha, yes It is but its just an example. This thread has been just about how to read and write bits from a word, and as a test I'm just passing bits through 1:1 to verify that I have it right. The actual FB that this is for, does not simply pass bits through.
 
Code:
out:= 0; (*reset Output word from last scan*)
(*reset bits from last scan*)
InputBit0:= FALSE;
InputBit1:= FALSE;
InputBit8:= FALSE;
OutputBit0:= FALSE;
OutputBit1:= FALSE;
OutputBit8:= FALSE;
(*determine input bits*)
IF (InputWORD AND 1) > 0 then InputBit0:= TRUE; END_IF;
IF (InputWORD AND 2) > 0 then InputBit1:= TRUE; END_IF;
IF (InputWORD AND 256) > 0 then InputBit8:= TRUE; END_IF;(*encoder enabled*)

(*simulated code, simply passing 3 bits through*)
OutputBit0:= InputBit0;
OutputBit1:= InputBit1;
OutputBit8:= InputBit8;


All of that can be simplified to:
OutputBit0:= ((InputWORD AND 1) > 0);
OutputBit1:= ((InputWORD AND 2) > 0)
OutputBit8:= ((InputWORD AND 256) > 0)
 

Similar Topics

Hi, I'm trying to setup a single pc solution to testing and devloping my PLC application. I have written an EthernetIP I/O simulator program...
Replies
6
Views
12,696
This probably just falls under personal preference, but when using RS-Logix 5 what is the advantage or situation when it is better to split...
Replies
4
Views
1,821
i have two plc 1. s7-1212dc/dc/dc ip; 192.168.0.1 2. s7-1500 1513-1pn ip; 192.168.3.2 i need to get data from plc1 to plc2. any idea how to do...
Replies
5
Views
125
Hi, I wanted to ask is there a way to have a visibility expression use the IP address of the HMI (Dynics, not PV) to show certain elements? The...
Replies
3
Views
201
Hello. I have a few machines that use Kinetix 300 (each machine has two drives). Both drives on one of the machine keep losing IP address. They...
Replies
2
Views
104
Back
Top Bottom