Serial Communications Example

Serial Connection from PC to PIC16F690

The software implements a command interpreter. To use this you must have a USB-to-TTL converter like the FTDI 232 3.3v or a USB cable with the FTDI chip built in. You will also need to install a terminal emulator on your PC. See references.

With this code as a starting point, you can implement multiple actions or tasks on the μC and control them from a PC. As the code executes it can report back to you.

Below is the schematic.

serialComm-sch

Source Code (serialComm.c)

A serial link lets you interact with your μC code via text messages. You send single letter commands to it and it sends responses to the terminal (via printf()). But, for high speed repetitive behavior, sending characters via a serial link can place a huge burden on the processor, thereby distorting the timing of your code. On the other hand, an LED can be turned on or off in a couple of microseconds.

The serial communication link is good for starting a test and reporting the results. An LED can be used inside an interrupt routine to alert you to its entry or exit. If you have access to an oscilloscope, you can use the LED (or its GPIO pin) to see the execution time of an interesting system behavior.

As it stands, this code does nothing with the LEDs.

Show text file suitable for cut-and-paste.

/*
 * File:   serialComm.c
 * Author: Brian
 *
 * Created on September 19, 2014, 11:25 AM
 *
 * DESCRIPTION: Connect to a PC over a USB/serial cable. Accepts single
 * character commands from the PC and returns responses. Requires use of
 * a USB-to-TTL cable or adapter.
 *
 * On the PIC, this implements a simple, single-character command interpreter
 * with formatted output. It is an example which illustrates all necessary
 * initialization.
 *
 * On the PC, run a terminal emulator (e.g. HyperTerm or Putty).
 * Setup is:
 *      9600 Baud, 1 stop bit, no parity, no handshaking
 * Both the terminal software and the 16F690 EUSART must agree on setup!
 *
 * Device: 16F690
 * All references herein are to Microchip DS41262E which is the current
 * data sheet for PIC16F631/677/685/687/689/690
 */
#include <xc.h>
#include <stdio.h>  /* for printf() */
#include <ctype.h>  /* for toupper() */

#pragma config FOSC=INTRCIO
#pragma config WDTE=OFF
#pragma config PWRTE=OFF
#pragma config MCLRE=OFF
#pragma config CP=OFF
#pragma config BOREN=OFF
#pragma config IESO=OFF
#pragma config FCMEN=OFF

/* globals controlled by remote commands */
int n = 0;
bit enableDebug = 0;
bit increment = 0;
bit decrement = 0;
void initUSART(void) {
    /*
     * set up for 9600 baud, asynchronous
     * see Table 12-5, pp.165-168
     *      section 4: SYNC=0 BRGH=1 BRG16=0
     *      Fosc=4 MHz: SPRG=25
     * use RB5 for Rx and RB7 for Tx
     */
    TXSTAbits.TXEN = 1;     // enable transmitter
    TXSTAbits.BRGH = 1;     // set up baud rate according to Table 12-5, 4th section
    BAUDCTLbits.BRG16 = 0;  // use the 8-bit counter
    SPBRG = 25;             // baud rate generator

    TXSTAbits.SYNC = 0;     // asynchronous mode
    RCSTAbits.CREN = 1;     // continuous receive

    ANSELHbits.ANS11 = 0;   // disable AN11 input (on pin RB5)
    TRISBbits.TRISB5 = 1;   // RX (RB5) is an input
    TRISBbits.TRISB7 = 1;   /* TX (RB7) is an input
                              * automatically configured as output by TXEN
                              */
    PIE1bits.RCIE = 0;      // no Rx interrupts
    RCSTAbits.SPEN = 1;     // automatically configures RX (RB5) as an input
}

void putch(char data) {
    /*
     * this is used by printf()
     */
    while (!PIR1bits.TXIF) {
        ;
        /* wait until TXIF indicates TXREG is available */
        /* alternatively, TXSTAbits.TRMT is set once a pending character has
         * been pumped out on the line.
         */
    }
    TXREG = data;
}
void dump(void) {
    /*
     * dump command
     */
    printf("N = %d\n\r", n);
}

void help(void) {
    printf("HELP\n\r");
    printf("  0..9 = set N\n\r");
    printf("  A+   = N=N+1\n\r");
    printf("  D    = dump N\n\r");
    printf("  H    = help (this is it)\n\r");
    printf("  S-   = N=N-1\n\r");
    printf("  Z    = toggle debug output\n\r");
}

void cmdInterpreter(void) {
    /* when a character is present in the receive register, RCREG,
     * this function interprets the character and:
     *      1) sets appropriate flags, and/or
     *      2) performs an immediate task
     */
    static unsigned char t;
    /*
     * service serial port input
     */
    if (PIR1bits.RCIF) {
        t = RCREG;
        /*
         * parse a command character
         */
        t = toupper(t);
        switch (t) {
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                n = t - '0';
                if (enableDebug) {
                    printf("DEBUG set N=%d\n\r", n);
                }
                break;
            case 'A':
            case '+':
                printf("increment N\n\r");
                increment = 1;
                break;
            case 'S':
            case '-':
                printf("decrement N\n\r");
                decrement = 1;
                break;
            case 'H':
                help();
                break;
            case 'D':
                dump();
                break;
            case 'Z':
                enableDebug = !enableDebug;
                if (enableDebug) {
                    printf("DEBUG ON\n\r");
                } else {
                    printf("DEBUG OFF\n\r");
                }
                break;
            default:
                printf("%c unrecognized\n\r", t);
                help();
                break;
        }
    }
}
void main(void) {
    OSCCONbits.IRCF = 0b110; /* 4 MHz (default) */
    initUSART();
    printf("Init complete!\n\r");

    while (1) {
        /*
         * service serial port input
         */
        cmdInterpreter();

        /*
         * perform tasks
         */
        if (increment) {
            increment = 0;
            n += 1;
            printf("N=%d\n\r",n);
        }
        if (decrement) {
            decrement = 0;
            n -= 1;
            printf("N=%d\n\r",n);
        }
    }
    return;
}

Leave a Reply

Your email address will not be published. Required fields are marked *

Tools, techniques, design approaches and fun!