This article describes a simple way to interface the ADC0804 8-bit analog-to-digital converter IC to the parallel port of an IBM-compatible PC. It largely superceeds my old page on how to interface the (now obsolete) ZN448E.
The ADC0804 from National Semiconductor is a simple, cheap, easily-available 8-bit ADC. By default, the analog input range is 0 to 5V, but by using an external reference, and/or lifting the Vin- pin above GND, a wide range of input levels can be catered for. With a maximum sampling rate of 8kHz, low-quality audio work could be attempted.
See the manufacturers information and datasheet on the ADC0804 at www.national.com/pf/AD/ADC0804.html, and also my Introduction to parallel port interfacing.
The IC draws only 1mA power, so the 5V supply can be taken from a 78L05 regulator and a PP3 battery or wall plug-in PSU. In fact, the IC still seems to work with no external power, owing to currents flowing down the signal lines from the PC (however this is not recommended, especially for accurate measurements)!
+5v --@-- --- parallel
| | | port
| | v GND
| | 'D' reg.
-------------------------- pin name bit
| 20 1 |
| Vcc -CS |
| -intr 5|--->----- 15 -Error S3+
| |
| -RD 2|---<----- 1 -Strobe C0-
analog | -WR 3|---<----- 16 -Init C2+
signal ----->---|6 Vin+ | MSB
0 - 5v | D7 11|--->----- 9 D7 D7
| D6 12|--->----- 8 D6 D6
----|7 Vin- D5 13|--->----- 7 D5 D5
| | D4 14|--->----- 6 D4 D4
| | D3 15|--->----- 5 D3 D3
v | ADC0804 D2 16|--->----- 4 D2 D2
GND | D1 17|--->----- 3 D1 D1
| D0 18|--->----- 2 D0 D0
| | LSB
NC ----|9 Vref/2 |
| |
| Clk Clk An Dig |
| R in GND GND | --- 18 GND N/A
| 19 4 8 10 | | -25
-------------------------- |
| | | | |
10k| | | | | v
| | | | | GND
| | v v
-----@ GND GND
|
|
150pF---
---
|
v
GND
...and the program you need (C++ version)
// Program to collect data from a parallel port ADC,
// 8-bits at a time using simple bi-dir protocol.
// Reading data from ADC0804LCN
// (NB Circuit will self-power off port!!!)
// (C) W.A. Steer 1998
#include <iostream.h>
#include <dos.h>
// Some (symbolic) constants...
const c0=1, c1=2, c2=4, c3=8;
const s0=1, s1=2, s2=4, s3=8;
void main()
{
// Set the port address variables etc.
unsigned base, data, stat, ctrl, eppdata;
base=0x278; // 0x278 for LPT2
// 0x378 for LPT1
data=base; stat=base+1; ctrl=base+2; eppdata=base+4;
unsigned char value;
int lc;
for (int sample=0; sample<3000; sample++)
{
// To read a value from the ADC...
// Initialise ADC conversion (pulse C2+, 'D' pin 16, LOW momentarily)
outportb(ctrl, 32);
outportb(ctrl, 36);
// wait until conversion complete (until S3+, 'D' pin 15, goes HIGH)
lc=0; do { lc++; } while (((inportb(stat) & s3)==0) && (lc!=256));
if (lc==256) cout << "Timed out. (Hardware not connected/powered/functioning?)" << endl ;
else
{
outportb(ctrl, 37); // set C0- (set 'D' pin 1 LOW), enabling ADC output
value=inportb(data);
outportb(ctrl, 36); // unset C0- (set 'D' pin 1 HIGH), disabling ADC output
cout << "ADC value: " << (unsigned int)value << endl;
}
// end of ADC-read procedure
}
}
Notes on the software
© William Andrew Steer