7.2 Defining And Using Bits
The interrupt routine shown in this chapter modifies a flag that is used by main-line code to set the state of the LED. The flag's state is set by the ISR. As this flag only needs to hold a true or false value, it was defined as a bit object to save on storage space and make checking its contents more efficient.
LEDState is defined by the following lines of
code:PSECT bitbss,bit,class=BANK1,space=1
LEDState:
DS 1 ;a single bit used to hold the required LED stateThe inclusion of the bit flag with the psect definition instructs the
linker that the units of address within this psect are bits, not bytes. This means that
the DS 1 directive, which allocates one unit of storage, is reserving a
single bit, not a single byte. The LEDState object, then, can hold only
a single bit.
PSECT bitbss,bit,class=BANK1,space=1
LEDState:
DS 1 ;a single bit used to hold the required LED state
otherState:
DS 1 ;a single bit for some other purposethen
these two bits would reside in the same byte of memory, but would, of course, be at
different bit positions within that byte.LEDState) represents
a bit address, not a byte address, and this affects how these symbols should be used in
instructions. The PIC instructions that perform bit operations, such as
bcf or btfss, require a byte address operand
followed by a bit position within that byte. A bit object that is located at bit address
0x283, for example, is located at byte address 0x283/8, which is 0x50,
and at bit position 0x283&7, which is position #3. If you are using
a bit object with a bit instruction, then you will need to divide the bit address by 8
to obtain the byte (file register) address used in the instruction, and you will need to
perform a bitwise AND with 7 to obtain the bit position within that byte. For example,
the main-line example code that reads the desired state of the LED
uses: BANKSEL LEDState/8
btfss BANKMASK(LEDState/8),LEDState&7Note that the BANKSEL directive also requires a byte address argument,
so the bit address of LEDState was divided by 8 for this instruction as
well. The BANKMASK() macro has also been used with the file register
operand to the btfss instruction in the usual way, but make sure this
macro is acting on the byte address of bit objects, that is, the bit address divided by
8.
#define LEDSTATE BANKMASK(LEDState/8),LEDState&7which
could then be used as follows: BANKSEL LEDState/8
btfss LEDSTATELEDSTATE, above, and hence, they can be used in the same
way. For example, the code sequence in the
interrupt: btfsc TMR0IE
btfss TMR0IF
goto notTimerInt ;not a timer interrupt
bcf TMR0IFuses
both the TMR0IE and TMR0IF SFR bits, both of which
expand to the byte address that holds them (that being the addresses of PIE0 and PIR0,
respectively) and their bit position within those bytes. These SFR bits are available
once you include <xc.inc> into your source file.bit
flag in the map file by looking for the Scale value. For bit
psects, this will indicate a value of 8 and be left empty for non-bit psects. In the map
file produced for this example project, the bitbss psect is
shown. Name Link Load Length Selector Space Scale
build/default/debug/main.o
config 8007 8007 5 0 4
isrVec 4 4 A 8 0
resetVec 0 0 3 0 0
bitbss 500 A0 1 A0 1 8
code E E 1D 8 0Notice the link address of 0x500. This is a bit address. The load address, however, is converted to a byte address and is shown as 0xA0.
A bit psect can be linked anywhere in the data memory. To highlight how banking works
with bit objects, the psect containing the flag in this example was associated with the
BANK1 linker class, which means that it was automatically placed
somewhere in the bank 1 data memory. To access bit objects more efficiently, try to
place them in the common memory or in the Access bank on PIC18 devices.
