Sending serial data from the PIC18F4620 to the PC

Sometimes, it’s extremely useful to be able to transmit data serially to or from a microcontroller. Fortunately, the PIC18F4620 has a built-in serial port that can be used for this purpose. In this example, I’m going to show how to send text from the PIC18F4620 to the PC screen very easily.

This can be very convenient when you’re debugging your system. For example, you could print out sensor readings from your analog inputs in real time. If your circuit already includes the connections between the PICkit 2 and the PIC18F4620, only a very small modification is required to facilitate serial data communication. Basically, pins 4 and 5 on the PICkit 2 need to be connected to the TX and RX pins on the PIC (pins 25 and 26 respectively).

To actually view the data being transmitted serially by the PIC, the PICkit2 application can be used. This small, but very useful program can be downloaded for free from

If you’re using MPLAB to write your C code, then before starting the PICkit 2 application, you should first ensure that the PICkit2 is not currently in use by doing the following:

  • In MPLAB: “Programmer -> Select Programmer -> None”

To get the communication link up and running, you need to do a few things:

  • Start the PICkit 2 application.
  • from the Tools menu, select “UART Tool…”. If you don’t see that item in the tools menu, it’s possible that you’re running an older version of the PICkit 2 application, in which case you’ll need to upgrade. I’m running version 2.61, so I know that it’s included in that version.
  • Set the baud rate (the dropdown box in the top left corner) to 2400.
  • Tick the VDD box to tell the PICkit 2 to supply power to the circuit.
  • Click the “Connect” button.

Once you do this, any text transmitted by the PIC should appear in the white box.

What actually happens each time the PIC transmits this short message ("AN0 = 0000") is that each of the ten characters ("A", "N", "0", " ", "=", " ", "0", "0", "0", "0") is represented by a single ASCII byte and transmitted one bit at a time over the serial link. Here’s a snapshot I made (using the PICkit 2 application’s “Logic Tool”, which is also in the Tools menu) of the voltage waveform on the PIC’s TX pin while one message is being transmitted:

The code I used for this example is based on my standard template code for the PIC18F4620. If you’re already using my template code as the basis of your program, then you’re basically ready to start printing messages. The serial port (aka the “USART” – universal synchronous / asynchronous receiver / transmitter)  is configured at power up time by my “setup” function. The baud rate (the number of bits transmitted per second) is set to 2400. Once the USART has been configured, text can be sent to the PC very easily using the “printf” function, which is part of the C standard library.

The main while loop of my program repeats the following steps indefinitely:

  • Switch on LED
  • Read voltage from AN0 using the read_analog_channel function
  • Send voltage reading to PC using the printf function
  • Switch off LED
  • Delay for 1 second

Here’s the complete code:

// PIC18F4620 serial transmit example
// Written by Ted Burke (
// Last update 20-3-2012

#include <p18f4620.h>
#include <delays.h>
#include <usart.h>
#include <stdio.h>

#pragma config OSC = INTIO67
#pragma config MCLRE = OFF
#pragma config WDT = OFF
#pragma config LVP = OFF

// Function prototypes
void setup(void);
unsigned int read_analog_channel(unsigned int);

void main(void)
	int voltage;

	setup(); // Configure the PIC

		voltage = read_analog_channel(0);
		LATDbits.LATD0 = 1;  // Set RD0 high
		printf("AN0 = %04d\r\n", voltage);
		LATDbits.LATD0 = 0;  // Set RD0 low
		Delay10KTCYx(200);   // 1s delay

void setup(void)
	// Set clock frequency (section 2 of the PIC18F4620 Data Sheet)
	// Set Fosc = 8MHz, which gives Tcy = 0.5us
	OSCCON = 0b01110000;

	// Set up ADC (section 19 of the PIC18F4620 Data Sheet)
	// Enable AN0-7 as analog inputs
	ADCON1 = 0b00000111;
	// Left justified result, manual acquisition time,
	// AD clock source = 8 x Tosc
	ADCON2 = 0b00000001;

	// Set up Port B (section 9.2 of the PIC18F4620 Data Sheet)
	// RB0-5 outputs, RB6-7 inputs
	LATB = 0b00000000;
	TRISB = 0b11000000;

	// Set up Port D (section 9.4 of the PIC18F4620 Data Sheet)
	// RD0-3 digital outputs, RD4-7 digital inputs
	LATD = 0b00000000;
	TRISD = 0b11110000;

	// Set up PWM (section 15 of the PIC18F4620 Data Sheet)
	// Set PWM frequency=36kHz and duty cycle=50% on both channels
	CCP1CON = 0b00001100;	// PWM on CCP1
	CCP2CON = 0b00001100;	// PWM on CCP2
	TRISC = 0b11111001;		// CCP1, CCP2 as outputs
	T2CON = 0b00000100;		// Enable TMR2 with prescale = 1:1
	PR2 = 55;				// period = (PR2+1) * Tcy * prescale
	CCPR1L = 27;			// Ch 1 duty cycle = CCPR1L / PR2
	CCPR2L = 27;			// Ch 2 duty cycle = CCPR1L / PR2

	// Set up USART (section 18 of the PIC18F4620 Data Sheet)
	// baud_rate = Fosc/(16*(spbrg+1))
	//           = 8000000/(16*(207+1)) = 2403.846 bits/s

// Read voltage from the specified channel.
// This function takes approximately 35us.
unsigned int read_analog_channel(unsigned int n)
	unsigned int voltage;

	ADCON0 = n << 2;
	ADCON0bits.ADON = 1;
	Delay10TCYx(3); // 15us charging time
	ADCON0bits.GO = 1;
	while (ADCON0bits.GO); // Await result (11us approx)

	// Return the result (a number between 0 and 1023)
	voltage = ADRESH;
	voltage = (voltage << 2) + (ADRESL >> 6);
	return voltage;
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s