program a2dmax; { A2DMAX version 2.0 Copyright 1997 Radio-Sky Publishing } {This is a program written to collect data from the max186 12 bit/8 channel analog to digital converter chip via a parallel port. It is written for the seismometer project proposed for the Amateur Scientist column of Scientific American. This program is distributed as Freeware and may be used or modified by anyone for non-profit enterprises. If modifications are made you should completely document these changes in the source code before redistributing the software. The designation of Freeware does not in any way relinquish the copyright of this program to others, and only implies that the program is distributed without charge. The first 4 channels are used (a,b,c,d). Inputs are single ended, that is, referenced to ground. The max186 may be run in single or bipolar modes. In bipolar mode + and -5 volt supplies are required. In single polar mode only a 5V supply is needed, but signal input voltages cannot swing negative. Input signals should range between +/- 2.049 volts (bipolar operation),and 0 to +4.095V for single polar operation. Inputs to the MAX186 should be tied to ground with a 100 kilohm resistor to avoid interference between channels. The forth channel is used for timing. A 60 hz square wave (5v) is fed to the timing channel. The program is written using an old version (5.0) of Turbo Pascal for DOS but should be easily converted to PASCALs for other operating systems. The main requirement is that the parallel port operate in a similar fashion. Two different port addresses (i,o) are used for input and output functions respectively. For IBM compatible PCs using an MSDOS operating system, use the Microsoft Diagnostic (MSD.EXE) program to find out the base address of the printer port to which the converter is connected. The Input Port will be 13 + Base Address of the port and the Output Port will be 12 + Base Address, in PC compatibles. The format of the output file will binary as follows: 2 bytes representing Polarity of the AtoD unit (occurs only at start of file) 6 bytes marking beginning of sampling period (0F0F1F1F2F2F) 2 bytes year 2 bytes month 2 bytes day 2 bytes Hour 2 bytes minute 2 bytes second 2 bytes channel a sample 2 bytes channel b sample 2 bytes channel c sample with these three sampling bytes repeated until this sampling period is suspended. Since each channel is sampled exactly 10 times per second, the second in which any given sample is collected can be calculated by its position in the sampling period and the time on the header for that period. } {Notes on Version 2.0 Several things have been fixed from the first version. - A record size of 2 bytes is used for writing to the disk to make files compatible withe the new A2DMax Reader program. - Tmax and Tmin are now added to the parameters which may be changed in the default file. These are the sample levels at which the program recognizes a change of state of the timing signal. Adjusting these values may help if inconsistent timing periods are encountered due to the timing waveforms variation from a square wave. - QuietVal is a new variable which is added to the default file. This is the number of consecutive sample values which must fall below the thresholds before a sampling event is ended and flushed to disk.} uses Crt, Graph, Dos; { o = $3BC; outport i = $3BD; in port ...used in test computer 486/25sx} { where the base address was discovered to be $3B0. } var GraphDriver, GraphMode : integer; GraphDriverPath : String; Clip, Recorded, ChA, ChB, ChC: boolean; gx,gy1,gy2,gy3:integer; i,o,Va,Vb,Vc:word; {input port,output port,threshold parameter} RunDirectory,DataDirectory: string; D:text; {default file} a : integer; {accumulator} p : word; {bit counter} DataFile: file; Amp,x,dptr,A1,LastA1,A2,LastA2,A3,LastA3 : integer; {Polar=1 single pole, =2 bipolar supply and data} choice : char; RecordedSamples: LongInt; RSamples:string; Blank:string; Polar,Result,Year,Month,Day,DayofWeek,Hour,Minute,Second,Sec100:word; FileInfo : SearchRec; DataFileName,VaS,VbS,VcS,PinS,PoutS,AmpS: string; QuietValS,TmaxS,TminS: string; Found: boolean; DataBuffer:array[1..28000] of integer; Tmax:integer; {timing signal high state} Tmin:integer; {timing signal low state} Quiet:integer; { Used to count quiet samples before flush to disk.} QuietVal:integer; { Value at which quite period triggers flush to disk} Procedure UpCaseStr0(Var s : String); Var i : Integer; Begin For i := 1 to Length(s) Do s[i] := UpCase(s[i]); end; procedure GetA(var a:integer); begin a :=0; for p := 11 downto 0 do begin Port[o] :=4; Port[o] :=0; x := Port[i]; x := x AND 32; if x=32 then a := a OR 1; a := a*2 end; Port[o] :=1; end; procedure CheckPolar; begin if Polar = 1 then begin Port[o] :=2; Port[o] :=6; Port[o] :=2; end else begin Port[o] :=0; Port[o] :=4; Port[o] :=0; end; end; procedure SetUp1; begin Port[o] :=1; Port[o] :=0; Port[o] :=2; Port[o] :=6; Port[o] :=2; Port[o] :=0; Port[o] :=4; Port[o] :=0; Port[o] :=4; Port[o] :=0; Port[o] :=0; Port[o] :=4; Port[o] :=0; CheckPolar; Port[o] :=2; Port[o] :=6; Port[o] :=2; Port[o] :=6; Port[o] :=2; Port[o] :=0; Port[o] :=4; Port[o] :=0; end; procedure SetUp2; begin Port[o] :=1; {CS high} Port[o] :=0; {CS low} Port[o] :=2; {Clk in start bit} Port[o] :=6; Port[o] :=2; Port[o] :=2; {channel select bits} Port[o] :=6; Port[o] :=2; Port[o] :=0; Port[o] :=4; Port[o] :=0; Port[o] :=4; Port[o] :=0; CheckPolar {send proper polarity bit for bi-/single polar}; Port[o] :=2; {single ended source} Port[o] :=6; Port[o] :=2; {internal clock mode} Port[o] :=6; Port[o] :=2; Port[o] :=0; Port[o] :=4; Port[o] :=0; end; procedure SetUp3; begin Port[o] :=1; Port[o] :=0; Port[o] :=2; Port[o] :=6; Port[o] :=2; Port[o] :=0; Port[o] :=4; Port[o] :=0; Port[o] :=4; Port[o] :=0; Port[o] :=2; Port[o] :=6; Port[o] :=2; CheckPolar; Port[o] :=2; Port[o] :=6; Port[o] :=2; Port[o] :=6; Port[o] :=2; Port[o] :=0; Port[o] :=4; Port[o] :=0; end; procedure SetUp4; {Timer Port} begin Port[o] :=1; Port[o] :=0; Port[o] :=2; Port[o] :=6; Port[o] :=2; Port[o] :=2; Port[o] :=6; Port[o] :=2; Port[o] :=0; Port[o] :=4; Port[o] :=0; Port[o] :=2; Port[o] :=6; Port[o] :=2; Port[o] :=2; {Timer port always single polarity} Port[o] :=6; Port[o] :=2; Port[o] :=2; Port[o] :=6; Port[o] :=2; Port[o] :=6; Port[o] :=2; Port[o] :=0; Port[o] :=4; Port[o] :=0; end; procedure WaitForTimer; begin SetUp4; GetA(a); while a>Tmin do begin SetUp4; GetA(a); end; while aTmin do begin SetUp4; GetA(a); end; while a4095 then a:= a-8194; A1 :=60 - a div (Amp*2); end else A1 := 119- a div Amp; Line (gx-1,LastA1,gx,A1); LastA1 := A1; if ABS(a)< Va then ChA := False else ChA := True; WaitForTimer; SetUp2; GetA(a); if Recorded then SaveSample; SetViewPort(0,140,639,260,Clip); SetColor(1); Line (gx,1,gx,119); SetColor(3); If Polar=2 then begin if a>4095 then a:= a-8194; A2 :=60 - a div (Amp*2); end else A2 := 119-a div Amp; Line (gx-1,LastA2,gx,A2); LastA2 := A2; if ABS(a) < Vb then ChB := False else ChB := True; WaitForTimer; SetUp3; GetA(a); if Recorded then SaveSample; SetViewPort(0,280,639,400,Clip); SetColor(1); Line (gx,1,gx,119); SetColor(3); If Polar=2 then begin if a>4095 then a:= a-8194; A3 :=60 - a div (Amp*2); end else A3 := 119-a div Amp; Line (gx-1,LastA3,gx,A3); LastA3 := A3; if ABS(a)< Vc then ChC := False else ChC := True; gx := gx+1; if gx = 639 then gx :=2; SetViewPort(0,0,639,459,Clip); if (NOT ChA and NOT ChB and NOT ChC and Recorded) then inc(Quiet); if (Quiet>QuietVal) or (dptr > 27990) then Flush; if Recorded then RecordedSamples := RecordedSamples + 1; if NOT Recorded and (ChA or ChB or ChC) then InitRecord; SetColor(0); OutTextXY(300,440,RSamples); Str(RecordedSamples,RSamples); SetColor(4); OutTextXY(300,440,RSamples); end; Procedure GetDefaults; begin Assign(D,'DEFAULTS.TXT'); {read the defaults file} Reset(D); readln(D,RunDirectory); readln(D,DataDirectory); readln(D,i); Str(i,PinS); readln(D,o); Str(o,PoutS); readln(D,Polar); readln(D,Va); Str(Va,VaS); readln(D,Vb); Str(Vb,VbS); readln(D,Vc); Str(Vc,VcS); readln(D,Amp); Str(Amp,AmpS); readln(D,QuietVal); Str(QuietVal,QuietValS); readln(D,Tmax); Str(Tmax,TmaxS); readln(D,Tmin); Str(Tmin,TminS); Close(D); end; Procedure EditDefaults; begin Assign(D, 'Defaults.txt'); Rewrite (D); write('Enter path where program files reside. '); readln(RunDirectory); write('Enter path where data files reside. '); readln(DataDirectory); write('Enter Input Port address. '); readln(i); write('Enter Output Port address. '); readln(o); write('Enter [1] single polarity or [2] bipolar. '); readln(Polar); write('Enter channel a trigger threshold. '); readln(Va); write('Enter channel b trigger threshold. '); readln(Vb); write('Enter channel c trigger threshold. '); readln(Vc); write('Enter screen scaling factor (1-34). '); readln(Amp); write('Enter Quiet value (suggest 10 to 30). '); readln(QuietVal); write('Enter Timer Hi Value. '); readln(Tmax); write('Enter Timer Lo Value. '); readln(Tmin); writeln(D,RunDirectory); writeln(D,DataDirectory); writeln(D,i); writeln(D,o); writeln(D,Polar); writeln(D,Va); writeln(D,Vb); writeln(D,Vc); writeln(D,Amp); writeln(D,QuietVal); writeln(D,TMax); writeln(D,TMin); Close(D); end; var yes: char; {Begining of main loop} begin Clip := True; {stay within graph boundaries} GraphDriver := 9; GraphMode :=VGAHi; {use 640x450 VGA} gx:=2; {set graph x pointer} GetDefaults; ClrScr; writeln(' 3 Channel Data Collection Program'); writeln(' (c) 1997 Radio-Sky Publishing'); writeln(' http://www.win.net/~radiosky'); writeln; writeln(' Default Run Directory : '+RunDirectory); writeln(' Default Data Directory : '+DataDirectory); writeln(' Channel Thresholds: A '+VaS+' B '+VbS+' C '+VcS); writeln(' Input Port '+ PinS+ ' Output Port ' + PoutS); if Polar = 1 then writeln(' Single Polar') else writeln(' Bipolar'); writeln(' Scaling factor (1-34) '+AmpS); writeln(' Quiet Value '+QuietValS); writeln(' Timing Hi Value '+TmaxS); writeln(' Timing Lo Value '+TminS); writeln; writeln(' Change Defaults (Y/N) '); repeat yes := ReadKey; until (yes='Y') or (yes = 'y') or (yes = 'N') or (yes = 'n'); if (yes='Y') or (yes='y') then EditDefaults; RecordedSamples := 0; GetDir( 0, GraphDriverPath); ChDir(DataDirectory); {lets go to data directory to test for file} repeat Found := False; writeln; write (' Enter Data File Name....'); readln(DataFileName); FindFirst(DataFileName,AnyFile,FileInfo); while DosError = 0 do begin if FileInfo.Name = DataFileName then begin with FileInfo do writeln(Name:14, Size:8, 'Already Exisits'); Found := True; end; FindNext(FileInfo); end; until NOT Found; ChDir(RunDirectory); {Get back to the run directory} InitGraph(GraphDriver, GraphMode, GraphDriverPath); DirectVideo := False; {write text to graphics screen} SetColor(7); {label the graphs} SetTextStyle(2,0,6); OutTextXY(10,120,'Channel 1'); OutTextXY(10,260,'Channel 2'); OutTextXY(10,400,'Channel 3'); OutTextXY(430,420,'Any Key Exits'); SetColor(3); SetViewPort(0,140,639,260,Clip); {make the boxes for the graphs} Rectangle(0,0,639,120); SetViewPort(0,280,639,400,Clip); Rectangle(0,0,639,120); SetViewPort(0,0,639,120,Clip); Rectangle(0,0,639,120); Assign (DataFile,DataDirectory+'\'+DataFileName); ReWrite(DataFile,2); {BlockWrite(DataFile,Polar,2,Result);} Close(DataFile); DataBuffer[1] := Polar; Recorded := False; dptr:= 2; repeat Graph3; until KeyPressed; if dptr>1 then Flush; end.