ME Labs, Inc.
  Developer Resources:

Programming Clues
    Sample Programs
Compiler Manual
    PICBASIC™ Compiler
    Serin2/Serout2 Modes
    ASCII Character Set
    Number Conversion
    Floating Point
    PBP Debug Monitor
    Articles and Tutorials

Hardware Clues
    Parts / Vendor List
    PICPROTO™ Boards
    LAB-X1 Docs
    LAB-X2 Docs
    LAB-X20 Docs
    LAB-X3 Docs
    LAB-X4 Docs
    LAB-XUSB Docs
    LAB-XT Docs

Accessing I/O pins and internal registers with PICBASIC PRO™ Compiler.

Assessing the I/O pins on a PICmicro® is very simple with PICBASIC PRO™.  You will need to know the official names of the port and data-direction registers.  Microchip assigns these names, and they can be found in the datasheet for the device you are using.  If you don't have the microchip datasheet, stop now and go get it.  They're available as free downloads from Microchip.  Don't try to program without the datasheet.

For the examples in this document, we will use PORTB as the I/O port name and TRISB as the data-direction register name.  These names are common to most PICmicros.  Our PICmicro is a PIC16F877.

Each PICmicro has pins that you can control for output, or read for input.  These pins are grouped into ports so that you can read or write to as many as 8 pins at once.  Typically, an I/O port represents 8 pins.

PORTB on a 16F877 has 8 bits, and each bit controls a pin.  When we look in the Microchip datasheet, we find that the PORTB pins are located on adjacent pins on the device.  RB0 (PORTB.0) is on pin-33, RB1 is pin-34... RB7 is pin-40.

Input and Output on an individual pin

Let's make our first goal to output 5V (logic 1) on physical pin-40, which is PORTB, bit-7.  If you are familiar with PICBASIC™, you may know that this can be done with the command, "HIGH 7".  This method is valid, but it hides an important step from you.  I want to demonstrate the manual method, which involves 2 steps.

The first thing you need to do is tell the PICmicro that you want the pin to be an output.  This is done by clearing the corresponding bit in the TRISB register (the data-direction register).  Since we are using bit-7 of PORTB, we will clear bit-7 of the TRISB register.

TRISB.7 = 0

Next, you will write the value that you want on the physical pin to it's PORTB equivalent.

PORTB.7 = 1

The data-direction registers will hold their settings until you change them.  You don't have to waste clock cycles clearing TRISB.7 each time you change the state of the I/O pin.  TRISB.7 = 0 only needs to be in your code once, near the top, unless you want to change PORTB.7 to an input.  You can change it to an input any time, with "TRISB.7 = 1".

When powered up, all the I/O pins on the device are configured as inputs.  To read the logic state of physical pin 39, just use the port name and bit exactly like you would a variable name.

StateOfRB6 = PORTB.6


If (PORTB.6 = 0) Then ButtonIsPressed

Input and Output on a Port (multiple pins)

You can access registers and ports without specifying the bit number.  This allows you to move 8 bits of data with one command.

Lets say you want to repeat the example above, but you want ALL the pins on PORTB to be driven high.  The code is basically the same, but you have to use 8 bits of data in your commands:

TRISB = %00000000    'set all PORTB pins as output

PORTB = %11111111    'make all PORTB pins high

To set PORTB as all input and read the input states of all pins to a variable:

TRISB = %11111111    'set all PORTB pins as input

StateOfPortB = PORTB    'read PORTB and store the 8-bit value in StateOfPortB

Specifying bits with variables

Sometimes it is desirable to specify the bit with a variable in your program.  This allows you to write to different bits, based on some condition in your code.

Let's write a code snippet which will count 0 to 7 and make the corresponding bit on PORTB high for each count.  To do this, we will use a bit offset.

i    var    byte    ' i will hold our count

TRISB = %00000000    'set all PORTB pins as output

For i = 0 To 7    'loop for 8 counts

    PORTB = %00000000    'make all pins low

    PORTB.0[i] = 1        'make pin number i high

    Pause 500            'pause for half a second

Next i        'go to the next count

This method works for setting pins high or low, but should not be used for more complex commands that accept a pin parameter.  An example of this is the COUNT command. 

To use a variable to direct the COUNT command to different pins, you must make use of the predefined labels for pins as described in the manual.  These labels allow you to use a number to address certain pins, instead of the port name.  This method only works on pins with predefined labels, which limits its use to 2 ports, or 16 pins.  To determine which pins may be accessed on a particular device, refer to the Pins section of the manual.

The following example uses a For loop to count pulses on each pin on port b.  This will work on 18, 28, and 40-pin PICmicro MCUs, with the exception of the 14C000.

i    var    byte    ' i will hold our count

W0    var    word[8]     ' define an array variable to hold the count result for each pin.

For i = 0 To 7    'loop for 8 counts

    Count i, 100, W0[i]    ' Count pulses on pin-i, and store result in the corresponding element of word array W0

Next i                'go to the next count

Assigning friendly names to pins

A common practice is to assign names to certain pins, to make your code easier to follow.  If PORTB.7 controls your warning LED, then you can assign the alias, "warnled".

warnled    var    PORTB.7    'assign alias name

TRISB.7 = 0    'set the pin as output

warnled = 1     'light the warning LED

Accessing Internal Registers

As you progress, you will want to read and write to the internal registers on the PICmicro.  These registers allow you to control and check the status of the hardware on the PIC®.

Once you know the names of the registers and what they do, the process is exactly the same as above.  In fact, we used the internal register TRISB to configure the PORTB pins. Complete descriptions of all the registers and their functions can be found in the Microchip datasheet for any PICmicro.

One of the common registers that must be configured for the 16F877 is ADCON1.  This register controls the analog-to-digital converters on the device.  If we want to shut off the converters in order to use the PORTA pins as digital I/O, we type:

ADCON1 = 7


ADCON1 = %00000111