Projects

PIC18F45K22 Serial Port Communication

Sun, Jul 16th, 2017   -   Project Status: Closed
PIC18F45K22 Serial Port Communication

PIC18F45K22 Microcontroller

This article describes how to setup and program a PIC18F45K22 microcontroller for serial communication. At project completion, for every byte the PIC micro receives in it's serial port buffer, it will transmit the same value out the serial port. Learning to program your microcontroller to communicate using the serial port, will open the door to many fun and interesting projects. For example, it is possible to have your microcontroller send messages to a WIFI micro, such as the ESP8266, using the serial port. This allows your microcontroller to communicate with the world using the internet.

The PIC18F45K22 contains two peripheral modules for serial I/O called the Enhanced Universal Synchronous Asynchronous Receiver Transmitter (EUSART). My program will use the EUSART in Asynchronous Mode. To read the details of how the module operates in this mode, read page 269 of the PIC18F45K22 datasheet.

PIC18F45K22 Datasheet

This article is a continuation of my previous PIC18 article titled An Introduction to the PIC18F45K22 Micro. To successfully complete this project by following this tutorial, I recommend reading my previous article first or you may miss important details previously mentioned.

As mentioned in my previous article, I am using the MPLAB X IDE version v3.20 and version v1.35 of the XC8 compiler by Microchip. My PIC program will use a peripheral library that was included with this compiler version that contains functions for serial communication. Newer compiler versions do not have this library included, as Microchip has introduced a new way to setup peripheral support on their microcontrollers. However, you may still download the legacy peripheral library from their compiler download page HERE

The peripheral library from Microchip contains functions that abstract away many low-level details to allow easier programming of such things as serial communication, analog-to-digital conversion, and EEPROM read/write. To use this library, add the following include directive to the file named main.c from the previous PIC18 article:

#include < plib\usart.h >

The usart.h header file facilitates PIC serial communication by providing simple functions to read from and write to the serial port buffers. For this simple program example, each byte the PIC receives in it's serial port buffer, it will transmit, or echo the same byte out it's serial port. Add a char variable to the code to hold the byte for reading and writing to the USART buffer.

unsigned char c;

No new code will be added to the main loop. It will do exactly the same thing it did in the last project, call the function FlashLEDs. The CPU will continually execute the code that this function contains, which simply flashes the LED that is connected to pin 20 (RD1) of the PIC. You may be wondering how the CPU will execute code related to the serial port? By enabling the peripheral interrupts, the CPU will be interrupted whenever there is activity on a peripheral module, such as the USART. The CPU will then execute the code defined in an interrupt service routine, or ISR and then return to executing the code in the main loop. Therefore, next I add a function prototype named isr, that will contain the code to be executed when the CPU is interrupted. Note the interrupt keyword that identifies this function as an ISR.

void interrupt isr(void);

In the isr function, the first thing to do is check if the serial port buffer received any data. If it did, assign the byte received to the variable c we defined earlier. Then write this value to the USART transmit buffer so it may be transmitted out the serial port. The peripheral library has two functions Read1USART() and Write1USART(byte) which read a byte from the serial receive buffer and write a byte to the serial transmit buffer respectively. Here is the code for the isr:


// interrupt service routine
void interrupt isr(void){
//If the serial port has received a byte
if((PIR1bits.RC1IF == 1)&&(PIE1bits.RC1IE == 1)){
// Read the byte received and assign to variable c
c = Read1USART();
// Transmit what was received out the serial port
Write1USART(c);
//Clear ISR flag
PIR1bits.RC1IF = 0;
}
}

Pin 26 (RC7) and pin 25 (RC6) are the USART1 receive and transmit pins respectively. Set these pins to 1 as stated on page 268 of the PIC18F45K22 datasheet. The EUSART will automatically reconfigure the pins from input to output as needed. To prevent interference from the analog system on port C, I will set port C to all digital. The following code, defined inside the main function sets RC6 and RC7 to 1, enables the interrupts including the peripheral interrupts, and sets port C to all digital.


TRISCbits.RC6 = 1;
TRISCbits.RC7 = 1;
//analog PORTC ports may interfere with serial port receive
ANSELC = 0X00; //Make all PORTC pins digital
RCONbits.IPEN = 0; //Disable using interrupt priority
INTCONbits.GIE = 1; //Enable all unmasked interrupts
INTCONbits.PEIE = 1; //Enable all unmasked peripheral interrupts

Next, the code will close the serial port if it was previously open. This clears any setup associated with the serial port.

Close1USART();  //turn off USART if was previously on

To setup the serial port, the peripheral library contains a function named Open1USART(unsigned char config, unsigned int spbrg). The first parameter is passed as a bitmask created by performing either bitwise AND operations or bitwise OR operations. The second parameter is an integer value that is written to the baud rate generator. The value 8 will result in a baud rate of 115200. Page 280 of the PIC18F45K22 datasheet discusses the EUSART Baud Rate Generator, or BRG. On this page it explains how to calculate the value to be passed as the second parameter of Open1USART for a given baud rate. In short, the following formula is used:

16(n + 1) = Fosc / BaudRate

baud rate formula


Next is the complete code to configure the USART. This code goes in the main function.


//configure USART
Open1USART(USART_TX_INT_OFF &
USART_RX_INT_ON &
USART_ASYNCH_MODE &
USART_EIGHT_BIT &
USART_CONT_RX &
USART_BRGH_HIGH,
8);//8 = x. Calculated x using 16(x + 1) = Fosc / Baud Rate
// This gave me a 115,200 baud rate

