Applied Robotics/Microcontrollers/Serial Communication

Serial Communication Basics

edit

Serial communication is a means of sending data between devices one bit at a time. This method only requires a few wires and I/O pins per device to facilitate communication. Typically, most serial devices send and receive byte-oriented data (8-bits per transaction), and have a dedicated transmit and receive line (full-duplex). Serial communication is typically handled by specialized hardware peripherals known as USARTs (Universal Synchronous-Asynchronous Receiver-Transmitters) that handle low level formatting, shifting, and recovery of data.

Most ATmega series AVR microcontrollers have 1-2 USARTs available. Some modern microcontrollers have 5-7 separate USARTs.

Serial Frame Structure

edit

Serial transactions are broken up into what are called frames. Each frame consists of the payload data byte being sent along with a set number of bits that "frame" or format the data. Most USARTs, including the AVR USARTs, are compatible with a frame structure such as this one.

 
An example generic UART serial communication frame.

The serial line idles at a logic high level until the transmission starts. Each transmission is started with a single logic-low bit known as a start bit. After the start bit, the payload data is shifted out, typically with the least-significant bit first. After the last data bit is shifted out, an optional parity bit is sent. The parity bit takes on a value of 0 or 1 depending on the number of logic 1 bits in the data and can be used by the receiver to detect an erroneous transmissions in which one of the bits are flipped. Finally, the serial line returns to logic high for a configurable period of 1 or 2 bit-times; these are known as stop bits. AVR USARTs are capable of sending frames with 5-9 data bits, with even, odd, or no parity, and 1 or 2 stop bits. In the frame above, a logic-high signal corresponds to a '0' while a logic-low signal corresponds to a '1'.

Synchronous vs. Asynchronous Serial

edit

Serial communication with a USART can be done both synchronously (data with a dedicated clock signal) or asynchronously (data without a dedicated clock signal). Using a synchronous serial line requires that extra wiring is included for the clock signals, and is often times unnecessary at typical serial data rates. Typically, most standard serial communication, especially between a PC and a microcontroller, is done asynchronously.

Baud Rate

edit

The baud rate specifies the frequency at which bits are sent. The baud rate can be calculated by dividing 1 over the bit time in seconds. Setting the baud rate correctly for asynchronous serial is very important as the receiver must recover a clock signal from the incoming data based on a predetermined clock frequency. Common baud rates available on a PC are 1.2k, 2.4k, 4.8k, 9.6k, 19.2k, 38.4k, 57.6k, 115.2k, 230.4k, 460.8k, and 921.6k.

Logic Levels

edit

There are many different standard serial logic levels used. Most PC interfaces use RS-232 serial, that specifies logic levels between -15V and -3V and +3 to +15V with idle-low lines. AVR USARTs use CMOS logic levels between 0-5V and have idle-high serial lines that are typically compatible with standard 3.3V or 5V logic outputs. The appropriate serial logic levels must be used between devices, and for that purpose, special level shifters may be required.

Texas Instruments manufactures RS-232 to CMOS/TTL level shifters for RS-232 use. These devices have a built in charge pump for providing the RS-232 levels and require only a few external components. An example of these chips is the MAX232 http://www.ti.com/product/max232.

Setting up a USART on an ATmega Microcontroller

edit

The following example shows how to set up a serial port on an ATmega128 using USART0 as an asynchronous serial device operating at 115200 baud. The ATmega128 is using a 16 MHz clock in this example. The program should initialize USART0, and send out the byte 0xAA on its transmitter. It will continue to check its receiver for new data and will set PB0 high if it receives the 0xAA byte. This allows for a quick loopback test and demonstrates basic USART concepts.

/**************************************************
 *
 * AVR Microcontroller USART0 Example 
 * Cody Hyman <hymanc@onid.orst.edu>
 *
 **************************************************/
#include <avr/io.h>

