Tuesday, March 31, 2020

UART communication using pic microcontroller

Here we have used PIC16F877A MCU, it has a module called “Addressable Universal Synchronous Asynchronous Receiver and Transmitter” shortly known as USART.  USART is a two wire communication system in which the data flow serially. USART is also a full-duplex communication, means you can send and receive data at the same time which can be used to communicate with peripheral devices, such as CRT terminals and personal computers.

The USART can be configured in the following modes:
  • Asynchronous (full-duplex)
  • Synchronous – Master (half-duplex)
  • Synchronous – Slave (half-duplex)
There are also two different modes namely the 8-bit and 9-bit mode, in this tutorial we will configure the USART module to work in Asynchronous mode with 8-bit communication system, since it is the most used type of communication. As it is asynchronous it doesn't need to send clock signal along with the data signals. UART uses two data lines for sending (Tx) and receiving (Rx) data. The ground of both devices should also be made common. This type of communication does not share a common clock hence a common ground is very important for the system to work.
UART-Communication-using-PIC-Microcontroller-PIC16F877A
At the end of this tutorial you will be able establish a communication (UART) between your computer and your PIC Microcontroller and toggle an LED on the PIC board from your laptop. The status of the LED will be sent to your laptop from the PIC MCU. We will test the output using Hyper Terminal in computer. Detailed Video is also given at the end of this tutorial.

Requirements:

Hardware:
  • PIC16F877A Perf Board
  • RS232 to USB converter Module
  • Computer
  • PICkit 3 Programmer
Software:
  • MPLABX
  • HyperTerminal

RS232 to USB converter is required to convert the serial data into computer readable form. There are ways to design your own circuit instead of buying your own module but they are not reliable as they are subjected noise. The one which we are using is shown below
RS232-to-USB-converter-Module
Note: Each RS232 to USB converter would require a special driver to be installed; most of them should get installed automatically as soon as you plug in the device. But, if it doesn’t relax!!! Use the comment section and I will help you out.

Programming PIC Microcontroller for UART Communication:

Like all modules (ADC, Timer, PWM) we should also initialize our USART module of our PIC16F877A MCU and instruct it to work in UART 8-bit communication mode.  Let’s define the configuration bits and start with the UART initialization function.

Initializing the UART module of the PIC Microcontroller:
The Tx and Rx pins are physically present at the pins RC6 and RC7. According to datasheet let’s declare TX as output and RX as input.
    //****Setting I/O pins for UART****//
    TRISC6 = 0; // TX Pin set as output
    TRISC7 = 1; // RX Pin set as input
    //________I/O pins set __________//

Now the baud rate has to be set. The baud rate is the rate at which information is transferred in a communication channel. This can be one of the many default values, but in this program we are using 9600 since its the most used baud rate.
    /**Initialize SPBRG register for required 
    baud rate and set BRGH for fast baud_rate**/
    SPBRG = ((_XTAL_FREQ/16)/Baud_rate) - 1;
    BRGH  = 1;  // for high baud_rate
    //_________End of baud_rate setting_________//

The value of the baud rate has to be set using the register SPBRG, the value depends on the value of the External crystal frequency, the formulae to calculate the baud rate is shown below:
SPBRG = ( ( _XTAL_FREQ/16 ) / Baud_rate) – 1;
The bit BRGH has to be made high to enable high speed bit rate. According to datasheet (page 13) it is always advantageous to enable it, as it can eliminate errors during communication.

As said earlier we will be working in Asynchronous mode, hence the bit SYNC should be made zero and bit SPEM must be made high to enable serial pins (TRISC6 and TRICSC5)
    //****Enable Asynchronous serial port*******//
    SYNC  = 0;    // Asynchronous
    SPEN  = 1;    // Enable serial port pins
    //_____Asynchronous serial port enabled_______//

In this tutorial we will be both sending and receiving data between MCU and computer hence we have to enable both TXEN and CREN bits.
    //**Lets prepare for transmission & reception**//
    TXEN  = 1;    // enable transmission
    CREN  = 1;    // enable reception
    //__UART module up and ready for transmission and reception__//

The bits TX9 and RX9 have to be made zero so that we operate in 8-bit mode. If there has to be high reliability need to be established then 9-bit mode can be selected.
    //**Select 8-bit mode**//  
    TX9   = 0;    // 8-bit reception selected
    RX9   = 0;    // 8-bit reception mode selected
    //__8-bit mode selected__//   