In addition to writing code, it is necessary to provide a means for a computer to connect to the PIC so that serial data can be exchanged. I added 5 header pins to the breadboard. From these header pins I added wires that extend from the header pins to pin 26 and 25, the USART1 RX and TX pins respectively. The next image shows the setup. Note also the ground wire that extends from the header pin that is the closest to the PIC.

header pin setup

Here is the complete code of main.c



/***********************************************
* Project Name: PIC18-USART
* Author: Frank Mock
* File Name: main.c
* Microcontroller used: PIC18F45K22
* Compiler used is XC8 VERSION 1.35
* Description: The PIC will receive and transmit via it's serial port
* Serial Port Settings: Baud rate 115200, 8 bit, no flow control, no stop bit
****************************/

#include< xc.h >
#include< plib\usart.h >
// Oscillator Selection bits (Internal oscillator block)
#pragma config FOSC = INTIO67
// MCLR Pin Enable bit (MCLR pin enabled, RE3 input pin disabled)
#pragma config MCLRE = EXTMCLR
// Watchdog Timer Enable bits (Watchdog timer is always disabled)
#pragma config WDTEN = OFF
#define _XTAL_FREQ 16000000 //speed of the internal oscillator
unsigned char c; // will hold rx and tx value
// Function prototypes
void SetUpClock();// setup internal oscillator
void interrupt isr(void); //UART receive interrupt handler
void delay_seconds(unsigned char s); //Creates delay in seconds
void FlashLEDs(); //Flashes an LED at one second intervals

int main(){
SetUpClock(); //internal clock set to 16MHz
ANSELD = 0; //Configure PORTD as digital
TRISD = 0; //Configure PORTD as output
PORTD = 0b00000000; //initial state - PORTD all off

/*
* According to page 268 of the data sheet, TRIS control bits of
* RX and TX should be set to 1. USART will automatically reconfigure
* them from input to output as necessary
*/

TRISCbits.RC6 = 1;
TRISCbits.RC7 = 1;

//analog PORTC ports may interfere with serial port receive
ANSELC = 0X00; //Make all PORTC pins digital
RCONbits.IPEN = 0; //Disable using interrupt priority
INTCONbits.GIE = 1; //Enable all unmasked interrupts
INTCONbits.PEIE = 1; //Enable all unmasked peripheral interrupts

Close1USART(); //turn off USART if was previously on

//configure USART
Open1USART(USART_TX_INT_OFF &
USART_RX_INT_ON &
USART_ASYNCH_MODE &
USART_EIGHT_BIT &
USART_CONT_RX &
USART_BRGH_HIGH,
8);//8 = x. Calculated x using 16(x + 1) = Fosc / Baud Rate
// This gave me a 115,200 baud rate
for(;;){
FlashLEDs();
}
} // END main

/*IRCF<2:0> Set Up Internal RC Oscillator Frequency Select bits
* 111 = HFINTOSC - (16 MHz) SEE PAGE 32 OF DATASHEET
*/

void SetUpClock(){
OSCCONbits.IRCF0 = 1;
OSCCONbits.IRCF1 = 1;
OSCCONbits.IRCF2 = 1;
}

// interrupt service routine
void interrupt isr(void){
//The serial port has received a byte
if((PIR1bits.RC1IF == 1)&&(PIE1bits.RC1IE == 1)){
// The serial port has received a byte
c = Read1USART();
// Transmit what was received out the serial port
Write1USART(c);
//Clear ISR flag
PIR1bits.RC1IF = 0;
}
}

/* Creates delay in seconds
* parameter s is the number of seconds */

void delay_seconds(unsigned char s){
unsigned char i,j;
for(i = 0; i < s; i++){
for(j = 0; j < 100; j++)
__delay_ms(10);
}
}

//Flashes an LED at one second intervals
void FlashLEDs(){
for(int i = 0;i < 2; i++){
PORTDbits.RD1 = 1; //LED 1 ON
delay_seconds(1);
PORTDbits.RD1 = 0; //LED 1 OFF
delay_seconds(1);
}
}


Before attempting to compile this code, it is first necessary to configure the project so that the linker knows to use the peripheral library. To do this in MPLAB X go to Run/Set Project Configuration/Customize Click the XC8 linker option from the categories tree on the left. Then select Link in Peripheral Library checkbox. Then click Apply.

link plib to project

Now compile the code by going to Run/Build Project


Build Project


In the console window at the bottom of the MPLAB X IDE, you should see a message stating success compiling and linking the code.

compile code


Next, the program needs to be transferred into the PIC18F45K22. Click the Program Device button at the top of the IDE.

program PIC


Next connect a serial port cable from the PIC to your computer and open a serial terminal program. If you have used the code above, be sure to set the baud rate to 115,200. The serial cable I have automaticaly converts the 3.3 volt signal from the PIC into the 5 volts the RS232 serial protocol expects. If you do not have a serial cable that does the voltage conversion for you, you may consider running your PIC at 5 volts (see my previous article). When you send a message to the PIC, the PIC will respond by echoing it back. In the image below, I am using Real Term to send a message, Frank, to the PIC and the PIC is echoing it back.

Pic echos message back

If you have considered trying to program a PIC before, especially for serial communication, I hope this article has inspired you to give it a try. Feel free to send me a message by using my Contact page if you have any questions or comments.

The PIC18F45K22 page on the Microchip website.PIC18F45K22 Info

Project Images

The USART1 RX and TX pins on the PIC18F45K22

The USART1 RX and TX pins on the PIC18F45K22

PIC18F45K22 Microcontroller

PIC18F45K22 Microcontroller