PIC16 RS-232 I/O with the UART module

Here I’ll explain how to use the USART module on a PIC microcontroller to perform RS-232 I/O. Many PIC microcontrollers include a Universal Synchronous/Asynchronous Receiver Transmitter (USART) module. We can use this module to perform I/O from a DB-9 connector to talk to a PC over RS-232. For this demo I used the PIC16F88, but you can use any PIC with a USART module. I’m using the MPLAB X IDE and XC8 compiler available free from Microchip.


The RS-232 protocol calls for a differential pair around +/- 7.5V that’s not native to the TTL logic of the PIC, so another chip called the MAX232 is used for the conversion. It uses charge pumps and external capacitors to convert the signal levels. There are variations of the MAX232 that will work like the MAX232A and product offerings from other vendors, but anything falling under the category of RS-232 driver/receiver should suit our needs.

Note that the DB-9 pinout for RS-232 has pin 2 labeled as Rx and pin 3 as Tx. These labels are from the PC frame of reference, so you’ll need to connect T1OUT from the MAX232 to DB-9 Rx and R1IN to Tx.

Here’s the complete circuit:


The following configuration line directs the PIC to use its internal RC oscillator for the clock:
#pragma config FOSC = INTOSCIO // Internal oscillator

These lines will set the internal oscillator to 4 MHz and wait for the oscillator to settle before continuing:

OSCCONbits.IRCF = 0b110; // Set internal RC oscillator to 4 MHz
while(!OSCCONbits.IOFS); // Wait for frequency to stabalize

The baud rate is set to 9600 by setting TXSTAbits.BRGH = 1 and SPBRG = 25. The first command puts the PIC in high baud rate mode and the second sets the baud rate generator to 25. The baud rate generator in high baud rate mode is calculated as baud rate = Fosc / (16 * (SPBRG + 1)) or 9600 ~= 4000000 / (16 * (25 + 1)). The remaining statements in UART_Init set the UART in asynchronous, 8-bit mode and enable the module and transmitter.

For output to the UART, you can override the C library function putch. The stdio library calls this function during a printf operation, so by overriding putch to write the input character to the UART register TXREG. I also like to append a carriage return character ‘\r’ to a line feed character ‘\n’ so I don’t have to use \r\n in each printf statement.

Input is handled by overriding the library functions getch and getche. getch gets a single character and getche gets a character while echoing it back to the terminal. These functions are called by cgets which gets a string ending with (CR/LF). Character entry is signaled in the interrupt service routine ISR by setting the getchar_active flag and clearing the interrupt flag.

The main program will prompt for a string, print out that string, then reverse the string and print it. If there’s no output from the program, here’s some things you can do to troubleshoot your circuit:

  • Connect the serial port Rx to Tx and make sure characters are echoed to the terminal. This will verify that the serial port on your PC is configured correctly.
  • Connect R1OUT to T1IN on the MAX232. Verify that characters typed in the terminal are echoed back. This will verify that the MAX232 is operating properly.

Here’s the complete code:

Dan Milliken

Leave a Reply

Your email address will not be published. Required fields are marked *