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..7RELAY[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 | Hexadecimal | Binary |
RELAY[1] as 16-bit | -32764 | 8004 | 1000 0000 0000 0100 |
RELAY[1] as 32-bit | -32764 | FFFF8004 | 1111 1111 1111 1111 1000 0000 0000 0100 |
&h00ff value | 255 | 000000FF | 0000 0000 0000 0000 0000 0000 1111 1111 |
RELAY[1] & &h00ff | 4 | 00000004 | 0000 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..7The 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 | Hexadecimal | Binary |
N | 4 | 0000004 | 0000 0000 0000 0000 0000 0000 0000 0100 |
N-1 | 3 | 00000003 | 0000 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 | Hexadecimal | Binary |
N=1, L | 0 | 00000000 | 0000 0000 0000 0000 0000 0000 0000 0000 |
N=2, L | 1 | 00000001 | 0000 0000 0000 0000 0000 0000 0000 0001 |
N=4, L | 3 | 00000003 | 0000 0000 0000 0000 0000 0000 0000 0011 |
N=8, L | 7 | 00000007 | 0000 0000 0000 0000 0000 0000 0000 0111 |
N=16, L | 15 | 0000000F | 0000 0000 0000 0000 0000 0000 0000 1111 |
N=32, L | 31 | 0000001F | 0000 0000 0000 0000 0000 0000 0001 1111 |
N=64, L | 63 | 0000003F | 0000 0000 0000 0000 0000 0000 0011 1111 |
N=128, L | 127 | 0000007F | 0000 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 | Hexadecimal | Binary |
N=1, H | 254 | 000000FE | 0000 0000 0000 0000 0000 0000 1111 1110 |
N=2, H | 252 | 000000FC | 0000 0000 0000 0000 0000 0000 1111 1100 |
N=4, H | 248 | 000000F8 | 0000 0000 0000 0000 0000 0000 1111 1000 |
N=8, H | 240 | 000000F0 | 0000 0000 0000 0000 0000 0000 1111 0000 |
N=16, H | E0 | 000000E0 | 0000 0000 0000 0000 0000 0000 1110 0000 |
N=32, H | C0 | 000000C0 | 0000 0000 0000 0000 0000 0000 1100 0000 |
N=64, H | 128 | 00000080 | 0000 0000 0000 0000 0000 0000 1000 0000 |
N=128, H | 0 | 00000000 | 0000 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