Serial interfaces are still used

Serial port

As the name suggests, the serial interface is used for serial data exchange with older mice and modems, for example. The standard used for this on the PC is RS-232C, usually called RS232 or V.24 for short. The interface is specified mechanically, electrically and logically from this standard. In contrast to the parallel port, the data protocols are already specified in the standard here, which defines the mechanics and electrics. Just like the parallel port, the serial interface is also capable of multiple interrupts.
This interface is attractive for the hobby electronics technician, as he does not have to worry much about the protocol and, in addition to the bulk wire, only one receive and one transmit wire are required for a bidirectional connection.

The serial interface in detail

The serial interface is available in both 9 and 25 poles. However, since most of the pins are unused in the 25-pin version and the pins otherwise have the same signals as the 9-pin version, it is very rare.
A good overview of the pins can be found at
Since the serial interface with 10 registers has many more registers than the standard parallel port and these registers are practically never controlled directly, reference is made to specialist literature such as the PC hardware book for a complete description. Another reason is that platforms other than PCs usually use different registers.

In practice there are some problems with the serial interface, for example because the logic levels of -12 and +12 V are not clean, e.g. B. because with an optocoupler that is supplied by the interface, only 0 V can be output as a low level or with a notebook that outputs only -5 and +5 V.
Another problem is the timing, i.e. the time reading / outputting of the data, which is theoretically easy, but does not work properly, especially on cheap mainboards.
These two problems, i.e. with regard to amplitude and phase, usually only appear at higher data rates, i.e. from 9600 baud (baud = bit / s), so that many devices, especially digital multimeters, are operated at low baud rates of 1200 or 2400.
Regarding the baud rate, it should also be noted that it cannot be freely selected, but only which can be selected from a list. This list ranges from 50 to 4,000,000 Hz and can be found in the relevant include file, for example bits / termios.h under Linux. In addition, not every program can use every baud rate; For example, the terminal programs only work up to 115.2 kbaud, even if 4 Mbaud is possible without any problems.
It is also important that the permissible cable length is inversely proportional to the baud rate and is 1.5 m at 57,600 baud (according to c't), but a little more cable length can usually be used. Converters with differential serial interfaces can be used for extension; these use other standards such as RS485.

Control of the serial interface with software

Direct control

More than 99% of the time, the serial interface is used as USART and therefore the pins are almost never controlled directly.
Nevertheless, the direct pin control is dealt with first, as you can do a lot of useful things with it. The output voltage of the pins is -12 or +12 V, depending on whether 1 or 0 is present. It is resilient with a few milliamps, so it is enough z. B. to control an LED. This is used, for example, to supply power to small devices such as a DCF-77 receiver (radio clock receiver) and also to read in the DCF-77 signal directly, which has only 1 baud in terms of amplitude modulation. It is also important for light barriers, since the supply voltage for the receiving side must be supplied by the interface. For details of direct control, because of the rare use of direct pin control for the serial interface, I refer to the adjacent tutorial on the parallel port, since direct pin control is covered in detail there.

Nevertheless, as a short example of how the pins can be controlled directly via the 8-bit I / O ports, once in C / Linux:

sbase = 0x2f8; // 0x2f8 = 760 usually for the second serial port, 0x3f8 = 1016 for first,
sregister = inb (sbase + 4); // cache the port value
outb (sregister & 0xfc, sbase + 4); // clear RTS and DTR
outb (sregister | 3, sbase + 4); // clear RTS and DTR

and once in Pascal / DOS / MS-Win (and German comments):

sbase: = 0x2f8; // Base address of the second serial interface, 0x3f8 for the first
sregister: = port [sbase + 4]; // Read in the port value
port [sbase + 4]: = sregister AND 0xfc; // Set RTS and DTR to 0
port [sbase + 4]: = sregister OR 3; // Set RTS and DTR to 1

This does not work with serial interfaces that are not directly accessible, e.g. B. on the USB-RS232 adapter, but the first example below shows how RTS and DTR can also be set there.

Indirect control

Now for the usual indirect use of the serial interface as a UART.
UART is the abbreviation for Universal Asynchronous Receiver Transmitter, which means asynchronous receiver and transmitter. The hardware synchronizes itself automatically to the start bit, of which the rising edge is used as the start time. In addition, the end is marked by one or two stop bits.
Based on the set parameters, it is clear at which points in time which bits are available and also how long a byte is. A byte is a single transmitted character here; it is the bit sequence between the start bit and stop bit. If there is a parity bit, it comes before the first stop bit and the character (byte) ends there.
The start bit of the following byte can be clearly recognized by a small pause of at least one cycle.
Since only individual characters (= bytes) are transmitted in this way, there is no endianess, so that the transmission is platform-independent. The order of the bytes is only important when you transfer larger data and therefore have to break it down into bytes.

Interface parameters

For serial transmission, the parameters must first be set, i.e. speed (= baud rate = bits / s, 50 ... 4,000,000), bits per byte (5..8, on microcontrollers up to 9), parity (N = none (missing), E = grade, ...) and number of stop bits (1..2).
These parameters are usually summarized in this order, e.g. B.
9600 8N1
for 9600 baud, 8 bit / byte, no (no) parity bit and one stop bit.

USB-RS232 adapter

Since the serial interfaces are increasingly being replaced by USB interfaces, but many devices such as digital multimeters and RLC meters are still only available with an RS232 interface, the USB-RS232 adapters should not go unmentioned here.
A good 50% of these adapters contain the IC FT232BM: This IC can be used up to 4 Mbit / s, but most microcontrollers cannot.
After installing the driver, which is usually not required under Linux, since the driver is usually included and is automatically loaded, an adapter behaves like a serial interface that can be found under Linux from / dev / ttyUSB0, while the classic serial interfaces are used from / dev / ttyS0.
In addition, a USB-RS232 adapter is also suitable for the direct connection of a microcontroller, since the interface IC that converts between USB and RS232 only forwards the RS232 signals as TTL levels to a level converter IC.
If you remove the level converter IC, you can connect a microcontroller directly to the interface IC. The following picture shows what this looks like, where RxD, TxD and ground go to a socket strip at the top:

USB-RS232 adapter

The 5 V supply voltage from the USB bus was not used here as it would be too much for the microcontroller I used, MSP430, but with a voltage regulator that would not be a problem either.
Alternatively, ICs such as the FT232BM can also be designed into your own circuit, but such a reduced adapter is helpful for prototypes and old circuits with microcontrollers without level converters. In addition, experience has shown that such an adapter is more reliable than a level converter such as MAX232 on a serial interface, especially at very high baud rates (> = 115.2 kbaud).

Data logs

Although the standard describes the interface logically, you also have to think about the protocol a little, as it is usually not enough to send and receive bytes. Since normally more than one byte has to be transferred, such a block must be identified by the recipient. There are two methods for this, which can also be used simultaneously:

A) Time structuring: There is a pause between the data packets (= transmitted byte sequences) and there is practically no pause in the data packets.

