Project

How to Use MAX232 to Communicate Between a PIC and a PC

August 15, 2015 by Jens Christoffersen

This is one simple way to control a LED, fan, relay or solenoid with a computer and a PIC.

This is one simple way to control a LED, fan, relay or solenoid with a computer and a PIC.

Recommended Level

Intermediate

Requirements

  • A computer with Microchip's MPLAB X IDE, with XC8 v1.34 compiler installed. (I'm using MPLAB X v3.05 and XC8 v1.34)
  • A PIC16F628A microcontroller
  • A MAX232 Driver/Receiver
  • A way to program the MCU
  • Partslist from Eagle (see below)
  • A computer with serial port interface/ a serial to USB cable
  • If you want to put the circuit on a breadboard, you'll need a breadboard and some jumper wires

Introduction

Maxim Integrated Products created the MAX232 IC in 1987. It is a dual driver/receiver and typically converts the RX, TX, CTS and RTS signals from/to the PC's serial port (which can reach up to 25 v) from/to TTL levels (5 v). With a MAX232 IC you can easily connect your PIC microcontroller to your PC. This opens up a lot of opportunities. You can control LEDs, fans, relays and solenoids, to name a few. In this How To, we'll simply turn on and then turn off a LED. This may sound simple bu with this knowledge, you can already build a lot of things! You'll be needing a computer with a serial port or a serial to USB converter. I'm using a USB to RS-232 adapter. Read more about RS-232 on Wikipedia.

For a more indepth reading on USART, USART configuration and initializing, please read Microchip's:  AN774 - Asynchronous Communication with the PICmicro USART. For ASM programmers, this link gives you a few source code examples.

Hardware

The first thing we do is make a block diagram. This is a diagram of our gadget, split into blocks. This is a good aid to keep us on track and it gives us an overlook of what we want our circuit to do.

Block diagram

We'll need:

  • a way to program our MCU, the ICSP block
  • the computer to communicate with the MCU, half duplex, the computer block
  • the MCU to control the LED/Output, the MCU block
  • to see the LED/ output block

The LED/output block can be LEDs, fans, relays or solenoids, or any other thing you want to control. One important matter you need to address is to be sure your MCU has a USART-port. We're using the PIC16F628A, which has one port. IC leg 7 and 8 are PORTBbits.RB1 and PORTBbits.RB2, respectively. If you are using a different MCU, you have to take that into consideration.

You'll need the components datasheet when you draw your circuit. The datasheet for the PIC16F628A can be found here. This will be your guide when you are stuck. The other IC's datasheet is here: MAX232CPE.

The hardware handshake is not considered in this schematic. To satisfy hardware handshake, you have to put some jumpers on X2:

When the block diagram is made, we'll draw the schematic:

Click on image for better resolution.

Block explanation

Block Description
Power This block is based on the LM7805-regulator. This is a linear regulater. With some capacitors, it regulates the volt we need to get a steady 5vDC.
ICSP This is a 1x5 pin header, used to program the PIC16F628A. In this setup, I'm using a PICkit3.
Microcontroller This is our PIC16F628A, the "brain".
Output This is the MAX232 IC. This is connected to the PIC and to the computer. The LED is also under the output block.

Partlist

This is a screenshot of the partlist file. The file is generated by EagleCAD.

After the hardware is made, it's time for the software.

Software

When writing software, you have to have the hardwares datasheet nearby. My setup allows me to have the datasheet on one screen while I have the programming environment on another screen. That way, I can access the datasheet in seconds.

This is based on MPLAB X IDE and the XC8 compiler. All are free for download at www.microchip.com. It is a good habit to comment on your code,while you write it. When you write it, you might think that you'll remember what all the lines do--and you may for the next day or the rest of the week. But what about a month from now? Would you still remember? Use comments. They will save a lot of work later, and others will thank you. The following code is fairly well commented, so there is no need to go through it line by line. So without further ado, here goes:


// INCLUDES
#include 
#include 
#include 
#include 

// CONFIG
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator: High-speed crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON       // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR)
#pragma config BOREN = ON       // Brown-out Detect Enable bit (BOD enabled)
#pragma config LVP = ON         // Low-Voltage Programming Enable bit (RB4/PGM pin has PGM function, low-voltage programming enabled)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

// DEFINITIONS
#define _XTAL_FREQ 16000000      // Tell the compiler that we are useing 16MHz

