Chapter 1, Basics of Serial Communications - JohnHau/mis GitHub Wiki

The Serial Programming Guide for POSIX Operating Systems will teach you how to successfully, efficiently, and portably program the serial ports on your UNIX® workstation or PC. Each chapter provides programming examples that use the POSIX (Portable Standard for UNIX) terminal control functions and should work with very few modifications under IRIX®, HP-UX, SunOS®, Solaris®, Digital UNIX®, Linux®, and most other UNIX operating systems. The biggest difference between operating systems that you will find is the filenames used for serial port device and lock files.

This chapter introduces serial communications, RS-232 and other standards that are used on most computers as well as how to access a serial port from a C program.

What Are Serial Communications? Computers transfer information (data) one or more bits at a time. Serial refers to the transfer of data one bit at a time. Serial communications include most network devices, keyboards, mice, MODEMs, and terminals.

When doing serial communications each word (i.e. byte or character) of data you send or receive is sent one bit at a time. Each bit is either on or off. The terms you'll hear sometimes are mark for the on state and space for the off state.

The speed of the serial data is most often expressed as bits-per-second ("bps") or baudot rate ("baud"). This just represents the number of ones and zeroes that can be sent in one second. Back at the dawn of the computer age, 300 baud was considered fast, but today computers can handle RS-232 speeds as high as 430,800 baud! When the baud rate exceeds 1,000, you'll usually see the rate shown in kilo baud, or kbps (e.g. 9.6k, 19.2k, etc). For rates above 1,000,000 that rate is shown in megabaud, or Mbps (e.g. 1.5Mbps).

When referring to serial devices or ports, they are either labeled as Data Communications Equipment ("DCE") or Data Terminal Equipment ("DTE"). The difference between these is simple - every signal pair, like transmit and receive, is swapped. When connecting two DTE or two DCE interfaces together, a serial null-MODEM cable or adapter is used that swaps the signal pairs.

What Is RS-232? RS-232 is a standard electrical interface for serial communications defined by the Electronic Industries Association ("EIA"). RS-232 actually comes in 3 different flavors (A, B, and C) with each one defining a different voltage range for the on and off levels. The most commonly used variety is RS-232C, which defines a mark (on) bit as a voltage between -3V and -12V and a space (off) bit as a voltage between +3V and +12V. The RS-232C specification says these signals can go about 25 feet (8m) before they become unusable. You can usually send signals a bit farther than this as long as the baud is low enough.

Besides wires for incoming and outgoing data, there are others that provide timing, status, and handshaking:

image

Two standards for serial interfaces you may also see are RS-422 and RS-574. RS-422 uses lower voltages and differential signals to allow cable lengths up to about 1000ft (300m). RS-574 defines the 9-pin PC serial connector and voltages.

Signal Definitions The RS-232 standard defines some 18 different signals for serial communications. Of these, only six are generally available in the UNIX environment.

GND - Logic Ground Technically the logic ground is not a signal, but without it none of the other signals will operate. Basically, the logic ground acts as a reference voltage so that the electronics know which voltages are positive or negative.

TXD - Transmitted Data The TXD signal carries data transmitted from your workstation to the computer or device on the other end (like a MODEM). A mark voltage is interpreted as a value of 1, while a space voltage is interpreted as a value of 0.

RXD - Received Data The RXD signal carries data transmitted from the computer or device on the other end to your workstation. Like TXD, mark and space voltages are interpreted as 1 and 0, respectively.

DCD - Data Carrier Detect The DCD signal is received from the computer or device on the other end of your serial cable. A space voltage on this signal line indicates that the computer or device is currently connected or on line. DCD is not always used or available.

DTR - Data Terminal Ready The DTR signal is generated by your workstation and tells the computer or device on the other end that you are ready (a space voltage) or not-ready (a mark voltage). DTR is usually enabled automatically whenever you open the serial interface on the workstation.

