Digital I/O: TRIS, PORT & LAT Registers
Three small registers per port are the entire interface for digital I/O on a PIC: one sets direction, one reads or writes the pin, and one is the safer way to write it.
Controlling a digital pin on a PIC comes down to three registers, repeated for each port (PORTA, PORTB, and so on). Once you understand this pattern for one port, it applies to every port on every PIC chip you'll ever use.
| Register | Job | Example |
|---|---|---|
| TRISx | Sets each pin's direction: 1 = input, 0 = output | TRISB0 = 0; makes RB0 an output |
| PORTx | Reads input pins, or writes output pins (older style) | if(PORTB0 == 1) {…} |
| LATx | The preferred way to write an output pin's state | LATB0 = 1; drives RB0 high |
The direction register is the one beginners most often forget: a pin's direction defaults to input on most PIC chips at power-on, so if your code writes to an output pin before setting its TRIS bit to 0, nothing happens — the pin is still configured as an input and simply ignores the write.
The difference between writing PORTx and writing LATx is subtle but worth knowing: PORTx reflects the actual voltage on the pin, which can be affected by outside factors like a loaded output or electrical noise; LATx is a separate internal "output latch" that always reflects exactly what you last told it to output, regardless of what's happening on the physical pin. For simple projects the difference rarely matters, but LATx is considered the more correct habit to build early.
// RB0 will drive an LED (output).
// RB1 will read a push button (input).
void main(void) {
TRISB0 = 0; // RB0 = output
TRISB1 = 1; // RB1 = input
while(1) {
if (PORTBbits.RB1 == 1) {
LATB0 = 1; // button pressed → LED on
} else {
LATB0 = 0; // button released → LED off
}
}
}