B) Control characters: A control character such as 0x00 or 0xff marks the beginning and / or end of a data packet.

Variant A has the advantage that the data can be output and read in unchanged, while with variant B the control characters have to disappear from the data. Bit stuffing is used for this disappearance, for which reference is made to the specialist literature.
With variant B you have the disadvantage on the PC that you have to use relatively long pauses of a few hundredths of a second without hard real-time.
In practice, therefore, A) is usually used together with known packet lengths, with the packet length resulting from the first byte or, quite simply, always constant.
The pauses between the packets are implemented using functions such as usleep when sending and select when receiving; timer interrupts and counting variables are used for this on the microcontroller. As the next protocol layer, an error correction can be added to the existing protocols, for example the 2-of-3 function, which, applied byte by byte, corrects all 1-bit errors and even corrects a single lost byte. Before starting the protocols described, you often have to consider the order in which the data are transmitted, because data can be sent and received simultaneously via the serial interface, but a small microcontroller (MC for short) usually does not have sufficient resources (RAM, ROM) to send and receive data at the same time - not to mention the effort for the parallel threads on the MC. Half-duplex operation is therefore mostly used, in which only data is received or sent from each device at any given time. In addition, the master-slave mode is often used: the master, usually the PC, sends a request to the slave, usually the MC, and the slave replies - otherwise the slave does not output anything. This makes the PC software very simple. When programming, it must also be taken into account that the data transmission usually takes place without hard real-time and always takes place with buffers, so that a data packet output for transmission in one piece can be sent in several pieces. In addition, the output is done by the driver in the background, so that without a function that waits for the end of the sending of the data, e.g. B. tcdrain (device_file_descriptor), the software continues to run and may already want to send the next data or even wait for a response, while the output buffer is not empty and the recipient of the data cannot have received all of the data. It is also wrong to empty the send buffer without waiting for the complete sending of the data, for example with tcflush, since this deletes the last bytes of the data packet in the buffer and therefore does not send it. When receiving, the other way round, data received in one piece are not always stored in one piece in the receive buffer, also because the data arrive bit by bit one after the other and the first bytes are already written to the receive buffer while the last bytes of the data packet are still being received or have not yet arrived. A frequently occurring error is therefore to read the input buffer only once when receiving the data. On the other hand, it helps to count the bytes received and to read them in several times with a loop until the timeout (for the end of the data packet) is reached. If the packet length is unknown, it is therefore necessary to wait until the timeout. The bottom line is that the buffering and serial transmission of the data reduce the hardware effort, but make the programming a bit more complicated. The programmer should therefore get a clear picture of the data flow and a time diagram. The software then has to implement this diagram properly, for example to the complete transmission of the data, e.g. B. wait with tcdrain (device_file_descriptor).

