05. Inputs and Outputs
Definition
By definition, a CPU will always have some sort of an IO. In the very least, a program must be somehow delivered to the CPU. In the most common case however, the term inputs and outputs (IOs) are usually used to refer to inputs and outputs during the run-time of the circuit/program.

IOs operations on the PIC24 are done through the pins. There are several modes of usage on the PIC24’s, depending on whether the IOs are used in digital or analog mode. First determine what the microcontroller needs to do. If for example, you want to measure a voltage using the PIC24’s ADC, then you’ll need to configure that pin into an analog input. If you want to end a signal to an open drain NPN transistor, then you’ll want to configure that pin into a digital output.
Pin Capabilities
You must be careful however, when assigning pins because not all pins can be configure any which way desired. Certain pins can only be configured as digital IOs, while other may be configured as analog or digital. In addition, the voltages which can be applied to the pins depend on the model of the chip. You must read the datasheet carefully before applying anything more than the Vdd voltage used to power the chip. What I mean by this is that certain models, even though they might be powered by a 3.3V power source, will be able to accept 5V as an input on digital IO pins, and can output 5V with an open drain configuration. Most of the PIC24s fall into this category. I haven’t tested the 5V open drain output myself, but this is because I usually add an external open drain circuit outside of the controller itself. This is mostly done as a superstition, or just precaution, but whatever is listed on the datasheet should work. However, I can attest to the fact that 5V on any of the digital pins will not damage any of the specified PIC24s.
Finally, on the low pin count models, the peripheral abilities of the pins are not fixed. This makes assigning pins to peripheral modules a bit trickier than the higher number pin models. We will discuss these issues in just a little bit.
Configurations
Before configuring the pins, you must first be able to identify the pins on the diagram. In the diagram below taken directly from Microchip’s datasheet, you’ll notice several things.

- Banks of analog pins have the prefix AN (ex. AN0, AN1 … AN16).
- There are several banks of pins with levels RA (ex. RA0, RA1 …) and RB (ex. RB0, RB1 …). These are your main input and output banks. Depending on the model of the chip, there might even be a “C” bank (ex. RC0, RC1 …), and even up to a “G” pin bank.
- On the low pin count models, there are pins with the prefix RP (ex. RP0, RP1 … RP16). These are the configurable pins for the peripheral modules.
As an example, I have put down a script from one of my old projects. This is how a typical pin configuration code might look like. I will explain what each of the lines mean after. I have also taken out any other configurations so that we can concentrate on the IO portion of the code. The was done on the PIC24HJ32PG204, so your chip’s configuration registers might be a bit different.
(IO configuration example)
(#include directives go here)
(Configurations go here)
//main function start
int main(void)
{
(Oscillator Configuration go here)
//Set up I/O Port
AD1PCFGL = 0xFFFF; //set to all digital I/O
TRISB = 0xFFFF; //configure all PortB as input
TRISC = 0xFFFF; //configure all PortC as input,
RPINR18bits.U1RXR = 2; //UART1 receive set to RB2
RPOR1bits.RP3R = 3; //UART1 transmit set to RB3
(other initializations go here)
//Main Program Loop, Loop forever
while(1)
{
(rest of the program)
Analog or Digital
The register AD1PCFGL controls analog/digital pin selection. As you can see from the diagram, some of the pins have dual functions. When this is the case, the programmer must specify whether they will be as analog or digital pins. By setting it to 0xFFFF, all the pins from AN0 to AN16 will be digital. If for example, I want to use AN5 as an analog pin, and the rest as digital, my assignment line would look like this:
AD1PCFGL = 0b1111111111011111; //assign analog to AN5, rest digital
Or
AD1PCFGL = 0xFFDF; //assign analog to AN5, rest digital
Inputs or Outputs
If the pin is not a shared analog/digital pin, or if the pin is configured as a digital pin, then the pin must be assigned as an input or an output. This function is controlled by the register TRISx, where x is the bank identifier. In the above example, I assigned both banks, RB, and RC as all inputs. In another example, if I want my RB0 – RB3 to be inputs and RB4 – RB15 to be outputs, the code would look like the following:
TRISB = 0b0000000000001111; //pin RB3-0 as inputs, rest outputs
Or
TRISB = 0x000F //pin RB3-0 as inputs, rest outputs
Special Peripherals
The RPx set of pins can be set to any number of special peripherals. When this occurs, any other configurations such as the input/output selection and the analog/digital selection are overridden. Not all chips have this feature. Usually on the low pin count chips rely on this method of assigning peripheral modules because it allows for more flexible pin placement.
There are several peripheral modules available on the PIC24. These include UART, SPI and several other modes. The inputs functions (ex. UART receive), are configured differently from the output functions (ex. UART transmit).
To configure the peripheral inputs, refer to the peripheral input mapping section of the datasheet.

On the PIC24HJ32PG202, there is a bank of registers named RPINRx. Each of these registers is assigned a function. To assign them to a pin, the programmer puts the RPx pin number into those registers. For example, in the above image, the external interrupt is located in the register bank RPINR0. To assign pin RP2 to that pin, the code would look like the following:
RPINR0.INT1 = 2; //assign RP2 to interrupt 1
In a similar fashion, in the original example taken from my old project, the same is true.
RPINR18bits.U1RXR = 2; //UART1 receive set to RB2
The assignment of the function U1RXR, UART receive is assigned to pin RP2/RB2 (it’s the same physical pin).
Configuring an output function is different. This time, each of the pins are assigned a register (as opposed to a function assigned to a register). These are listed as follows on the PIC24HJ32PG202.

The assignment is done by tying the function to the register. The register RPOR5.RP11R for example, is the register assigned to pin RP11. If I want to make it a UART transmit pin, then the code looks like the following:
RPOR5.RP11R = 3; //UART TX to RP11
That should allow you to do most of all inputs and outputs. I’m sure you can figure out the rest on your own.
Reading and Writing to Pin Banks
While configuring pins might be useful, to actually use them, the pins must be read and written to. This is a very simple task.
To write to a pin, first, make sure that the pin is configured as digital (you cannot output to an analog configured pin). Next, make sure that the pin is configured as an output. Lastly, to write to the pin, use the register LATx, where x is the pin bank identifier. For example, if I want to write a 1 to RB0, I could use the following code:
LATB = 0x0001; //RB0 = 1
Or
LATB = 0b0000000000000001;
However, since the header file already has assignments for individual pins, there’s no need to write the full 16 bit information to LATB. You can do the following:
LATBbits.LATB0 = 0; //RB0 = 0
To read a pin, make sure that the pin is configured as digital and as an input. Use the PORTx register to read their values:
int x = 0;
x = PORTBbits.PORTB0; //assign pin RB0 to x
Of course, you can read the whole bank if you wish, with the following assignment:
int x = 0;
x = PORTB; //assign pin RB0-16 to x
I will not cover the analog inputs in this section. Those goodies will be discussed in future updates. However, this should get you started for now.
Table of Contents
Previous – Configurations
Next – Oscillator and Timing

Entries (RSS)
I was wondering if you’re sure that this statement you have on the inputs and outputs page is correct “The assignment of the function U1RXR, UART receive is assigned to pin RP2/RB7 (it’s the same physical pin). I looked through the pic24 datasheets and RP2 = RB2.
You are correct. This is from an old program and I just copied and pasted. Thanks for pointing it out! It should be fixed.
LATBbits.LATB0 = 0; //RB0 = 1
Did you mean this sets ‘RB0 = 0′ ?
Thanks!
You are correct, comment fixed.
Thanks,
-J