Tech Tutorials > Parallel Port


The PC's parallel port can be very useful I/O channel for connecting your own circuits to PC. It can be used to perform some very amusing hardware interfacing experiments. The port is very easy to use when you first understand some basic tricks.

WARNING: PC parallel port can be damaged quite easily if you make mistakes in the circuits you connect to it. If the parallel port is integrated to the motherboard (like in many new computers) repairing damaged parallel port may be expensive (in many cases it it is cheaper to replace the whole motherborard than repair that port).

PC parallel port is 25 pin D-shaped female connector in the back of the computer. It is normally used for connecting computer to printer, but many other types of hardware for that port is available today.

Parallel Port pins

The pins can be used an Input and Output, although there are some restrictions for the pins:

Pin1^2-91011^121314^151617^18-25
DirectionIn/OutIn/Out*InInInInIn/OutInIn/OutIn/OutGND
RegisterC.0D.(0-7)S.7S.6S.5S.4C.1S.3C.2C.3GND

Note:

Normally, data, control and status registers will have following addresses. We need these addresses in programming later.

RegisterAddress
(Hexadecimal)
Data378
Status379
Control37A

There are mainly three specifications for the Parallel Port namely SPP, EPP and ECP. I would not give details about these since they are irrelevant, but to use the parallel port properly, make sure that the port is set as EPP or ECP from the BIOS.

Parallel port male To start using the parallel port, you will need a parallel port cable with D-25 type Male connector on one side as shown. Regarding the pin numbering, pay close attention to the 25-pin plug and you will see that each pin is numbered (or else the end pins will be numbered). The male connector goes into the parallel port socket behind the CPU.

The output pins of the parallel port are TTL level output pins. This means that they put out ideally 0V when they are in low logic level (0) and +5V when they are in high logic level (1). In real world the voltages can be something different from ideal when the circuit is loaded. The output current capacity of the parallel port is limited to only few milliamperes. In ordinary parallel port implementations the data outputs are 74LS374 IC totem-pole TTL outputs which can source 2.6 mA and sink 24 mA.
Note: When taking current from PC parallel port, keep the load low, only up to few milliamperes. Trying to take too much current (for example shorting pins to ground) can fry the parallel port.

Simple LED circuits

LED You can make simple circuit for driving a small led through PC parallel port. The only components needed are one LED and one 470 ohm resistors. You simply connect the diode and resistor in series. The resistors is needed to limit the current taken from parallel port to a value which light up acceptably normal LEDs and is still safe value (not overloading the parallel port chip). In practical case the output current will be few milliampres for the LED, which will cause a typical LED to somewhat light up visibly, but not get the full brigtness.

Then you connect the circuit to the parallel port so that one end of the circuit goes to one data pin (that one you with to use for controlling that LED) and another one goes to any of the ground pins. Be sure to fit the circuit so that the LED positive lead (the longer one) goes to the datapin. If you put the led in the wrong way, it will not light in any condition. You can connect one circuit to each of the parallel port data pins. In this way you get eight software controllable LEDs.

Led connected to Parallel port

The software controlling is easy. When you send out 1 to the datapin where the LED is connected, that LED will light. When you send 0 to that same pin, the LED will no longer light.

For more parallel port controlled circuits try epanorama.net. That is the site from where I got most of the content for this page.

Programming

I'll be using Linux as the OS and C/C++ as the language for development. There is a direct interface available for controlling the Parallel Port in C, but there are libraries available which make your task simpler.

One of the best library I found is parapin. It allows you to control each pin individually, which is really useful in our circuits. You will have to download it from the parapin site. A few examples are also given (in the examples directory) in the package you download from the site.

Using parapin

The following is just a summary of the documentation of parapin. For details, you can look up the original documentation.

After downloading and extracting, copy the parapin.h and parapin.c files to the directory where your program is kept. In the program include the parapin.h file:

	#include "parapin.h"

While compiling your program, compile parapin.c with your program as follows:

	gcc yourprogram.c parapin.c

Note: You must be logged in as root to use most of the functions below, since they require access of ports which is not allowed to a normal user by default in Linux.

Before any other Parapin functions can be used, the library must be initialized. Initialization is performed using the function

        int pin_init_user(int lp_base);

whose single argument, lp_base, specifies the base I/O address of the parallel port being controlled. This is where the addresses we talked about above, will be helpful. So to initialize, you'll write:

	pin_init_user(0x378);

The return value of pin_init_user will be 0 if initialization is successful, or -1 if there is an error. Applications must not call other Parapin functions if initialization fails, so you will have to check the return value. Failed initialization is usually because the program is not running as root.

As you may have noticed, I gave the address of the Data Pins. First try using the the Data pins since they are easier to use.