Programs for the serial interface

There are free terminal programs for the serial interface, which are mostly used for communication with other computers and can also be used for "remote control" of the BIOS (if available; mostly only on server mainboards). This is particularly useful for computers without a monitor. These programs are available for MS Windows (hyperterm) and Linux (minicom).
These programs can also be used to communicate with hardware you have built yourself. For this, however, the binary data must be converted to ASCII, if possible 7-bit ASCII. An example of this is the LCR 612 LCR meter from Tecpel, which is new on Ebay for 110 EUR.

Example 1: Reading in digital multimeter data

This example reads in the data that the digital multimeter (DMM for short) VC 820 (around 45 EUR at or the VC 840 constantly outputs. The serial interface of the DMM is isolated from the PC via an optocoupler up to at least 2000 V.
Since the DMM does not have a data input or it is not equipped in the device, it can only be read in what the device is currently measuring, so that you have to do it yourself to control the DMM. There are other DMMs for which this is not necessary, as they can be completely controlled via the interface, but they also cost significantly more.
You can also take the 5 V from the USB bus for power supply for continuous measurements, as the LowBat display only appears below 4 V and the DMM only consumes a few mA.

Fig. 1: Conrad VC 820 digital multimeter

The program vc840.c in detail

The program is in C for Linux, but easily portable, since only the interface functions have to be adapted. However, it should work under any Posix-compliant operating system without modification, including FreeBSD, Unix, etc.
Since only data is read in and the interface parameters are fixed, only the device file of the connected interface is required as command line parameters.
The data are read in by opening the device file, for example / dev / ttyS0 (first serial interface), with open and then the data is read in with read:

// open the file descriptor with the read + write mode and not waiting (blocking) mode
fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY);
read (fd, & buffer [n], 1); // write one byte into the buffer

