BIT manipulation

Setting a bit within a byte

To set a bit to 1 use the OR operator.

The OR operator is similar to the ADD operator in that it takes two arguments and produces a result.

The XCSB OR operator is the '|' (vertical bar) character

BEWARE: XCSB has both a bitwise OR operator and a logical OR operator. The logical OR operator is '||' (two vertical bar characters).

How it works

The OR operator forces a 1 in a column where a 1 exists in either the first argument or the second argument.
e.g.
argument 1 0 0 1 0 0 1 0 0
argument 2 0 0 1 0 0 0 0 1
result 0 0 1 0 0 1 0 1
Written in XCSB this would be
	ARG1 = 0x24
	ARG2 = 0x21
	result = ARG1 | ARG2

	// this could be written using constants as
	result = ARG1 | 0x21

	// or as
	result = 0x24 | ARG2
The above example shows the result of a bitwise OR operation.

Setting bits within an existing variable or output PORT is achived by assigning the result back to one of the arguments

	PORTA = PORTA | 0x21
This is equivalent to forcing bits 0 and 5 to 1 in PORTA

(see a more detailed explanation of OR operator)

Clearing a bit within a byte

To set a bit to 0 use the AND operator.

The AND operator is similar to the ADD operator in that it takes two arguments and produces a result.

The XCSB AND operator is the '&' (ampersand) character

BEWARE: XCSB has both a bitwise AND operator and a logical AND operator. The logical AND operator is '&&' (two ampersand characters).

How it works

The AND operator forces a 0 in a column where a 0 exists in either the first argument or the second argument.
e.g.
argument 1 0 1 0 0 1 0 0 0
argument 2 0 1 0 0 0 0 1 0
result 0 1 0 0 0 0 0 0
Written in XCSB this would be
	ARG1 = 0x48
	ARG2 = 0x42
	result = ARG1 & ARG2

	// this could be written using constants as
	result = ARG1 & 0x42

	// or as
	result = 0x48 & ARG2
The above example shows the result of a bitwise AND operation.

Clearing bits within an existing variable or output PORT is achived by assigning the result back to one of the arguments

	PORTA = PORTA & 0x42
This is equivalent to forcing all bits except bits 1 and 6 to 0 in PORTA

This turns out to be difficult to visualise. It would be much simpler if we could force all bits represented by 1 to 0;

This is actually very easy to accomplish if we use the bitwise NOT operator. The XCSB bitwise NOT operator is the '~' (tilda) character (NOTE: this operator only takes one argument, it is like placeing a minus in front of an expression to change the sign of the result)

	PORTA = PORTA & ~0x42
This is equivalent to forcing bits 1 and 6 to 0 in PORTA

(see a more detailed explanation of AND operator)

The XCSB bitwise NOT operator has the effect of changing all ones to zeros and all zeros to ones

e.g.
argument 0 1 0 0 0 0 1 0
result 1 0 1 1 1 1 0 1

(see a more detailed explanation of NOT operator)

Using bit numbers instead of masks

Instead of using a bit mask such as 0x40 it is possible to use a bit number to address a bit within a byte. For any memory location (including PORTA) the bits within the location are numbered as:

7 6 5 4 3 2 1 0

(See a more detailed description of bit numbers)

To set bit 6 of PORTA to 1 we could use the XCSB statement

	PORTA = PORTA | (1 << 6)
XCSB is actually clever enough to realise what it meant and it will generate the single PIC instruction to perform the operation
	bsf	PORTA,6
To set bit 6 of PORTA to 0 we could use the XCSB statement
	PORTA = PORTA & ~(1 << 6)
Again XCSB is clever enough to realise what it meant and it will generate the single PIC instruction to perform the operation
	bcf	PORTA,6
The advantage of using bit numbers over simple masks is not clear from these simple examples. The fact is that in some circumstances it is much simpler to perform calculations on bit numbers than it is on masks. Consider the situation where you need to store a PORT address and a bit within the port in a table so that you can step through the table turning PIN's on and off. If you use a mask you will also need to store the address of the port along with the mask. If you store a bit number you can code this into 3 bits (0 to 7) which leaves the remaining 5 bits available for use as a port number.
	for j=0 while j<64 step j+=1 do

		acc = tbl[j]
		bit_number = acc & 7
		port_number = acc >> 3

		PORTA[port_number] = PORTA[port_number] | (1 << bit_number)

		wait()
	done

Bits and Masks

BITS    HEX Bit
7 6 5 4 3 2 1 0   Expr
 
0 0 0 0 0 0 0 0    0x00    (0 << 0)
0 0 0 0 0 0 0 1    0x01    (1 << 0)
0 0 0 0 0 0 1 0    0x02    (1 << 1)
0 0 0 0 0 1 0 0    0x04    (1 << 2)
0 0 0 0 1 0 0 0    0x08    (1 << 3)
0 0 0 1 0 0 0 0    0x10    (1 << 4)
0 0 1 0 0 0 0 0    0x20    (1 << 5)
0 1 0 0 0 0 0 0    0x40    (1 << 6)
1 0 0 0 0 0 0 0    0x80    (1 << 7)