// GLOBAL VARIABLES
unsigned int choice;            // Variable to hold user choice
bool getchar_active = false;    // Boolean variable

// FUNCTION PROTOTYPE
void interrupt tc_int(void);
void UART_init(void);
unsigned char getch();
unsigned char getche(void);
void showMenu(void);


// FUNCTIONS
void UART_init(void){
    TXSTAbits.BRGH = 0;     // Setting BRGH to use LOW speed
    TXSTAbits.SYNC = 0;     // Setting async mode
    TXSTAbits.TX9 = 0;      // Setting 8-bit transmission
    RCSTAbits.CREN = 1;     // Enable continious receive
    
    SPBRG = 25;             // Setting the SPBRG register to use 16MHz with BRGH 0
    
    PIE1bits.RCIE = 1;      // USART receive interrupt enable
    RCSTAbits.SPEN = 1;     // Enable serial port
    TXSTAbits.TXEN = 1;     // Enable transmit
    
    return;
}

unsigned char getch()
{
    getchar_active = true;  // Boolean variable set to true
    while(getchar_active)   // While true
        continue;           // Carry - on
    return RCREG;           // return the value in RCREG
}

unsigned char getche(void){ 
    unsigned char c;
    putch(c = getch());
    return c;
}

void putch(unsigned char byte){     // Adding Carrier Return and Line feed
    while(!TXSTAbits.TRMT);
    TXREG = byte;
    if ('\n'==byte){
        while (!TXSTAbits.TRMT);
       TXREG = '\r';
    }
    return;
}

void interrupt tc_int(void){
    if(RCIE && RCIF)                // Check RC Inter bit & Inter Flag
    {
        getchar_active = false;
        RCREG;
    }
    return;
}

void showMenu(){
        printf("\n\n*****************************************************\n");
        printf("**        PIC, MAX232 and PC communication demo    **\n");
        printf("*****************************************************\n");
        printf("\n\t1. LED on.\n");
        printf("\t2. LED off.\n"); 
        printf("Your choice: ");
}
/*
 * THIS IS THE MAIN PROGRAM
 */
int main(int argc, char** argv) {
TRISA = 0b00000000;     // All output
PORTB = 0b00000000;     // All low

TRISB = 0b00000110;     // RB1 & RB2 set as input ref datasheet
PORTB = 0b00000000;     // All low

    UART_init();        // Initialize the UART
    
    INTCONbits.PEIE = 1;    // Enable peripheral interrupt
    INTCONbits.GIE = 1;     // Enable global interrupt
    
    do {
        showMenu();         // Show awesome menu

        choice = getchar(); // Assign char from getchar to choice

        switch(choice){     // Menu options
            case '1': printf("\n\n\t\t** Led is ON **\n");
                    PORTBbits.RB3 = 1;
                    break;
            case '2': printf("\n\n\t\t** Led is OFF **\n");
                    PORTBbits.RB3 = 0;
                    break;
            default:    printf("\n\n\t\t** Invalid choice. RTFM :-D **\n\n");
            break;
        }
    } while (choice !=3);
   
    return (EXIT_SUCCESS);
}


 

main_max232.c.zip

If the source code compiles with no errors or warnings, you can program the MCU, and hook it up to your computer. Open your favourite serial communication program and use 9600-8-N-1 for the port settings. Apply power to the circuit, and you should see a small menu on the screen. It works on both Windows and Linux. See the short video at the end.

Conclusion

We used a PIC16F628A and a MAX232 to control a LED with a PC. We didn't use a lot of hardware, and we didn't have a lot of code. We didn't bother to make our own libraries to write to the UART-port, either: we used the standard printf-function. Our code used 9% of the PIC's data memory and 21% of the program memory. You can download the source code from the bottom of this page.

Pictures and video

The compete circuit

The microcontroller part.

The MAX232 part.

Give this project a try for yourself! Get the BOM.

8 Comments
  • I
    isabelahtam October 22, 2015

    Thanks! ^-^

    Like. Reply
  • S
    sheina January 13, 2016

    Sweet…. Thanks for the post. This is what i have been looking for. I have a lot of max232 but i only have pic16f877a what do i need to edit on the code. Thanks
    You can also email me .(JavaScript must be enabled to view this email address)

    I badly needed someone to help me with my project :(

    Like. Reply
    • J
      Jens Christoffersen January 16, 2016
      Hi, why don't you go through the code and the datasheet, and then compare the two datasheets? Then you'll find what you need to change. Or post a question on the forum...
      Like. Reply