This is the core of the driver and no root privileges are required for this, as only the driver of the serial interface accesses the hardware directly.
In addition to the code for decoding the data, the program also includes setting the necessary interface parameters, for example the interface speed and exclusive access to the interface, so that several programs cannot access the interface at the same time.
According to the Serial Programming Howto, select is used to receive the data and some checks are still built in, since the data transmission via the serial interface is not very reliable. This also makes use of the fact that microcontrollers send the data by means of an interrupt service routine, so that the data are transmitted in seamless packets with long pauses if no errors occur.
There is also a timeout Posix thread in the program, which is necessary for some serial interfaces and USB-RS232 adapters, which open but cannot be initialized and stop the thread at this point, even if the interface is non-blocking is opened.

Here is a command line example for the program that shows the received values ​​and any error messages / status messages both together in the console, and also saves the measured values ​​separately in "data" and saves the error messages / status messages separately in "log.err":

{./vc840 / dev / ttyS0 | tee data; } 3> & 2 2> & 1 1> & 3 | tee log.err

The data file contains the values ​​(time in s since start and measured value)
separated by spaces:
0.4 -297,200 mV ()
0.8 -297,300 mV ()
1.1 -297,300 mV ()


In addition to the program, there is also the script, which plots the measurement data every second using Gnuplot. This means that the time course of the measurement data can be followed graphically and virtually in real time. The script is used with a pipe (|) on the command line:
./ | gnuplot

An article on other, older digital multimeters can be found in Linuxmagazin, issue 8/1998, which is also available online at

Example 2: Switchable socket strip

The second example is not used for measuring but for controlling and it uses the 8fa relay card, which is relatively cheap for less than 40 EUR, with which you can switch eight sockets with up to 6 amps (after you have strengthened the conductor tracks of the relays accordingly).
This relay card is used in a switchable socket strip with a spacious, earthed iron housing (Power Manager, 40 EUR at so that the stray fields are well shielded and the residual current circuit breaker is triggered as quickly as possible in the event of a fault.
A remaining stock plug-in power supply unit for 12 V is used for power supply, but the card can also be supplied with 12 V from the PC's Firewire bus (if available).
Since the power manager only has 7 sockets, but the card has 8 relays, there is an extra output to switch low voltage.
So that the mass of the card does not drift freely, it is connected to the protective conductor with a medium-ohm resistor (here 560 ohms), since unnecessarily large hum currents would flow with a zero-ohm resistor, which could trigger an FI circuit breaker; d. H. This passive termination dampens ripple voltages.

Image 1: 8fa relay card in the power box, both from, both around 40 EUR. An egg boiler is attached.

The relais.c program in detail

As in example 1, the program is in C for Linux, but easily portable.
This driver is essentially the same as in the previous example, but with the addition that data is also written using

write (fd, wbuf, 4);

In addition, the exclusive or of the bytes of a packet is attached to the packet as a checksum. This checksum is very short, simple, requires little code and shows all 1-bit errors as well as most multi-bit errors.
The control command is of course required as an additional parameter for control; for example -off to switch off:

./relais / dev / ttyUSB0 -off

Further information can be found in the header and the documentation of the card, which can be downloaded from Conrad.

At there is another open source program that controls several of these cards via one interface, because these cards can be cascaded so that up to 255 pieces of a serial Interface can be controlled!


In addition to the program, there is also the script, which switches all outputs off / on every two seconds, except for number 2.
You can easily adapt it to use the PC as an 8-fold timer at the same time, for example by transferring such scripts to / etc / crontab.


I / O ports under Linux:

Linux I / O port programming mini-HOWTO:

Serial Programming HOWTO:

Serial Programming Guide for POSIX Operating Systems:

Book "Developing Linux Drivers, A Systematic Introduction to Device Drivers for the 2.6 Kernel, Free and Completely Online:

Book Linux Device Drivers:

Hard real-time extension RTAI for the Linux kernel:

Posix-Threads: Book "Pthreads Programming"

Posix Threads Tutorial:

Book "I / O projects for the PC", ISBN 3-89576-129-X, with simple DOS / MS-Win drivers for many interfaces on the PC.


So far, only simple user programs have been dealt with, i.e. programs in user space.
In order to avoid redundancy, I refer to the neighboring tutorial on the parallel port with regard to kernel space and hard real-time.