With this we complete our initialization setup. Now the Module is configured as UART and is ready for operation.

Transmitting data using UART:
The below function can be used to transmit data through the UART module:
//**Function to send one byte of date to UART**//
void UART_send_char(char bt)  
{
    while(!TXIF);  // hold the program till TX buffer is free
    TXREG = bt; //Load the transmitter buffer with the received value
}
//_____________End of function________________//
Once the module is initialized whatever value is loaded into the register TXREG will be transmitted through UART, but transmission might overlap. Hence we should always check for the Transmission Interrupt flag TXIF. Only if this bit is low we can proceed with the next bit for transmission else we should wait for this flag to get low.

However, above function can be used only to send only one byte of data, to send a complete a string the below function should be used
//**Function to convert string to byte**//
void UART_send_string(char* st_pt)
{
    while(*st_pt) //if there is a char
        UART_send_char(*st_pt++); //process it as a byte data
}
//___________End of function______________//
This function might be a bit tricky to understand since it has pointers, but trust me pointers are wonderful and they make programming more easy and this is one good example of the same.
As you can notice we have again called the UART_send_char() but now inside the while loop. We have split the string into individual characters, each time this function is called, one char will be sent to the TXREG and it will get transmitted.

Receiving data using UART:
The following function can be used to receive data from the UART module:
//**Function to get one byte of date from UART**//
char UART_get_char()   
{
    if(OERR) // check for Error 
    {
        CREN = 0; //If error -> Reset 
        CREN = 1; //If error -> Reset 
    }
    
    while(!RCIF);  // hold the program till RX buffer is free
    
    return RCREG; //receive the value and send it to main function
}
//_____________End of function________________//

When a data is received by the UART module it picks it up and stores it up in the RCREG register. We can simply transfer the value to any variable and use it. But there might be overlap error or the user might be sending data continuously and we have not yet transferred them to a variable.
In that case the Receive flag bit RCIF comes to rescue. This bit will go low whenever a data is received and is not yet processed. Hence we use it in the while loop creating a delay to hold the program till we deal with that value.

Toggling LED using the UART module of PIC Microcontroller:
Now let us come to the final part of the Program, the void main(void) function, where we will be toggling a LED through the computer using the UART communication between PIC and computer.
When we send a character “1” (from computer) the LED will be turned ON and the status message “RED LED -> ON” will be sent back (from PIC MCU) to the computer.
Similarly we send a character “0” (from computer) the LED will be turned OFF and the status message “RED LED -> OFF” will be sent back (from PIC MCU) to the computer.
while(1) //Infinite loop
    {
      get_value = UART_get_char(); 
        
        if (get_value == '1') //If the user sends "1"
        {
            RB3=1; //Turn on LED
            UART_send_string("RED LED -> ON"); //Send notification to the computer 
            UART_send_char(10);//ASCII value 10 is used for carriage return (to print in new line)
        }
        
        if (get_value == '0') //If the user sends "0"
        {
           RB3=0; //Turn off LED
           UART_send_string("RED -> OFF"); //Send notification to the computer      
           UART_send_char(10);//ASCII value 10 is used for carriage return (to print in new line)
        }
    }

Simulating our program:

As usual let’s simulate our program using proteus and find out if it works as expected.
UART-Communication-using-PIC-Microcontroller-simulation
The above image shows a virtual terminal in which one it shows a welcome message and status of the LED. The Red Color LED can be noticed to be connected to the pin RB3. The detailed working of the simulation can be found in the Video at the end.

Hardware Setup and Testing the output:

The connection for this circuit is really simple, we use our PIC Perf board and just connect the three wires to RS232 to USB converter and connect the module to our computer using USB data cable as shown below.
Toggling-LED-through-computer-using-PIC-UART
UART-Communication-between-PIC-Microcontroller-and-computer

Next we install the Hyper Terminal Application (download it) and open it up. It should show something like this
Hyper-terminal-in-computer

Now open Device Manager on your computer and check which Com port your module is connected to, mine is connected to COM port 17 as shown below
finding-com-port-number-for-Hyper-terminal
Note: The COM port name for your module might change according to your vendor, it is not a problem.

