PARPORT

This was a quickie little project intended to:

  • Play around with rotary encoders
  • Show my nephews that there is more to computers than creating digital video
  • Do something quick and pleasant over the 2009 Christmas Break!

Hardware

The hardware really was quick 'n' easy - except for the rotary encoder I got from Jameco, everything else came out of my parts bins. I actually got to use some old seven-segment LED displays I've had laying about for literally decades!

See the schematic. The circuit depends on the data outputs (D7-D0) being totem-pole style active outputs (to supply sufficient current to LEDs), control outputs being open-collector style passive outputs with internal pull-up resistors, and status inputs having internal pull-up resistors. This is true of parallel ports on any but the oldest (and probably by now, rare) peecees. As a result, no passive components are required on the circuit board.

PARPORT Schematic

Well, almost. It seems that the inexpensive rotary encoder is quite noisy, particularly on Channel A when Channel B is low. So I put a fairly big capacitor on the ACK line to help filter the interrupt signal. It works fairly well, probably a larger cap would work even better.

7-SegI think there is a standard way of assigning seven-segment segments to pins. Probably the "a" and "b" should really be on the left side. But as long as it's consistent with the software, it works. I identified the pins by probing around with a small 5V power supply and a 470-ohm resistor.

Parts List

  • Seven-Segment LED display with common cathode and through-hole leads
  • PCB mount momentary contact SPST pushbutton switches
  • LEDs. Through-hole, any color
  • Rotary Encoder (Bourns PEC12-4225F-N0024, Jameco part number 776386)
  • 0.01uF ceramic capacitor, 10V or more
  • 0.1x0.1 header (I used a right-angle version)
  • 25-conductor ribbon cable, 26-pin IDC socket, 25-pin IDC male D connector
  • A bit of perf board

Construction

As seen in the photo, everything fits on a 0.1x0.1 matrix perf board. Two holes for the rotary encoder mounting tabs had to be drilled, and the holes for the switch terminals had to be drilled out, as the terminals were a bit too large for the perf board holes. After that, it was about an hour's worth of point-to-point wire-wrap wiring.

Note the bank of 300-ohm resistors; this was from an earlier phase, when I had a single seven-segment being direct-driven by the port and needed dropping resistors. Rather than mess up the wiring by removing them, I simply jumpered over them. So the resistors are not there, electrically. But they look cool and electronic for younger people!

Front ViewBack View

Software

The software is available here:

Source Zipfile

The project builds under DJGPP v2.03 and requires the pdcurses 28 library. Unzip the project in a working directory and type "make". Then run "parport". A curses screen appears, and allows you to navigate to the various control fiels with the up/down arrows, and select different options with the left/right arrows.

Description of files:

parport.c Main function, which runs everything from a tight loop as fast as the computer can run (no scheduling). Some helper functions to handle events from the user via the control panel and events detected from the hardware. Some helper functions to handle the special modes of the LED displays. Also where the global variables are defined.
global.h Defines the symbols corresponding to the global variables, and declares the "extern" global variables. This file will be included in any source file that uses the global variables.
lpt_ctrl.c All hardware interfaces are gathered in this file. Includes a "init" function to initialize all hardware operations and associated variables and a "shutdown" function to leave the parallel port in a safe state. Includes an "process" function to be called from the main loop to perform all hardware update and querying operations. Note that the "hooks" for using the ACK interrupt under DJGPP are in this file, and are enabled by uncommenting the documented line in Makefile. Interrupts don't work very well due to the noisy rotary encoder contacts, so the default operation is a state machine driven by "fast" polled inputs.
lpt_ctrl.h Presents the interface to lpt_ctrl.c functions externally.
ctlpanel.c User interface subsystem, currently based on Public Domain curses. Includes an "init" function to set up curses, create the windows and populate them, and initialize associated variables, and a "shutdown" function to stop curses and restore normal screen behaviour. Includes a "process" function to be called from the main loop to handle keyboard events, update the screen in response, and return the event to the main loop for application-unique handling. If a different user interface system were in use (say, GEM), this file would be heavily modified to accommodate it, but the same external interface would remain.
ctlpanel.h Presents the interface to ctlpanel.c functions externally.

Note to diehard Windows users: The project will work under Windows. You have to get and install the MinGW system, the pdcurses system for MinGW, and io.dll that allows port access under Windows (see the remarks in lpt_ctrl.c). Copy "Makefile.mingw" over "Makefile" and then run "make".