NU32v2: Digital Input and Output

From Mech
Revision as of 02:53, 23 January 2011 by Lynch (Talk | contribs)
Jump to: navigation, search

Digital inputs and outputs (DIO) are the simplest of interfaces between the PIC and other electronics, sensors, and actuators. The PIC32 has many DIO pins, each of which can take one of two states: high or low. More information can be found in Chapter 12 of the Data Sheet and Chapter 12 of the Reference Manual. Some special function registers (SFRs) are listed in Chapter 4 of the Data Sheet.



The PIC32 offers many digital I/O pins, arranged into "ports" A through G. The pins are labeled Rxy, where x is the port letter and y is the pin number. For example, pin 5 of port B is named RB5. Ports B and D are "full" 16-bit ports, with pins 0-15. Other ports have a smaller number of pins, not necessarily sequentially numbered; for example, port C has pins 1-4 and 12-15. All pins labeled Rxy can be used for input or output, except for RG2 and RG3, which are input only. For more details on the available pin numbers, see chapter 1 of the Data Sheet.

Each pin configured as an output can be configured to be a typical 0 or 3.3 V output (since our PIC is powered by 3.3 V), or to be "open drain." An open drain output can take one of two states: 0 V or "floating" (disconnected). An open drain output allows you to attach an external "pull-up" resistor from the output to any positive voltage, e.g., 5 V. Then when the output is left floating by the PIC, the external pull-up resistor will pull the voltage up to 5 V. A reasonable resistance for the pull-up is 1 K to 10 K ohms.

An input pin will read low if the input voltage is close to zero, and it will read high if it is close to 3.3 V. Many input pins will tolerate voltages up to 5 V; see the figure showing the PIC pins near the beginning of the data sheet. Some input pins, those that can also be used for "change notification" (labeled CNy), can be configured to have an internal pull-up resistor to 3.3 V. If configured this way, the input will read "high" if it is disconnected (left floating). Otherwise, if an input pin is not connected to anything, we can't be certain what the input will read.


The functions of the DIO pins are controlled by special function registers (SFRs). Each of these SFRs has 32 bits on the PIC32, but for many, only 16 of the bits are relevant. Depending on whether these bits are set to 0 or 1, different actions or settings are performed:

  • AD1PCFG: This SFR determines which of the 16 pins with an analog input function (port B) is treated as an analog input or a DIO pin. The 16 most significant bits (high bits) AD1PCFG<31:16> are ignored, but AD1PCFG<15:0> determine which of the 16 pins is treated as an analog input. 0 indicates analog input, and 1 indicates DIO. So if the bit AD1PCFG<7> is 0, then the pin with the function AN7 is an analog input; if AD1PCFG<7> is 1, then it is a DIO. By default, AD1PCFG = 0x0000, so all 16 pins are treated as analog inputs. To set AN15 and AN1 as analog inputs and the rest as DIO, we can use the C command AD1PCFG = 0x7FFD. To set AN15 and AN1 as analog inputs but leave the other settings unchanged, we can use the C command AD1PCFG &= 0x7FFD. Note we only had to specify 16 bits, or 4 hex digits, as the 16 most significant bits have no role. Instead of acting on the entire SFR, we could instead address an individual bit using AD1PCFGbits.PCFG15 = 0 to set the value of a single bit.
  • TRISx: This SFR determines which of the DIO pins of port x are inputs and which are outputs. For example, TRISBbits.TRISB5 = 0 sets RB5 as an output (0 = Output), TRISBbits.TRISB5 = 1 sets RB5 as an input (1 = Input), TRISB &= FF00 makes RB0..RB7 outputs while leaving the others unchanged, TRISB ^= FF00 makes RB8..RB 15 inputs while leaving the others unchanged, and TRISB = FF00 makes RB0..RB7 outputs and RB8..RB15 inputs.
  • LATx: A write to the latch sets the output for pins configured as digital outputs. For example, LATB = 0x00FF sets pins RB0..RB7 to high and pins RB8..RB15 to low.
  • PORTx: val = PORTB returns the current digital inputs for DIO pins configured as inputs.
  • ODCx: ODCB = 0x00FF sets RB0..RB7 as open drain, and pins RB8..RB15 as typical buffered output.
  • CNPUE: The relevant bits of this SFR are CNPUE<21:0>, and they apply only to the 22 change notification pins CN0..CN21. If CNPUEbits.CNPUE2 = 1, then the pin with CN2 function has the internal pull-up resistor enabled, and if CNPUEbits.CNPUE2 = 0, then it is disabled. The command CNPUE = 0xFFFFFF enables the internal pull-up resistor for all CN pins. The default has the pull-ups disabled.

Finally, SET (set), CLR (clear), and INV (invert) registers are available for all SFRs (e.g., TRISB, LATD, PORTA, ODCC, etc.). SET means that bits are set (made equal to 1), CLR means that bits are cleared (made equal to 0), and INV means that bits are inverted. So TRISBCLR = 0x0010 will clear bit 4 and TRISBSET = 0x0010 will set bit 4. Bits with a 0 associated are unchanged. The reason to use these functions is that they are faster than the read-modify-write method. For example, LATBSET = 0x0001 has the same effect as LATB ^= 0x0001, but the former is faster.

Other SFRs and their functions are described in Chapter 12 of the Reference Manual.

Library Functions

The peripheral library offers a number of function calls to help you use the DIO pins. These functions have names such as PORTRead, PORTSetPinsDigitalIn, PORTSetPinsDigitalOut, etc. C source code can be found in pic32-libs/peripheral/ports/source/*.c, and .h header files can be found in pic32-libs/include/peripheral/ports.h. The DIO functions are simple enough, however, that we will usually just set the appropriate SFRs manually, as described above and demonstrated in the example below.

Code Sample

This example uses two pins as digital outputs and one pin as digital input. When the switch is pressed, one LED will turn on and the other will turn off. When the switch is not pressed, the opposite LED will turn on and the other one will turn off.

Super simple Digital Output and Digital Input. 

#include <plib.h>


// Define constants for PINS D1 - D2 and C1
#define PIN_D1			LATDbits.LATD1	// Digital Output
#define PIN_D2			LATDbits.LATD2	// Digital Output
#define PIN_C1			PORTCbits.RC1	// Digital Input

int main(void)

       // Configure the proper PB frequency and the number of wait states 
	// Initialize Pins D1 and D2 output. 
	// Initialize pins D1 and D2 as high
	// Need to set TRIS bits 1 and 2 to low for output
	LATD |= 0x0006; TRISD &= 0xFFF9; // initialize 
	// Initialize Pin C1 as digital input
       // technically not necessary, since pins default to input
	TRISCbits.TRISC1 = 1;
	// Set all analog pins to be digital I/O
	// This line of code only needs to be used if your pins are Analog Input (B port)
       AD1PCFG = 0xFFFF;
       while(1) {
		// Toggle LEDS based on digital input
		if(PIN_C1) {
			PIN_D1 = 1;
			PIN_D2 = 0;
		else {
			PIN_D1 = 0;
			PIN_D2 = 1;
Personal tools