Now go back to Hyper Terminal Application and navigate to Set Up -> Port Configuration or press Alt+C, to get the following pop up box and select the desired port (COM17 in my case) in the pop-up window and click on connect.
Hyper-terminal-with-COM-port

Once the connection is established turn on your PIC perf board and you should see something like this below
Hyper-terminal-UART-intialized
Keep your cursor in the Command Window and enter 1 then press enter. The LED will be turned on and the status will be displayed as shown below.
Hyper-terminal-LED-ON-using-computer-and-PIC-UART
Same way , keep your cursor in the Command Window and enter 0 then press enter. The LED will be turned off and the status will be displayed as shown below.
Hyper-terminal-LED-OFF-using-computer-and-PIC-UART

Below are given the complete code and detailed video, which will show how the LED responds in real time for “1” and “0”.

That’s it guys, we have interfaced PIC UART with our computer and transferred the data to toggle the LED using Hyper terminal. Hope you understood, if not, use the comment section to ask your query. In our next tutorial we will again use UART but make it more interesting by using a Bluetooth module and broadcast the data over air.
 
Code: 
// CONFIG
#pragma config FOSC = HS       // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF       // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)
// End of configuration
#include <xc.h>
#define _XTAL_FREQ 20000000
#define Baud_rate 9600
//***Initializing UART module for PIC16F877A***//
void Initialize_UART(void)
{
    //****Setting I/O pins for UART****//
    TRISC6 = 0; // TX Pin set as output
    TRISC7 = 1; // RX Pin set as input
    //________I/O pins set __________//
    
    /**Initialize SPBRG register for required 
    baud rate and set BRGH for fast baud_rate**/
    SPBRG = ((_XTAL_FREQ/16)/Baud_rate) - 1;
    BRGH  = 1;  // for high baud_rate
    //_________End of baud_rate setting_________//
    
    //****Enable Asynchronous serial port*******//
    SYNC  = 0;    // Asynchronous
    SPEN  = 1;    // Enable serial port pins
    //_____Asynchronous serial port enabled_______//
    //**Lets prepare for transmission & reception**//
    TXEN  = 1;    // enable transmission
    CREN  = 1;    // enable reception
    //__UART module up and ready for transmission and reception__//
    
    //**Select 8-bit mode**//  
    TX9   = 0;    // 8-bit reception selected
    RX9   = 0;    // 8-bit reception mode selected
    //__8-bit mode selected__//     
}
//________UART module Initialized__________//

//**Function to send one byte of date to UART**//
void UART_send_char(char bt)  
{
    while(!TXIF);  // hold the program till TX buffer is free
    TXREG = bt; //Load the transmitter buffer with the received value
}
//_____________End of function________________//

//**Function to get one byte of date from UART**//
char UART_get_char()   
{
    if(OERR) // check for Error 
    {
        CREN = 0; //If error -> Reset 
        CREN = 1; //If error -> Reset 
    }
    
    while(!RCIF);  // hold the program till RX buffer is free
    
    return RCREG; //receive the value and send it to main function
}
//_____________End of function________________//

//**Function to convert string to byte**//
void UART_send_string(char* st_pt)
{
    while(*st_pt) //if there is a char
        UART_send_char(*st_pt++); //process it as a byte data
}
//___________End of function______________//
    
// **********START of Main Function**************//
void main(void)
{
    int get_value;
    
    TRISB = 0x00; //Initialize PortB as output
    Initialize_UART();    //Initialize UART module                    
    
    UART_send_string("UART Module Initialized and active");    // Introductory Text
    
    while(1) //Infinite loop
    {
      get_value = UART_get_char(); 
        
        if (get_value == '1') //If the user sends "1"
        {
            RB3=1; //Turn on LED
            UART_send_string("RED LED -> ON"); //Send notification to the computer 
            UART_send_char(10);//ASCII value 10 is used for carriage return (to print in new line)
        }
        
        if (get_value == '0') //If the user sends "0"
        {
           RB3=0; //Turn off LED
           UART_send_string("RED -> OFF"); //Send notification to the computer      
           UART_send_char(10);//ASCII value 10 is used for carriage return (to print in new line)
        }
       
    }
}
// **********END of Main Function**************//

No comments:

Post a Comment