09.2 UART – Part 2 – Usage
9.2 UART – Part 2
In part 1 of the UART tutorial, I showed you the basic building blocks of the UART module. Included were three functions to initiate the module, and to send a receive data on the serial line.
So… …now what? Well, there’s tons of stuff you can do. The limitations are boundless, since there are so many products and chips with a UART controller on them. Your computer for example has a serial port, and it already has an application that can read and write in UART.
The limitation however is that serial port on your computer is implemented in RS-232, and the UART module on the PIC is in TTL levels. How can you get around this? Maxim IC sells a series of RS-232 to TTL transceivers that translate between the RS-232 levels to TTL levels. I usually use the MAX208; you can find the datasheet on their website.
I won’t go into how the circuit looks, but if I get enough demand for a circuit, I might eventually post an example. However, once you have it hooked up, you can see if the UART functions work. The following example shows how to use the functions discussed in the UART Tutorial, part 1.
Example: UART Repeater
Okay, so this is like a stupid device. There’s no useful application for a UART repeater, but I’ll include it anyways since it demonstrates well the send and receive capabilities of the PIC24. The device functions thusly: it waits for a signal on the RX line, and when it receives a signal, sends the exact data back on the TX line.
The UART RX pin is of course connected to some signal source that can produce a UART signal, at TTL levels, and the UART TX signal coming out of the PIC24, you can do whatever you feel like with it (it doesn’t matter, it’s just a demonstration of how to use the UART functions).
The project contains 4 files. The main file “main.c” contains the initializations and the main loop. The “uart1.c” and “uart1.h” files contain the functions for the UART module. The “system.h” file contains the “#include” directives for the specific PIC model that is selected by MPLAB IDE. For a review of why I use a “system.h” file, go to part 1 of the UART tutorial. My OSCI is running at 10 MHz (review oscillator functions here).
“system.h”
Engscope
Author: JL
July 16, 2007
System file, include all headers
*/
#if defined(__PIC24FJ64GA002__)
#include “p24FJ64GA002.h”
#include “pic_i2c.h”
#include “LCD.h”
#elif defined(__PIC24FJ32GA002__)
#include “p24FJ32GA002.h”
#include “pic_i2c.h”
#include “LCD.h”
#elif defined(__PIC24HJ32GP204__)
#include “p24HJ32GP204.h”
#include “pic24H_i2c.h”
#include “LCDLite.h”
#include “encoder.h”
#elif defined(__dsPIC30F3012__)
#include “p30f3012.h”
#endif
#include “accel.h”
#include “adc.h”
#include “uart1.h”
“main.c”
/*
Engscope Tutorial
UART Repeater
Author: JL
April 29, 2008
*/
#include “../h/system.h”
#include “timer.h”
#include “pic.h”
//prototype
void RepeaterProcessEvents();
unsigned int state = 0;
unsigned char temp1;
char flag1 = 0;
//Configs, EC clock, No protect, Watchdog Off
_FBS (BWRP_WRPROTECT_OFF & BSS_NO_FLASH);
_FGS (GSS_OFF & GCP_OFF & GWRP_OFF);
_FOSCSEL(FNOSC_PRI & IESO_OFF);
_FOSC (FCKSM_CSDCMD & IOL1WAY_OFF & OSCIOFNC_OFF & POSCMD_EC);
_FWDT (FWDTEN_OFF);
_FPOR (FPWRT_PWR1 & ALTI2C_ON);
int main(void)
{
OSCCON = 0x2200; //Use primary, no divide FCY = 10Mhz/2 = 5Mhz
CLKDIV = 0x0000; //do not divide
//Disable Watch Dog Timer
RCONbits.SWDTEN = 0;
//Set up I/O Port
AD1PCFGL = 0xFFFF; //set to all digital I/O
TRISB = 0xF3FF; //configure all PortB as input
RPINR18bits.U1RXR = 2; //UART1 receive set to RB2
RPOR1bits.RP3R = 3; //UART1 transmit set to RB3
UART1Init(15); //Initiate UART1 to 19200 at 10MHz OSCI
DelaymSec(1000);
//Main Program Loop, Loop forever
while(1)
{
//process data
RepeaterProcessEvents();
}
return(0);
}
//Repeater main function
void RepeaterProcessEvents()
{
unsigned char data = 0;
//wait for data to be received
data = UART1GetChar();
//send data back on UART TX line
UART1PutChar(data);
}
“uart1.h”
/*
Engscope
UART
April 16, 2008
Author: JL
*/
//prototypes
//Initiation
extern void UART1Init(int BAUDRATEREG1);
//UART transmit function
extern void UART1PutChar(char Ch);
//UART receive function
extern char UART1GetChar();
“uart1.c”
/*
Engscope
UART
April 16, 2008
Author: JL
*/
#include “system.h” //see tutorial below!
#include “uart1.h”
//Initiation function, parameter BAUDRATEREG1 determines baud speed
void UART1Init(int BAUDRATEREG1)
{
//Set up registers
U1BRG = BAUDRATEREG1; //set baud speed
U1MODE = 0×8000; //turn on module
U1STA = 0×8400; //set interrupts
//reset RX interrupt flag
IFS0bits.U1RXIF = 0;
}
//UART transmit function, parameter Ch is the character to send
void UART1PutChar(char Ch)
{
//transmit ONLY if TX buffer is empty
while(U1STAbits.UTXBF == 1);
U1TXREG = Ch;
}
//UART receive function, returns the value received.
char UART1GetChar()
{
char Temp;
//wait for buffer to fill up, wait for interrupt
while(IFS0bits.U1RXIF == 0);
Temp = U1RXREG;
//reset interrupt
IFS0bits.U1RXIF = 0;
//return my received byte
return Temp;
}
Since I have gone through explaining the “uart1.c”, “uart1.h” and “system.h” files already in the first section of the tutorial, I will only go over the “main.c” file. The main file starts with all the regular initiations:
#include “../h/system.h”
#include “timer.h”
#include “pic.h”
//prototype
void RepeaterProcessEvents();
unsigned int state = 0;
unsigned char temp1;
char flag1 = 0;
//Configs, EC clock, No protect, Watchdog Off
_FBS (BWRP_WRPROTECT_OFF & BSS_NO_FLASH);
_FGS (GSS_OFF & GCP_OFF & GWRP_OFF);
_FOSCSEL(FNOSC_PRI & IESO_OFF);
_FOSC (FCKSM_CSDCMD & IOL1WAY_OFF & OSCIOFNC_OFF & POSCMD_EC);
_FWDT (FWDTEN_OFF);
_FPOR (FPWRT_PWR1 & ALTI2C_ON);
int main(void)
{
OSCCON = 0x2200; //Use primary, no divide FCY = 10Mhz/2 = 5Mhz
CLKDIV = 0x0000; //do not divide
//Disable Watch Dog Timer
RCONbits.SWDTEN = 0;
//Set up I/O Port
AD1PCFGL = 0xFFFF; //set to all digital I/O
TRISB = 0xFFFF; //configure all PortB as input
Note that my CLKI input is running at 10 MHz, so the instruction clock is running at 10 MHz/2 = 5 MHz. Now I set up my TX and RX pins.
RPINR18bits.U1RXR = 2; //UART1 receive set to RB2
RPOR1bits.RP3R = 3; //UART1 transmit set to RB3
At Fcy = 5MHz, and a desired baud rate of 19200 bps, I have calculated my BRG to be 15, as discussed in UART part 1. I put a delay after the initiation because certain components of my circuit might not have reset yet. This is just an arbitrary delay.
UART1Init(15); //Initiate UART1 to 19200 at 10MHz OSCI
DelaymSec(1000);
Lastly, I loop forever.
//Main Program Loop, Loop forever
while(1)
{
//process data
RepeaterProcessEvents();
}
return(0);
The function that gets called during the main loop is called “RepeaterProcessEvents()”. This function is very simple:
//Repeater main function
void RepeaterProcessEvents()
{
unsigned char data = 0;
//wait for data to be received
data = UART1GetChar();
//send data back on UART TX line
UART1PutChar(data);
}
I create a temporary variable named “data”, which I store the received character. The function UART1GetChar() will only exit when a data is received. So if you don’t sent anything on the RX line, your program is going to loop in the UART1GetChar(); function. When the function does receive a byte, it then calls the function UART1PutChar(data). This function sends the received data and repeats it on the TX pin.
Done!
Table of Contents
Previous – UART – Part 1 – Setup
Next – I2C – Part 1 – Understanding I2C Basics

Entries (RSS)
I think you have the ports mixed up
RPINR18bits.U1RXR = 2; //UART1 receive set to RB7
RPOR1bits.RP3R = 3; //UART1 transmit set to RB6
I think this code sets the U1RX to pin RP2 which is RB2, and sets the U1TX to pin RP3 which is RB3.
Am I missing something?
You are correct, I made the modifications.
-J
Thank you so much for this info! I have a question how would you store a long string of characters? For instance A GPS array that may have 70 characters in it? I think perhaps create an array, put the received character in the array at the current index value, and then advance the index. I’m just not sure how that would be coded.
This is more of a C question than a PIC question. You’ll need to look up a C tutorial. It has nothing to do with the hardware in the PIC.
-J
I’m new at pic programming. How did you implement the DelaymSec routine ? And in general how can I implement a variable delay routine using timer1 ?
Best regards,
Vittorio Grandi
Hi Vittorio, please read the timers section.
http://www.engscope.com/pic24-tutorial/8-timers/
I apologize for the noob question…I see you haven’t included ‘uart.h’ What sort of difference would including that file make, meaning, what kind of additional functions would I then have access to? Thanks!
This is a C question. As always, the definitive book on C is by its creator, “The C Programming Language”, B. Kernighan and D. Ritchie, 1988. It is the bible that C programmers are required to read. I would highly recommend reading the book as it is rather short and concise.
As for your question, C functions require prototypes, and the uart1.h defines the prototypes. This is required because during compilation the compiler checks for the return types and parameters for function calls. If the prototypes are not present, then the compiler errors out. This is required because the next step cannot occur with incorrect return types and parameters. Linking requires that the datatypes are correct. The “uart1.c” file does not need to include the header because nothing in the code calls functions defined in “uart1.h”. However the main file does call the function inside “uart1.c”, and therefore requires the function prototypes found in “uart1.h”.
-J
Perhaps you misunderstood, I wasn’t talking about including “uart1.h”, I meant including “uart.h” (the UART function library). From what I understand, it has certain built in functions that would assist in reading/writing to the UART lines. Again, sorry if I’m way off on this…Thanks again.
I see what you mean. The library functions are already compiled in the library files. These are the object files after compilation and ready to be linked. In order to access them however, you need to have the function prototypes. Microchip provides the library for some of the modules of their chip. For example, the I2C, the UART and the ADC all have compiled object files read to be used. All you need to do is include the headers to access them. A word of warning however, as I have found bugs in these functions and debugging compiled files are a lot of trial and error. The tutorial just shows you how to write the source code yourself.
-J
Makes sense. Thanks JL!