Introduction: 10 Minute Bidirectional USB Control

This is a simple method to quickly enable USB control of external devices without using microcontrollers or expensive dev boards. Both input and output are possible, allowing two way interaction with the environment.

The project is based around a generic USB-Serial converter and a small number of discrete components likely to be found in any well-stocked junk box. Code examples are given for control of the interface and simple to construct examples are given throughout. I originally developed this interface to build an office control system , but have since used it on many projects where I wanted quick results and didn't need the complexity of full USB control.

Preview of the steps involved:
1. Overview - how does it work?
2. Output
3. Output examples: LED control and motorised flashing beacon notification
4. Input
5. Input example: signature hotkey

An arbitrary number of interfaces can be controlled by the same host machine via hubs etc., which combined with the low cost of USB-Serial converters makes this a great starting point for many projects.

Step 1: Overview

The pinout of a standard 9-pin serial connector is shown in the diagram. In addition to the RxD and TxD data lines, a number of signals are exposed that can be put under software control. These are the modem control lines. For input these are DCD, DSR, RI, CTS, while for output we can use DTR and RTS. The RS232 logic levels for the modem control lines are logic HIGH (1): anywhere between 3V and 15V, logic LOW (0): anywhere between -3V and -15V. Note that this is the reverse of those used by the RxD and TxD serial data line levels.

These levels mean they can't be interfaced directly with the TTL logic levels of HIGH +5V and LOW 0V. The signals also have a high source impedance. While this means that they can stand being short circuited it also means that you really can't power anything with a significant load. So in order to be useful, our interface needs to convert these signals to TTL levels and reduce the source resistance to allow higher power devices to be controlled.

In this example we'll just be controlling one input (CTS) and one output (RTS), but the same method can be applied to use the other available lines for control. For instance, by using both the RTS and DSR lines we could control external I²C devices by bit-banging the SDA and SCL lines.

So let's start by enabling output...

Step 2: Output

To convert an RS232 output to TTL levels we simply apply the RS232 signal to the base of a transistor in common emitter configuration. This allows us to set the voltage to our desired levels of 0V and 5V. The addition of the diode prevents damage to the transistor due to the reverse base-emitter voltage when the RS232 input is logic LOW (-3V to -15V).

Step 3: Output Examples: LED and Beacon

The USB specification allows USB ports to drive a load of up to 100mA which, even allowing for the power required for the adapter, is plenty to drive an LED. The RS232 to LED driver is shown in the first image. If you can open your USB serial adapter then you can tap the +5V USB supply to drive this low power circuit.

However it's much more rewarding to use an external supply and drive higher power devices. For example, a rotating beacon. I found these battery powered beacons recently and converted one for USB control. The circuit in the second image uses two transistors in Darlington configuration, with U2 a higher power device than U1, enough to supply a few hundred milliamps to the beacon. The beacon is simply a motor in parallel with an incandescent bulb, so I've added a small capacitor to suppress noise from the motor and a diode to prevent the back EMF from the motor damaging the transistor.

The attached file 'serialcontrol.c' can be used to control both these circuits. It allows the level on the RTS line to be switched from the command line, for example:

serialcontrol /dev/ttyUSB0 on

This makes it simple to control the beacon from a script, allowing you to make an incoming email indicator or a server monitor indicator etc. Note that the circuits in both of these examples invert the input, so you'll have to turn the port 'off' to switch the device on.

Now we just need to capture some input and we can really begin to interact with our environment!

Step 4: Input

Input is a little more tricky. We can use the +5V supply to signal logic HIGH as this is just within the RS232 spec, but we need to generate a negative voltage to signal RS232 logic LOW. What we can do is use the voltage present on the adapter's redundant TxD pin. When the port is idle (no data output), this line will be at logic HIGH (-3V to -15V - remember the RxD and TxD lines use inverted logic levels). We can use this as a negative voltage source for our converter. This time we use a PNP transistor in common emitter configuration to set the new voltages.

The value of R3 needs to be chosen based on the serial converter used as it's sensitive to the converter's input impedance. I use a value of 1K, but you may need to experiment.

Step 5: Input Example: Signature Hotkey

A simple input example is the "signature hotkey". This allows a preset word or phrase to be automatically pasted when an external button is pressed. This is particularly useful if, like me, you have an awkward surname, or if you have to end all your documents with a set phrase. For example, a British railways employee might want to assign the phrase "We apologise for any inconvenience caused to your journey."

The attached file 'hotkey.c' gives an example of a daemon process that monitors the external hotkey. When the hotkey is pressed, the daemon sends the phrase to the currently active window as a series of keypresses. This saves me considerable time when filling in online forms or writing letters. The daemon uses TIOCMIWAIT to sleep while waiting for a keypress and then sleeps for a few milliseconds afterwards to debounce the key before sending the phrase.


USB Contest

Participated in the
USB Contest