CTS - Clear To Send The CTS signal is received from the other end of the serial cable. A space voltage indicates that is alright to send more serial data from your workstation.

CTS is usually used to regulate the flow of serial data from your workstation to the other end.

RTS - Request To Send The RTS signal is set to the space voltage by your workstation to indicate that more data is ready to be sent.

Like CTS, RTS helps to regulate the flow of data between your workstation and the computer or device on the other end of the serial cable. Most workstations leave this signal set to the space voltage all the time.

Asynchronous Communications For the computer to understand the serial data coming into it, it needs some way to determine where one character ends and the next begins. This guide deals exclusively with asynchronous serial data.

In asynchronous mode the serial data line stays in the mark (1) state until a character is transmitted. A start bit preceeds each character and is followed immediately by each bit in the character, an optional parity bit, and one or more stop bits. The start bit is always a space (0) and tells the computer that new serial data is available. Data can be sent or received at any time, thus the name asynchronous.

image

The optional parity bit is a simple sum of the data bits indicating whether or not the data contains an even or odd number of 1 bits. With even parity, the parity bit is 0 if there is an even number of 1's in the character. With odd parity, the parity bit is 0 if there is an odd number of 1's in the data. You may also hear the terms space parity, mark parity, and no parity. Space parity means that the parity bit is always 0, while mark parity means the bit is always 1. No parity means that no parity bit is present or transmitted.

The remaining bits are called stop bits. There can be 1, 1.5, or 2 stop bits between characters and they always have a value of 1. Stop bits traditionally were used to give the computer time to process the previous character, but now only serve to synchronize the receiving computer to the incoming characters.

Asynchronous data formats are usually expressed as "8N1", "7E1", and so forth. These stand for "8 data bits, no parity, 1 stop bit" and "7 data bits, even parity, 1 stop bit" respectively.

What Are Full Duplex and Half Duplex? Full duplex means that the computer can send and receive data simultaneously - there are two separate data channels (one coming in, one going out).

Half duplex means that the computer cannot send or receive data at the same time. Usually this means there is only a single data channel to talk over. This does not mean that any of the RS-232 signals are not used. Rather, it usually means that the communications link uses some standard other than RS-232 that does not support full duplex operation.

Flow Control It is often necessary to regulate the flow of data when transferring data between two serial interfaces. This can be due to limitations in an intermediate serial communications link, one of the serial interfaces, or some storage media. Two methods are commonly used for asynchronous data.

The first method is often called "software" flow control and uses special characters to start (XON or DC1, 021 octal) or stop (XOFF or DC3, 023 octal) the flow of data. These characters are defined in the American Standard Code for Information Interchange ("ASCII"). While these codes are useful when transferring textual information, they cannot be used when transferring other types of information without special programming.

The second method is called "hardware" flow control and uses the RS-232 CTS and RTS signals instead of special characters. The receiver sets CTS to the space voltage when it is ready to receive more data and to the mark voltage when it is not ready. Likewise, the sender sets RTS to the space voltage when it is ready to send more data. Because hardware flow control uses a separate set of signals, it is much faster than software flow control which needs to send or receive multiple bits of information to do the same thing. CTS/RTS flow control is not supported by all hardware or operating systems.

What Is a Break? Normally a receive or transmit data signal stays at the mark voltage until a new character is transferred. If the signal is dropped to the space voltage for a long period of time, usually 1/4 to 1/2 second, then a break condition is said to exist.

A break is sometimes used to reset a communications line or change the operating mode of communications hardware like a MODEM. Chapter 3, Talking to MODEMs covers these applications in more depth.

Synchronous Communications Unlike asynchronous data, synchronous data appears as a constant stream of bits. To read the data on the line, the computer must provide or receive a common bit clock so that both the sender and receiver are synchronized.

Even with this synchronization, the computer must mark the beginning of the data somehow. The most common way of doing this is to use a data packet protocol like Serial Data Link Control ("SDLC") or High-Speed Data Link Control ("HDLC").