Most of the pins on modern parallel ports can be configured as either inputs or outputs. When Parapin is initialized, it is safest to assume that the state of all these switchable pins is undefined. That is, they must be explicitly configured as outputs before values are asserted, or configured as inputs before they are queried.

As mentioned earlier, Pins 2-9 (Data Pins) can not be configured independently. They are always in the same mode: either all input or all output. Configuring any pin in that range has the effect of configuring all of them.

At this point I recommend going through the Basics section of the parapin documentation, to get acquainted with its Pin naming convetion. Ignore the information about the kernel version of parapin, we don't need it.

Pin mode (Output/Input)

In parapin, the pins can be set to output mode or input mode using the following three functions:

        void pin_input_mode(int pins);
        void pin_output_mode(int pins);
        void pin_mode(int pins, int mode);

The pins argument of all three functions accepts the LP_PINnn constants described in the Basics Section of the documentation.

Examples:

        pin_input_mode(LP_PIN01);
        /* Pin 1 is now an input */

        pin_output_mode(LP_PIN14 | LP_PIN16);
        /* Pins 14 and 16 are now outputs */

        pin_mode(LP_PIN02, LP_INPUT);
        /* Pins 2 through 9 are now ALL inputs */

        pin_mode(LP_PIN01 | LP_PIN02, LP_OUTPUT);
        /* Pin 1, and Pins 2-9 are ALL outputs */

        pin_input_mode(LP_DATA_PINS);
        /* The constant LP_DATA_PINS is an alias for Pins 2-9 */

Outputing a Value

Once Parapin has been initialized, and pins have been configured as output pins, values can be asserted on those pins using the following functions:

        void set_pin(int pins);
        void clear_pin(int pins);
        void change_pin(int pins, int state);

The pins argument of all three functions accepts the LP_PINnn constants. set_pin turns pins on, electrically asserting high TTL values. clear_pin turns pins off, electrically asserting low TTL values. The convenience function change_pin does the same thing as set_pin and clear_pin; its state argument takes one of the constants LP_SET or LP_CLEAR. Calling change_pin(pins, LP_SET) has exactly the same effect as calling set_pin(pins).

Note: These three functions will only have effects on pins that were previously configured as output pins. Attempting to assert a value on an input pin will have no effect.

Note that while the direction of Pins 2-9 must be the same at all times (i.e., either all input or all output), the actual values of these pins are individually controllable when they are in output mode.

Examples:

        pin_output_mode(LP_PIN01|LP_DATA_PINS|LP_PIN14|LP_PIN16|LP_PIN17);
        /* All these pins are now in output mode */

        set_pin(LP_PIN01 | LP_PIN04 | LP_PIN07 | LP_PIN14 | LP_PIN16);
        /* Pins 1, 4, 7, 14, and 16 are all on */

        clear_pin(LP_PIN01 | LP_PIN16);
        /* Pins 1 and 16 are now off */

        change_pin(LP_PIN01 | LP_PIN02, some_integer ? LP_SET :	LP_CLEAR);
        /* Pins 1 and 2 are now off if and only if some_integer == 0 */

Taking Input

Once Parapin has been initialized, and pins have been configured as input pins, the value can be read using the following function:

        int pin_is_set(int pins);

Any number of pins can be queried simultaneously. The pins argument accepts the LP_PINnn constants. The return value is an integer in the same format. Any pins that are set (electrically high) will be set in the return value; pins that are clear (electrically low) will be clear in the return value.

Pins may only be queried if:

Any query to an output pin will always return a value indicating that the pin is clear. In other words, this function can not be used to determine what value was previously asserted to an output pin.

Examples:

        pin_input_mode(LP_PIN01 | LP_DATA_PINS | LP_PIN17);
        /* Pins 1, 2-9, and 17 are now in input mode, along with
           Pins 10, 11, 12, 13, and 15, which are always inputs */

        /* check the state of pin 1 */
        printf("Pin 1 is %s!\n", pin_is_set(LP_PIN01) ? "on" : "off");

        /* check pins 2, 5, 10, and 17 - demonstrating a multiple query */
        int result = pin_is_set(LP_PIN02 | LP_PIN05 | LP_PIN10 | LP_PIN17);

        if (!result)
                printf("Pins 2, 5, 10 and 17 are all off\n");
        else {
                if (result & LP_PIN02)
                        printf("Pin 2 is high!\n");
                if (result & LP_PIN05)
                        printf("Pin 5 is high!\n");
                if (result & LP_PIN10)
                        printf("Pin 10 is high!\n");
                if (result & LP_PIN17)
                        printf("Pin 17 is high!\n");
        }

That's it. I think this much info is good enough for you to start using the parallel port in your own circuits. For any queries you can always contact me.


Tech Tutorials > Parallel Port