Author Topic: Test Bit for greater than or Less than  (Read 120 times)

Lorne Van Dusen

  • Jr. Member
  • Posts: 78
  • I'm a old guy
    • View Profile
Test Bit for greater than or Less than
« on: January 09, 2020, 10:14:01 PM »
I have RELAY[1] that uses the first 8 bits 0 to 7 and only one bit is on at any time

I have another RELAY[2] that can have one or more bits 0 to 7 on
I need to turn on a bit that only turns on if any of the bits in RELAY[2] is greater than the bit in RELAY[1]
Then I also need a different bit to turn on if any bit that is of lower value than the bit in RELAY[1] regardless if any bit that is higher than RELAY[1] is also on.

garysdickinson

  • Expert Member
  • Posts: 457
  • Old PLC Coder
    • View Profile
Re: Test Bit for greater than or Less than
« Reply #1 on: January 10, 2020, 06:39:35 AM »
    Lorne,

    This is not too difficult to do in TBASIC. It is a bit more complicated do do in ladder logic.

    This is the sort of code that I would suggest:

' SetFlgs - CF to test lower 8-bits or RELAY[1] against RELAY[2]
'
N = RELAY[1] & &h00ff   ' isolate bits 0..7
L = N - 1            ' low mask (bits less than single bit in N)
H = &hff ^ (L | N)      ' high mask (bits greater than single bit in N)

if RELAY[2] & L
   SetIO LowFlg
else
   ClrIO LowFlg
endif

if RELAY[2] & H
   SetIO HighFlg
else
   ClrIO HighFlg
endif


Comments on code:
  • L is map of the bits less that the single bit set in RELAY[1]
  • N is map of the bits greater than the single bit set in RELAY[1]
  • LoFlg is a RELAY that is set when there are bits in RELAY[2] that are less than the single bit in RELAY[1]
  • HighFlg is a RELAY that is set when there are bits in RELAY[2] that are set at positions greater than the single bit in RELAY[1]
Concerns about RELAY[1]
  • This code works if there is exactly one bit set in RELAY[1] bit positions 0..7
  • This code fails miserably if there are no bits set in RELAY[1] bit positions 0..7
  • This code fails in interesting ways if there is more than one bit set in RELAY[1] bit positions 0..7
  • If there is any chance that your rules about RELAY[1] may not be held sacred, then you need to add some code to test and verify that RELAY[1] meets the rules before you get to the code that sets/clears flags.

Best Regards,

Gary Dickinson[/list]
« Last Edit: January 10, 2020, 04:04:20 PM by garysdickinson »

Lorne Van Dusen

  • Jr. Member
  • Posts: 78
  • I'm a old guy
    • View Profile
Re: Test Bit for greater than or Less than
« Reply #2 on: January 10, 2020, 04:19:11 PM »
Gary as usual I guest it would be you that came up with the perfect program to solve my issue.
I forgot to mention that there is always a value in RELAY[1] and only 1 bit will be on at any time.
I had programmed a circuit that worked OK but the code was a lot longer than yours.

Basically the circuit for a bit greater than worked fine so I then reversed the bits in both RELAY[1] and put it into RELAY[3]  & also reversed the bits in RELAY[2] and put them into RELAY[4] then did a compare   

I tested your program today and it works perfectly and requires a lot less code than my program

Thanks

garysdickinson

  • Expert Member
  • Posts: 457
  • Old PLC Coder
    • View Profile
Re: Test Bit for greater than or Less than
« Reply #3 on: January 10, 2020, 06:59:36 PM »
Thanks Lorne,

I like algorithms. Before I sent the reply I came up with some rather complicated ideas, also. I got balled up with numeric values and the idea of comparing values.

But the easier algorithm was to just figure out how to build bit maps base on the single bit in RELAY[1]. TBASIC supports a good set of Boolean operators which makes bit twiddling easy. 

The trick was that the less than map just needed a subtraction.  The bit map for greater than is easier, it's all the other bits that aren't in the less than map and the bit in RELAY[1] and this is just a bit of Boolean bit twiddling.

Gary d

garysdickinson

  • Expert Member
  • Posts: 457
  • Old PLC Coder
    • View Profile
Re: Test Bit for greater than or Less than
« Reply #4 on: January 14, 2020, 03:50:11 AM »
Lorne,

I thought about the ladder logic implementation.  I wrote 1/2 of the code that checks for bits in RELAY[2] that are less than the single bit in RELAY[1].