Each protocol defines certain bit sequences to represent the beginning and end of a data packet. Each also defines a bit sequence that is used when there is no data. These bit sequences allow the computer see the beginning of a data packet.

Because synchronous protocols do not use per-character synchronization bits they typically provide at least a 25% improvement in performance over asynchronous communications and are suitable for remote networking and configurations with more than two serial interfaces.

Despite the speed advantages of synchronous communications, most RS-232 hardware does not support it due to the extra hardware and software required.

Accessing Serial Ports Like all devices, UNIX provides access to serial ports via device files. To access a serial port you simply open the corresponding device file.

Serial Port Files Each serial port on a UNIX system has one or more device files (files in the /dev directory) associated with it: image

Opening a Serial Port Since a serial port is a file, the open(2) function is used to access it. The one hitch with UNIX is that device files are usually not accessable by normal users. Workarounds include changing the access permissions to the file(s) in question, running your program as the super-user (root), or making your program set-userid so that it runs as the owner of the device file.

For now we'll assume that the file is accessable by all users. The code to open serial port 1 on an sgi® workstation running IRIX is:

Listing 1 - Opening a serial port.

#include <stdio.h> /* Standard input/output definitions / #include <string.h> / String function definitions / #include <unistd.h> / UNIX standard function definitions / #include <fcntl.h> / File control definitions / #include <errno.h> / Error number definitions / #include <termios.h> / POSIX terminal control definitions */

/*

  • 'open_port()' - Open serial port 1.
  • Returns the file descriptor on success or -1 on error. */

int open_port(void) { int fd; /* File descriptor for the port */

fd = open("/dev/ttyf1", O_RDWR | O_NOCTTY | O_NDELAY); if (fd == -1) { /* * Could not open the port. */

perror("open_port: Unable to open /dev/ttyf1 - ");

} else fcntl(fd, F_SETFL, 0);

return (fd); } Other systems would require the corresponding device file name, but otherwise the code is the same.

Open Options You'll notice that when we opened the device file we used two other flags along with the read+write mode:

fd = open("/dev/ttyf1", O_RDWR | O_NOCTTY | O_NDELAY); The O_NOCTTY flag tells UNIX that this program doesn't want to be the "controlling terminal" for that port. If you don't specify this then any input (such as keyboard abort signals and so forth) will affect your process. Programs like getty(1M/8) use this feature when starting the login process, but normally a user program does not want this behavior.

The O_NDELAY flag tells UNIX that this program doesn't care what state the DCD signal line is in - whether the other end of the port is up and running. If you do not specify this flag, your process will be put to sleep until the DCD signal line is the space voltage.

Writing Data to the Port Writing data to the port is easy - just use the write(2) system call to send data it:

n = write(fd, "ATZ\r", 4); if (n < 0) fputs("write() of 4 bytes failed!\n", stderr); The write function returns the number of bytes sent or -1 if an error occurred. Usually the only error you'll run into is EIO when a MODEM or data link drops the Data Carrier Detect (DCD) line. This condition will persist until you close the port.

Reading Data from the Port Reading data from a port is a little trickier. When you operate the port in raw data mode, each read(2) system call will return however many characters are actually available in the serial input buffers. If no characters are available, the call will block (wait) until characters come in, an interval timer expires, or an error occurs. The read function can be made to return immediately by doing the following:

fcntl(fd, F_SETFL, FNDELAY); The FNDELAY option causes the read function to return 0 if no characters are available on the port. To restore normal (blocking) behavior, call fcntl() without the FNDELAY option:

fcntl(fd, F_SETFL, 0); This is also used after opening a serial port with the O_NDELAY option.

Closing a Serial Port To close the serial port, just use the close system call:

close(fd); Closing a serial port will also usually set the DTR signal low which causes most MODEMs to hang up.

⚠️ **GitHub.com Fallback** ⚠️