Status: (05/31/00) edited schematic
This is a photo of a general purpose timer/counter card
you can wirewrap in a weekend. It plugs into your
PC's ISA bus just like a sound or modem card. It gives
high-resolution timing (microseconds). Because
of its programmablity, it is very powerful and flexible.
You can even control DC or servo motors using pulse-width modulated
(PWM), or stepper motors using its square wave capabilities.
The figure below is the actual output (square wave) from the 8254
card captured by an oscilloscope:
DO REM A dummy delay which does nothing FOR X = 0 TO N REM do nothing NEXT X REM Delay finished, do the event GOSUB EVENT WHILE(userDidNotQuit)N is some integer you choose (using a stopwatch for instance) that approximates the delay time you need. There are several problems with this approach. First, it is imprecise (depending on your reflexes with a stopwatch). Second, the FOR...NEXT loop executes faster on different computers (e.g. faster on a Pentium than on a 286). Third, N is hard to tune for very short times (e.g millisecond or microsecond ranges)
One can use more sophisticated software solutions, which commonly use the PC's native timer. But typically 55 ms is the shortest time they can measure which is too long for many applications. There are software tricks (such as interrupts and DMA) for shorter times but they are not always intuitive and easy to use.
The 8254 increments its on-chip counters using pulses. It can be any pulse (0 to +5V transition). For example, you can add a SPST switch to the 8254 and the counter will increment by one for every toggle.
Motor encoder disks also generate pulses and can be used to increment the 8254's counters. Used in this manner, the 8254 can count the number of motor rotations. You can also combine counters to make a single 32 or 48-bit counter which may be useful in quadrature applications.
The 8254 is also a timer. This is because you can increment the counter with an oscillator. Thus if you use a 1.0 MHz oscillator, the counter would increment every 1 microsecond. By reading the counter's value at any instant, you can determine how much time has passed. For this reason, the 8254 is often called a timer chip, but technically, it is a counter chip.
Lastly, each counter has a gate which allows you to instantly start or stop counting. The figure below shows a pulse-width-modulated (PWM) signal captured by an oscilloscope using two of the 8254's three counters. You can easily program any duty cycle you want. PWM is a commonly used for controlling motor speeds.
This tutorial is broken down into the following sections:
PART DESCRIPTION | VENDOR | PART | PRICE EA (1999) | QTY | NOTES |
8254 CMOS 10 MHZ TIMER CHIP | JAMECO | 52409 | 5.95 | 1 | |
24 PIN WIREWRAP SOCKET | JAMECO | 75416 | 1.25 | 1 | |
1.0 MHZ OSCILLATOR | JAMECO | 27861 | 3.75 | 1 | SEE BELOW |
34-PIN IDC WIREWRAP HEADER | JDR | IDH34W | 3.59 | 2 | SEE BELOW |
34-PIN IDC SOCKET | JAMECO | 32643 | 0.45 | 2 | |
34-PIN RIBBON CABLE 25 FEET | JAMECO | 37840 | 10.50 | 1 | MIN. 25' ORDER |
2x8 HEADER PINS | JAMECO | 109567 | 0.35 | 2 | SEE BELOW |
1x36 HEADER PINS | JAMECO | 68339 | 0.49 | 1 | SEE BELOW |
JUMPER BLOCK | JAMECO | 22023 | 0.19 | 2 | |
74HC393 4-BIT RIPPLE COUNTER | JAMECO | 45874 | 0.59 | 1 | |
74LS09 AND-GATE | JAMECO | 46391 | 0.25 | 1 | |
14-PIN WIREWRAP SOCKET | JAMECO | 37217 | 0.75 | 2 | |
74HC138 3-8 DECODER | JAMECO | 45330 | 0.45 | 2 | |
16-PIN WIREWRAP SOCKET | JAMECO | 37436 | 0.95 | 2 | |
74HC373 LATCH | JAMECO | 45831 | 0.59 | 1 | |
20-PIN WIREWRAP SOCKET | JAMECO | 75379 | 1.15 | 1 | |
PC BUS PROTOTYPING CARD | JAMECO | 21531 | 17.95 | 1 | |
0.1 uF CAPS | JAMECO | 15270 | 1.00 | 4 | 1.00 FOR 10 |
11 lines from the PC's ISA slot: the three clock, gate and out lines, the +5 V and GND lines. However, the schematics uses the 34-pin sockets and ribbon cable for potential expandability. For instance, you might wish to draw out more lines from the the ISA bus in the future (e.g. the PC's interrupt lines, address, data and -5, -12, +12 volt lines).
Lastly, this particular 8254 chip is rated for 10 MHz. This gives you a delays as short as 0.1 microsecond. The schematic however uses a 1.0 MHz oscillator for 1 microsecond resolutions but you can use any oscillator up to 10 MHz that suits your own needs.
PC interfacing through the ISA slot has many advantages over
the parallel or serial interfacing. Firs, ISA slots
directly connect your card's circuit to your PC's processor
and hence data is quickly transferred. Second, the data
lines are bidirectional, which means you can easily read or
write 8-bit (one byte) data to and from your ISA-circuit.
Third, the ISA-slots bring out many of the PC's processors
pinouts such as interrupts, address, and data lines. Fourth,
the ISA-slot also has a +5 V supply line so you don't need an
extra power supply to run your card's TTL chips.
The 8-bit ISA slot is 62-pin edge connector and has the
pinouts shown in the figure (left). There are 31
pins on both the component and solder sides (Figures 3 and 4).
The second block is the eight data lines D0-D7 which your computer's processor (via the ISA slot) uses to transfer (reading and writing) data to and from the 8254.
The third block is the chip select (/CS), chip reading and writing (/WR and /RD) and programming mode select lines (A0 and A1). Your computer's processor uses these lines to program the 8254 when reading or writing counter values.
Status: edited schematic introduced 05/31/00
NB: 05/31/00 8254Schematic.gif and 8254Schematic.pdf were replaced with the 8254sch3.gif and 8254sch.pdf shown above. These are corrected diagrams and address readers' questions and concerns.
One often confusing point with ISA-related circuits is the use of the prefix "A". As mentioned before, an ISA card has a component and a solder side, often called "A" and "B" respectively. There are 62 edge tabs: 31 on the component side (A1-to-A31) and 31 on the solder side (B1-to-B31). However, address lines often use the prefix "A" too. On the PC there are 20 address lines (A0-to-A19).
To avoid this prefix confusion, this tutorial uses the lower case "a" to refer to the component side's 31 edge tabs. For example a11 is the AEN pin. "b" refers to the solder side's 31 edge tabs. For example b13 identifies the /WR pin.
One of the two 74HC138 chips in the schematic works with an 8-position jumper to assign a unique address to your 8254 card. Figure 5 below shows the jumper block in one of the 8-positions on the header.
You can choose one of the following 8 addresses:
Since Figure 5 shows the block in position 4 (from the top) the 8254 card's address is 260H (or 608D). The suffixes "H" and "D" mean hexadecimal and decimal respectively. Later, in the programming section, you will use this address to program your 8254 card.
The above eight addresses are not typically used by sound, modem and CD-ROM cards. If by hapchance your 8254 gives you unexpected results, you might have an address conflict. This is easily resolved by choosing a different jumper position.
This 4-pin silver rectangular shaped part generates square waves at its rated frequency. The schematic uses a 1.0 MHz crystal oscillator. Very often commercial 8254 cards use the ISA's OSC (pin b30 on the ISA slot) pinout rather than use an oscillator. This is a bad design for several reasons.
First, oscillators gives you predictable results on any PC. OSC is the PC's native oscillator and depending on your PC, (PC, XT, AT, 286 etc) can be 2, 4, 8, 12 MHz and higher. The 1.0 MHz oscillator is only $3.75 which is a cheap price to pay to make your 8254 board work predictably, independent of PC-model.
Second, commercial boards that do have an oscillator do not use a socket. Again, this forces you to use whatever oscillator the manufacturer decides and is restrictive. By using a socket, you can easily replace the 1.0 MHz oscillator with whichever one that better suits your needs (up to 10 MHz).
In addition to the 8254 card,
you need to construct a terminal expansion board. This board is
where you will eventually wire up your peripherals to.
The 34-pin cable tethers (Figure 7) the card and board. Figure 8
is a photo of a terminal expansion board made from a regular
breadboard. The 34-pin cable attaches to the 34-pin socket on this
terminal expansion noard. The male stub on the connector fits
into the socket's female notch. Figure 8 also shows some additional
circuits. One is a JK flip-flop which was used for motor speed
control. There is also a switch which was used to count toggles.
OUT(portAddress, byteValue) byteValue = IN(portAddress)
OUT writes byteValue (0 to 255 decimal) to the address defined in portAddress and IN reads the value from portAddress and stores it in the variable byteValue.
In Turbo C you use:
outportb(portAddress, byteValue) byteValue = inportb(portAddress)
to accomplish the same thing. outportb() and inportb() are defined in the conio.h header file, so you must to #include it in your Turbo C program. For this tutorial we will use Turbo C to highlight programming in DOS and easy enough to translate into other languages.
int baseAddress, counter0, counter1, counter2; baseAddress = 608; /* 8254 card's base address in decimal */ counter0 = baseAddress; counter1 = baseAddress + 1; counter2 = baseAddress + 2;
one then does a outportb(counter0, counterValue) to write a value to counter0 or a counterValue = inportb(counter0) to read a value from counter0 . You do the same outportb() and inportb() if you need to select counter1 and counter2.
controlRegister = baseAddress + 3; outportb(controlRegister, controlWord);
where the variable controlWord is determined with the following chart (Figure 9)
From Figure 9 we can see that the control word is an 8-bit binary number. There are 5 steps to calculate the proper control word number:
Step 1: Chose one counter (SC1 and SC0) Step 2: Chose method to load (RW1 and RW0) Step 3: Chose programming mode (M2, M1 and M0) Step 4: Chose binary or BCD number (BCD). Step 5: Convert the final binary word into decimal
Example: Suppose you want to make counter 0 a binary counter that generates square waves, and uses LSB and MSB read/write loading. What is the proper control word?
Figure 10 shows
the answer. From Step 1, SC1 and SC0 both are 0 if you
want to use counter 0. Step 2 say that LSB and MSB are
both loaded. For square wave generation, you use Mode 3 and
Step 3 says that M2,M1,M0 = 011. Step 4 makes BCD = 0 to
have a binary counter. Thus the resulting binary number
is 00110110 or, 54 decimal. Thus you would load
the control register with controlWord
with 54:
controlRegister = baseAddress + 3; outportb(controlRegister, 54); /* counter 0 is in Mode 3 */D. LSB and MSB
All 3 counters are 16-bits. A byte is 8-bits long, hence each timer is 2-bytes. This means that each counter can have values ranging from:
0000000000000000 (16 zeros) to 1111111111111111 (16 ones)in binary, or 0 to 65535 decimal. ISA is an 8-bit data bus and can read or write only one byte at a time. Thus to read or write a 16-bit value, you must do so one byte at a time. The lower and higher 8-bit numbers are called least and most-significant bytes (LSB, MSB) respectively. For example, to load counter0 with 38370 decimal, the LSB is 226 decimal, and its MSB is 149 decimal (Figure 11).
![]()
The control word's RW1 and RW0 setting tells the 8254 that you will read or write 16-bit byte values with the LSB first followed by the MSB. In code you would do the following:
/* load counter 0 with value 38370 for example */ outportb(counter0, 226); /* load LSB first */ outportb(counter0, 149); /* then load MSB */There might be cases where you only want to read or write the LSB or MSB. You would then choose the respective RW1 and RW0 values from Figure 9.
E. Counter Reading and/or Writing
By reading the counter value you can determine how many pulses it has received. Rather than counting upwardly (0,1,2..., 65535), the 8254's counters by default, count downwardly (65535, 65534...,0). In many of the programming modes, the counter will wrap around and start at 65535 once it has reached 0.You can give a counter a preset value to start counting down from by writing this value to it. For example in the code above, counter0 starts counting down from 38370.
For timed applications, using a 1.0 MHz oscillator, each count takes 1 microseconds (usec). Thus the preset value takes the same number of usec needed to reach 0. Thus 38370 would take 38370 usec.
You now may know see the significance of using the 74HC393. By changing jumper positions you can easily drive the counter with a different frequency. Thus we have:
Frequency time/count 1.0 MHz 1 usec 500 KHz 2 usec 250 KHz 4 usec 125 KHz 8 usec 62.5 KHz 16 usecII. The Code
With the preliminaries out of the way, 3sqwave.c . is a short Turbo C program that allows the user to select a counter and frequency to generate square waves. A useful application of this code is to drive a stepper motor. Many dedicated stepper motor chips (such as Allegro Microsystems 5804) require a square wave, thus you can extend the code to run a stepper motor.The program begins by defining crystalValue with 1.0 MHz. Further down, baseAddress is given the 8254 card address 608 decimal and is used to assign addresses to the counters and control register.
Each counter is then configured in Mode 3 (square wave) as a binary counter with LSB and MSB loading. This makes the control word 54, 118 and 182 decimal (see Figure 9).
During program execution the user is then promped to select a counter (0, 1 or 2) and its gate, (gateNumber) is then assigned.
The user is then asked to enter a frequency. The appropriate calculations are performed to load the counter's preset value counterValue. The gate can be toggled so that the user can stop or start the squave wave at any time. Also, the user can change the squave wave frequency at any time during program execution.
As you can see programming the 8254 is not very complicated. The 8254's other modes can be programmed similarly.
Final Words
This tutorial provides a solution to many timing and counting needs required in PC interfacing. By building the 8254 circuit on an ISA card, one can have a very powerful, flexible and high resolution timer.Program mode 3 was illustrated to demonstrate the 8254 card's squave wave generating ability. In the near future, source code for other modes will be added. Other soon to come tutorials will illustrate the 8254 forL
- (Available 06/14/99) A motor speed control using pulse-width-modulation
- Counting motor revolutions
- Stepper motor application
- Running servo motors
Let me know (email) if you have found this tutorial useful! Happy building and interfacing. Click here to go Paul's Main Page
Click here to go to Columbia University's Robotics Lab
Click here to email me