From: fdeck@happy.helios.nd.edu (francis deck) Subject: Cheap 12-bit ADC circuit for PC CHEAP 12-BIT ADC FOR IBM PC Francis J. Deck fdeck@grumpy.helios.nd.edu This is an 8-channel 12-bit analog-to-digital converter that hooks up to the parallel printer port of a PC and costs well under $50. All parts (and data sheets for the chips) are available from Digi-Key, 1-800-DIGI-KEY. Recommended construction technique is hand-wiring on perfboard w/ ground plane. The big decoupling caps are mandatory, otherwise you get a lot of noise in the readings. The resistors on the inputs limit current through the input protection diodes of the LTC1290, which protects from overloads of up to +/- 15 V. Of course, this circuit is not guaranteed for accuracy, safety, or reliability, and does not protect your computer against damage from electric discharge or overloads. It is up to you to evaluate the circuit for its suitability for a particular application. Software is in Turbo Pascal, and was compiled under Version 5.0. You may have to modify the NLPT and DELAY constants in the program for your machine. There is a mandatory 13 microsecond delay which is created by a software loop. SCHEMATIC DIAGRAM 8 ----- 14 ANALOG INPUTS -----|4 MHz|---P (+/- 2.5 V) LTC1290 | |Clock|7 1 ---------- 20 | |Osc |---G A0 o------R------|CH0 VCC|----P | ----- 2| |19 | IBM PC Parallel A1 o------R------|CH1 ACLK|---------- Printer Port 3| |18 2 (use male DB25) A2 o------R------|CH2 SCLK|---------------o D0 4| |17 3 A3 o------R------|CH3 DIN|---------------o D1 5| |16 10 A4 o------R------|CH4 DOUT|---------------o ACK 6| |15 4 A5 o------R------|CH5 CS'|---------------o D2 7| |14 18 A6 o------R------|CH6 REF+|------ G---o GND 8| |13 | A7 o------R------|CH7 REF-|---G | 9| |12 |---R---P G---|COM V-|---N |+ 10| |11 Z G---|DGND AGND|---G | ---------- G POWER SUPPLY +---------+-----------------o +5 V | | | gnd| |+ ----- out B |79L05|-----G | ----- | |in | | +---------+-----------------o -4 V LEGEND: P = +5 V supply N = negative supply G = ground R = 1k resistor Z = LM336Z-2.5 precision Zener B = 9 V battery DECOUPLING +5 Supply: 22 uF tantalum (watch polarity) -4 Supply: 0.1 uF disc REF+: 4.7 uF tantalum (watch polarity)} {======== CONTROL ROUTINES FOR 12-BIT ADC CIRCUIT ========} unit ltc1290; interface {-------- User-definable constants --------} const lpt1 = 1; {these define the 3 printer ports} lpt2 = 2; lpt3 = 3; adc_nlpt = lpt1; {which port?} vref = 2.48; {reference voltage} {-------- Read an ADC channel, result in V --------} function adc_read (ch: integer): real; {======== Implementation Section ========} implementation const sclk = 1; {SCLK line on output port} din = 2; {DIN line on output port} dout = 64; {DOUT line on output port} cs = 4; {CS' line on input port} var lpt_addrlist: array[1..3] of word absolute $40:08; {BIOS RAM} aout, ain: word; {input, output port addresses} {-------- Read an ADC channel --------} function adc_read; const wconst = 1 + 32 + 64; {setup for single-ended, bipolar, MSB first} chconst: array[0..7] of byte = (0,2,8,10,4,6,12,14); {channels} delay = 10; {may have to be larger for '386 machines} var i: integer; {loop counter} win: word; {word transmitted to ADC chip} result: word; {word received from ADC chip} begin for i := 1 to delay do begin end; {software delay} win := wconst + chconst[ch]; {transmit setup word} port[aout] := 0; {drop CS'} for i := 1 to 12 do begin port[aout] := (win and 1)*din; {put bit on output} port[aout] := (win and 1)*din + sclk; {clock it out} win := win div 2; {shift setup word} port[aout] := 0; {drop clock line} end; port[aout] := cs; {raise CS'} for i := 1 to delay do begin end; {software delay} {receive conversion result word} port[aout] := 0; {drop CS'} result := 0; win := wconst + chconst[ch]; {retransmit setup word} for i := 1 to 12 do begin port[aout] := (win and 1)*din; {put bit on output} port[aout] := (win and 1)*din + sclk; {clock it out} result := result*2; {shift result word} if port[ain] and dout <> 0 then result := result + 1; port[aout] := 0; {drop clock line} end; port[aout] := cs; {raise CS'} adc_read := vref*((result + 2048) and 4095)/2048 - vref; end; {-------- Initialization ----------} var dummy: real; {dummy analog input} begin aout := lpt_addrlist[adc_nlpt]; {find port addresses} ain := aout + 1; {other address} port [aout] := cs; {deselect ADC chip} dummy := adc_read(0); {read ADC once} end. {======== DEMO PROGRAM FOR ADC =========} program testltc; uses crt, ltc1290; var i: integer; begin writeln ('Press a key to finish.'); while not keypressed do begin for i := 0 to 7 do write (adc_read(i):4:4,' '); writeln ('V'); delay (1000); end; end.