/* Initialize USART0 */
void init_usart()
{
    UBRR0H = 0; // Initialize the baud rate registers for 115.2kbps
    UBRR0L = 8; 
    UCSR0C = (1<<UCSZ00)|(1<<UCSZ01);// Set the USART data size to 8b
    UCSR0B = (1<<RXEN0)|(1<<TXEN0);  // Enable the receiver and transmitter
    DDRE |= (1<<1);                  // Set the Tx line (PE0) to be an output.
}
/* Blocking single byte transmit on USART0 */
void transmit_usart0(uint8_t byte)
{
    // Check for previous transmission to complete and 
    while(!(UCSR0A & (1<<TXC0))); // Wait until last transmit is complete
    UDR0 = byte;                  // Start next transmission by writing to UDR0
}
/* Checks the USART0 Rx complete status flag */
uint8_t usart_has_rx_data(void)
{
    return (UCSR0A & (1<<RXC0)) != 0; // Return the RX complete status flag
}
/* Reads data from the USART receive buffer */
uint8_t receive_usart0(void)
{
    uint8_t ret_val = UDR0; // Read data register
    return ret_val;   // Return read value
}
int main(void)
{
    init_usart();              // Run USART initialization routine
    DDRB |= (1<<0);            // Initialize ATmega128 board LED 0
    uint8_t received_data = 0; // Receive data buffer
    transmit_usart0(0xAA);     // Transmit 0xAA
    while(1)    // Main loop
    {    
        if(usart_has_rx_data())               // Check for received data
        {
            received_data = receive_usart0(); // If yes, get the data
            if(received_data = 0xAA)          // Check the data
                PORTB |= (1<<0);              // If it matches, turn on LED
            else
                PORTB &= ~(1<<0);             // Else turn off LED
        }
    }
    return 0;
}

USB - Serial Bridges

edit

Typically most modern PCs do not have a dedicated RS-232 serial port available, so an alternative must be used. Many vendors sell both RS-232 and TTL or LVTTL level adapters for a low cost. Many of these devices typically require drivers, so follow all manufacturer setup instructions.

Plugable USB to RS-232 Adapter

FTDI UMFT230XB USB to 3.3V Serial Adapter

FTDI TTL-232R-5V-PCB USB to 5V (or 3.3V) Serial Adapter

On Windows machines

edit

Serial adapters typically enumerate as a COMx port. Check your device manager to determine the COM port number.

On Linux machines

edit

Serial adapters typically enumerate as ttyUSBx devices. Check your /dev/ directory for ttyUSB devices to determine the tty device number.

RS-232 Pinouts

edit

The following pinouts are commonly found standard RS-232 DE-9 connectors. The male DTE pinout corresponds to the pins on the PC or serial adapter side. The female DCE pinout corresponds to the end device, such as a microcontroller board with an RS-232 port. RS-232 also specifies a number of other flow control lines that were commonly used in old serial modems, however for most cases, just the TxD/RxD and ground lines are needed.  

Common Errors

edit

Common errors include improperly wiring the DCE side connector Tx/Rx pins or accidentally using an RS-232 crossover cable rather than a straight cable. It's strongly advised to check these factors if your RS-232 communication does not work.

Serial Terminal Software

edit

A variety of serial terminal programs exist that allow for quick sending and receiving of serial data. These are useful for debugging and testingrial devices.

Windows Serial Programs

edit

Realterm - A very capable GUI based serial terminal. - http://realterm.sourceforge.net/ Linux Serial Programs: Minicom: A very popular terminal based serial interface program - Debian package name "minicom" Cutecom: A GUI based serial terminal program - Debian package name "cutecom"

Python Serial Module (PySerial)

edit

An easy cross platform library for PC serial communication is PySerial. Python version 2.7 is recommended over Python 3.x. Pyserial allows for easy serial port management and manages sending and receiving data over a COM or tty port in Windows or Linux respectively. Pyserial and the accompanying documentation can be found at - http://pyserial.sourceforge.net/