PIC16F877A UART Serial Communication in PICSimLab
Serial output is the embedded developer’s printf: once the UART works, every later project gets easier to debug. This tutorial sends and echoes text from a PIC16F877A in PICSimLab at 9600 baud, 8N1 — and it starts with the one prerequisite that most beginners miss: the desktop simulator needs a virtual null-modem port before any PC terminal can talk to it.
What you need
- PICSimLab 0.9.3 — see the download page.
- MPLAB X IDE and the XC8 compiler.
- Board: McLab2 or PICGenios, microcontroller PIC16F877A.
- A way to see the serial data — either PICSimLab’s own IO Virtual term spare part (simplest, described below) or a PC terminal connected through a virtual null-modem pair.
The serial prerequisite (read this first)
Per the official PICSimLab documentation, desktop serial communication works through a NULL-MODEM virtual serial port: on Windows you install com0com, on Linux tty0tty (for example the pair /dev/tnt2 <=> /dev/tnt3). PICSimLab opens one end of the pair and your terminal program opens the other, both at 8N1. There is no direct pass-through to a real COM port, so skipping this step is the number one reason “the UART does nothing”.
For a first test you can skip the driver entirely: add the IO Virtual term spare part (Virtual category in Spare Parts) and connect it to the TX/RX pins — it is a virtual serial terminal inside PICSimLab. Note that the online version of PICSimLab is more limited here: it has no general serial support, only the IO Vterm.
Wiring used in this tutorial (example)
- USART TX → RC6, USART RX → RC7 (the PIC16F877A hardware USART pins)
- IO Virtual term RX → RC6 (TX), IO Virtual term TX → RC7 (RX) — serial lines always cross
Steps
1. Generate the project
Create the MPLAB X project for the PIC16F877A with the Code Project Wizard.
2. Set up the virtual port or virtual terminal
Easy path: open Modules → Spare parts, add Virtual → IO Virtual term and connect it in Properties as above. PC-terminal path: install com0com (Windows) or tty0tty (Linux), note the port pair it creates, point PICSimLab’s serial configuration at one end and your terminal at the other, 9600 8N1 on both sides.
3. Configure the USART in code
The example sets RC6/RC7 directions, loads SPBRG = 129 for 9600 baud at a 20 MHz clock with BRGH = 1, then enables the transmitter and receiver. If your board clock differs, recompute SPBRG with the datasheet formula instead of copying 129.
4. Build, load, run and type
Build in MPLAB X, load the .hex and start the simulation. The terminal should show “PIC16F877A ready” once, then echo every character you send back to you.
Example code (XC8)
// Example: USART echo at 9600 baud, 8N1 - PIC16F877A, XC8
// 20 MHz clock, BRGH=1: SPBRG = 20e6/(16*9600) - 1 = 129
#pragma config FOSC = HS
#pragma config WDTE = OFF
#pragma config PWRTE = ON
#pragma config BOREN = ON
#pragma config LVP = OFF
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CP = OFF
#include <xc.h>
#define _XTAL_FREQ 20000000 // Example: match the board clock
void uart_init(void) {
TRISCbits.TRISC6 = 1; // TX pin direction per datasheet
TRISCbits.TRISC7 = 1; // RX pin
SPBRG = 129; // 9600 baud at 20 MHz, BRGH=1
TXSTA = 0x24; // TX enabled, BRGH=1
RCSTA = 0x90; // Serial port on, RX enabled
}
void uart_putc(char ch) {
while (!TXSTAbits.TRMT) { } // wait for the transmit buffer
TXREG = ch;
}
void uart_puts(const char *s) { while (*s) uart_putc(*s++); }
char uart_getc(void) {
while (!PIR1bits.RCIF) { } // wait for a received character
return RCREG;
}
void main(void) {
uart_init();
uart_puts("PIC16F877A ready\r\n");
while (1) {
char ch = uart_getc(); // echo everything back
uart_putc(ch);
}
}
Try next
- HD44780 LCD — show received commands on a display.
- Timers and interrupts — receive serial data in an interrupt instead of polling.
- ETH W5500 spare part — the next step up from serial: network hardware.
Troubleshooting
Nothing appears in the terminal. Check the chain in order: virtual port pair installed and the two ends not swapped, same baud and 8N1 on both sides, TX and RX crossed between the microcontroller and the terminal, and the simulation actually running.
Garbage characters appear. That is a baud-rate mismatch: your SPBRG value does not match the real board clock. Verify the clock configured in PICSimLab, recompute SPBRG, rebuild and reload.