Why?  Just to see how hard it was to write.  I did manage to write more code on a single rung that the ladder logic can support so I broke the problem across two rungs.

I attached the code to this email.  The 1/2 that I wrote took 2 lines of ladder logic and a total of 50 ladder diagram words. Double that to get the complete program.

If your application requires this bit testing code to checked on every scan of the ladder logic, then I'd use the ladder logic rung rather than calling the CF solution.

Best regards,

Gary Dickinson

Lorne Van Dusen

  • Jr. Member
  • Posts: 78
  • I'm a old guy
    • View Profile
Re: Test Bit for greater than or Less than
« Reply #5 on: January 14, 2020, 04:49:09 PM »
Gary for me the Ladder Logic is easy I have attached a simplified version how I have always done a circuit similar to what I had asked you for. However I totally impressed with your Basic version which works exceptionally well with such a small amount of code however I cannot totally understand exactly how your Basic program does what it does.
L =N -1
IF CALLS & L SETIO CBP ELSE CLRIO CBP ENDIF 
How does it actually turn out to be If Calls Less than be?
My brain keeps seeing if N = 4 then L would be 3 then any Call Value below 3 would be less that 3 but how does that statement IF CALLS & L equal Less Than
Also the same question for the IF CALLS & H SETIO CAP 

Lorne Van Dusen

  • Jr. Member
  • Posts: 78
  • I'm a old guy
    • View Profile
Re: Test Bit for greater than or Less than
« Reply #6 on: January 14, 2020, 09:59:32 PM »
Gary I figured it all out. It was driving me crazy until I actually did the math one step at a time.
I had totally missed the fact that if you subtract 1 in the value in N you get all 1's below the value of N
Then when you do an & of FF with L you only get a 1 if the bits match so the less than works
Next it took a while but I realized that when you do the Exclusive or it changes all the bits above either L or N into 1's
Then any bit greater than L produces a 1 when you do a & with Calls & H so the greater than so the greater than works.
Your a genius for figuring this out with such a small amount of code. 

As usual thanks for your expert help

garysdickinson

  • Expert Member
  • Posts: 457
  • Old PLC Coder
    • View Profile
Re: Test Bit for greater than or Less than
« Reply #7 on: January 14, 2020, 10:37:08 PM »
Lorne,

Your ladder logic code is much better than my version.  It is much simpler and solves the problem very directly.  I am very impressed!

I will try and explain how my TBASIC program operates.  TBASIC supports three types of operators:
  • Arithmetic Operators: +, -, *,/ and MOD.  The first 4 show up on calculators. MOD is the remainder from integer division and is what was taught in elementary school (10 divided by 3 is 3 remainder 1).
  • Bitwise Boolean Operators: &, |, ^, and ~ ( bitwise AND, bitwise OR, bitwise Exclusive OR and bitwise NOT)
  • Relational Operators: =, <>, ... AND, OR

I will explain the use of Bitwise Boolean operators in my program line by line.
N = RELAY[1] & &h00ff   ' isolate bits 0..7

RELAY[1] is a 16-bit value that represents the the state of Relays 1..16.   If Relay #3 and Relay #16 is ON and the other 14 relays are OFF, then the value of RELAY[1] would have a decimal value of -32764 or &h8004.  But all arithmetic in TBASIC is done with 32-bit signed arithmetic the Value of RELAY[2] will be sign-extended to a 32-bit value.  I only care about the lower 8-bits of the value so I will use the bitwise Boolean & (and) operator to clear all but the least significant 8 bits of the value.

Look at the last two lines in the table to see the effect of the Bitwise Boolean & (AND) operator.

Comment                 Decimal    HexadecimalBinary
RELAY[1] as 16-bit-3276480041000 0000 0000 0100
RELAY[1] as 32-bit-32764FFFF80041111 1111 1111 1111 1000 0000 0000 0100
&h00ff value255000000FF0000 0000 0000 0000 0000 0000 1111 1111
RELAY[1] & &h00ff4000000040000 0000 0000 0000 0000 0000 0000 0100

This line of code is an assignment statement.  The variable, N, will be assigned the value that results from the Bitwise Boolean & (AND) operator.
N = RELAY[1] & &h00ff   ' isolate bits 0..7

The next line of code generates a map of all of the bits that are less than the single bit set in RELAY[1] and assigns this value to "L":

L = N - 1            ' low mask (bits less than single bit in N)

