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.