Comment                 Decimal    HexadecimalBinary
N400000040000 0000 0000 0000 0000 0000 0000 0100
N-13000000030000 0000 0000 0000 0000 0000 0000 0011

The line of code:
L = N - 1            ' low mask (bits less than single bit in N)
doesn't use any binary operators, just old school subtraction.  The reason that subtracting 1 from N gets a bit map is because of the fact that that only possible values of N are 1,2,4,8,16,32,64 and 128. Those values have only a single 1 set in their binary representations.  128 in binary is 10000000 subtracting 1 from 128 will get you 127 or 01111111 binary (lots of carries).

Table that shows the bit map off all of the bits less than N for all possible values of N:
Comment                 Decimal    HexadecimalBinary
N=1, L0000000000000 0000 0000 0000 0000 0000 0000 0000
N=2, L1000000010000 0000 0000 0000 0000 0000 0000 0001
N=4, L3000000030000 0000 0000 0000 0000 0000 0000 0011
N=8, L7000000070000 0000 0000 0000 0000 0000 0000 0111
N=16, L150000000F0000 0000 0000 0000 0000 0000 0000 1111
N=32, L310000001F0000 0000 0000 0000 0000 0000 0001 1111
N=64, L630000003F0000 0000 0000 0000 0000 0000 0011 1111
N=128, L1270000007F0000 0000 0000 0000 0000 0000 0111 1111

The next line of code is:
H = &hff ^ (L | N)      ' high mask (bits greater than single bit in N)
That line of code generates the mask for the bits that are greater than then single bit in N (RELaY[1]). This line of code uses 2 bitwise Boolean operators, "|" (XOR) and "^" (exclusive OR).

The Boolean OR operator looks at 2 bits and if either bit is a "1" the output will be a "1".  TBASIC's bitwise Boolean OR, "|", works with two 32-bit values and on a bit-by-bit basis to create a new 32-bit value.

Exclusive OR (XOR) is a Boolean operator that is used to compare two bits. If the bits have different values then the output is a "1". If the two bits have the same value (both 0s or 1s) then the outputs is a "0".

TBASIC supports a bitwise Boolean XOR, "^". Bitwise means that it works with two 32-bit input values and outputs a new 32-bit value based on a bit by bit comparison.

At this point in the program we have N and L.  L is a bit map of all of the bits less than the value of N. What we need to do is compute the bit map for all of the bits that are greater than N. 

This bit of code is evaluated first as it group in parenthesis:
(L | N)
The bitwise Boolean "|" create a new value that is a bit wise OR of L and N.  This value is the pattern of all of the bits that are less than N and equal to N. This is value is actually all the bits that we don't want.  The bitwise XOR comes to the rescue by allowing us to sort of subtract out the bits we don't want to generate the mask of bits greater than N.

H = &hff ^ (L | N)

&hff is a constant that represents all possible bits in an 8-bit value. The "^" operator will remove the result from the  (L | N) expression from the &hff constant. The result will be assigned to H as a map of all of the bits greater than N.

All of the possible values of H:
Comment                 Decimal    HexadecimalBinary
N=1, H254000000FE0000 0000 0000 0000 0000 0000 1111 1110
N=2, H252000000FC0000 0000 0000 0000 0000 0000 1111 1100
N=4, H248000000F80000 0000 0000 0000 0000 0000 1111 1000
N=8, H240000000F00000 0000 0000 0000 0000 0000 1111 0000
N=16, HE0000000E00000 0000 0000 0000 0000 0000 1110 0000
N=32, HC0000000C00000 0000 0000 0000 0000 0000 1100 0000
N=64, H128000000800000 0000 0000 0000 0000 0000 1000 0000
N=128, H0000000000000 0000 0000 0000 0000 0000 0000 0000

Now that the high and low bit maps have been calculated, it is pretty easy to look for bits in RELAY[2] that are less than and greater than the value in N.

if RELAY[2] & L
   SetIO LowFlg
else
   ClrIO LowFlg
endif

The bitwise Boolean operator "&" (AND) is used to determine if any bits in RELAY[2] are set at the bit positions determined by L. The result of the & operation will be either 0 or something non-zero. If any bits are set in RELAY[2] that correspond to bits in the L map the result will be non-zero and the SetIO LowFlag statement will execute.

I'm sorry that the length of the explanation.

Gary D
« Last Edit: January 15, 2020, 01:35:44 AM by garysdickinson »