Category : Files from Magazines
Archive   : ISSUE-34.ZIP
Filename : SCOPE.FIG

 
Output of file : SCOPE.FIG contained in archive : ISSUE-34.ZIP


(( This is Real World Figure 5 -- Oscilliscope Test Program ))

program test; {oscilliscope tester for Kaypro 2X. By Bruce Eckel 8/86}

const
A_CONTROL: byte = $22; {Control and Data I/O locations}
A_DATA: byte = $20; {for each of the Z80 PIO ports}
B_CONTROL: byte = $23;
B_DATA: byte = $21;

MODE : byte = $4f; {0100 1111 mode 1 = input}
INT : byte = $07; {0000 0111 interrupts disabled}
var
temp,val : byte;

function noise_test : boolean; {this keeps the screen from
flickering because of the noise in the bottom bit of the A/D
converter}
begin
if ( { part of what this function does is }
(temp <> val) { stall the program while the A/D }
and { converter catches up }
(temp <> (val+1)))
then noise_test := true else noise_test := false;
end;
begin
port[A_CONTROL]:= MODE; {initialize port A of the pio}
port[A_CONTROL]:= INT; { port B is done the same way }

ClrScr; write(#27,'C4'); { Turn kaypro cursor off }

{ Turbo's "port array" is used to write to the PIO. The first
one starts the A/D converter. Note that most of the programming
effort is just to make the screen output nice. The following
line is really all there is to running the A/D converter. }

val := port[A_DATA];

repeat begin
temp := port[A_DATA];
if noise_test then begin
val := temp;
GotoXY(30,10); clreol; write('binary ',val, ' ');
{ Note I take the value, divide it by the number of
steps, and multiply by the voltage range (my power
supply doesn't quite make it to 5.0). The ":4:3"
is formatting information for Turbo. Check the
results with your multimeter. }
write(((val/255) * 4.99 ):4:3, ' volts');
end;
end
until keypressed;
write(#27,'B4'); { Turn cursor back on }
end.


((*************************************************************))

(( This is Real World Figure 6 -- Oscilliscope Program -- A/D ))


program scope; { oscilliscope program for A/D example. By Bruce Eckel 8/86 }
type
direction = (FALLING, RISING); { trigger on rising or falling edge }
binary = (ON,OFF); { whether to turn a pixel on or off }
pixel_control = string[2]; { how to turn pixel on or off }
screen_buffer = array[0..159] of integer; { Kaypro screen is 160
pixels wide }
const
A_CONTROL: byte = $22; {Control and Data I/O locations}
A_DATA: byte = $20; {for the Z80 PIO port A }
MODE : byte = $4f; {0100 1111 mode 1 = input}
INT : byte = $07; {0000 0111 ints disabled}
min_capture_band : integer = 3; {minimum triggering search window}
var
CH : char; trigger_edge : direction;
low_capture_bound, high_capture_bound : integer;
sample_rate, pause_rate : integer;
point_buffer, pixel_buffer, old_pixel : screen_buffer;
loopcntr, dly, dlycntr : integer;
cursor_off, cursor_on : string[3];
pixel_off, pixel_on : pixel_control;
dim, bright, reverse_video, normal_video : string[3];
revdim,normal: string[6];

procedure terminal_customization; { should make it a little easier to}
begin { customize for other computers. }
cursor_off := #27 + 'C4';
cursor_on := #27 + 'B4';
pixel_off := #27 + ' ';
pixel_on := #27 + '*';
dim := #27 + 'B1'; { If you don't have these features, just }
bright := #27 + 'C1'; { set the strings to ''. }
reverse_video := #27 + 'B0';
normal_video := #27 + 'C0';
revdim := reverse_video + dim;
normal := normal_video + bright;
end;

procedure pixel(on_or_off:binary; vertical_coord, horizontal_coord : integer);
const
vertical_offset : integer = 131; { the kaypro's screen doesn't start
at 0,0}
horizontal_offset : integer =32; { these offsets start it in lower
left corner}
var pixel_char : pixel_control;
begin
if (on_or_off = ON) then pixel_char := pixel_on else
pixel_char := pixel_off ;
write(pixel_char, chr(vertical_offset - vertical_coord),
chr(horizontal_offset + horizontal_coord));
end;

procedure refresh_screen(var new_screen, old_screen : screen_buffer);
{ displays contents of point_buffer while erasing old trace on screen. }
var pixel_counter : integer;
begin
for pixel_counter := 0 to 159 do begin {Kaypro screen width again...}
pixel(OFF, old_screen[pixel_counter], pixel_counter);
pixel(ON, new_screen[pixel_counter], pixel_counter);
old_screen[pixel_counter] := new_screen[pixel_counter];
end;
end;

procedure ADC_delay (multiplier:integer); { Tried using assembly language
here, but the overhead of the INLINE statement overwhelmed my timing loop.
Adjust this until you get something from your A/D converter. }
var i,j: integer;
begin for i := 1 to multiplier do begin j :=0; j:= 1; j:=2; end; end;

procedure trigger(edge: direction; low_bound, high_bound : integer);
var presentval,lastval : integer; slope, edge_not : direction;
begin
edge_not := direction(ord(edge) xor 1); { invert edge }
slope := edge_not;
presentval := port[A_DATA];
while (slope = edge_not) do begin { wait for the right direction }
while (not ((presentval > low_bound) { ... and range of values }
and (presentval < high_bound))) do begin
ADC_delay(1);
presentval := port[A_DATA];
end;
lastval := presentval;
ADC_delay(1); presentval := port [A_DATA];
if (((edge = RISING) and ( presentval > lastval)) or
((edge = FALLING) and ( presentval < lastval)))
then slope := edge;
end;
delay(dly); { trigger delay in milliseconds }
end;

procedure get_samples(rate :integer);
{ tried passing the point_buffer array by variable, but it slowed things
down enough to make the data look bad }
var counter : integer;
begin
for counter := 0 to 159 do begin
point_buffer[counter] := port[A_DATA]; { point_buffer is global }
ADC_delay(rate);
end;
end;

procedure process_samples(var input_point, output_point : screen_buffer);
{ put samples in a form which can be displayed }
var index : integer;
begin
for index :=0 to 159 do {steps in A/D conv \/}
output_point[index] := (trunc ((input_point[index]/255)*99));
end; {vertical steps on screen /\}

procedure menu; { too many variables to bother passing -- all changed globally}
var i : integer;
begin
clrscr; gotoxy(1,3);
writeln(' ',revdim,'Digital Oscilliscope Options Menu:',normal);
writeln;
writeln(' t : change trigger delay. Current delay = ',
revdim,dly,normal,' mS');writeln;
write(' e : rising or falling trigger edge : ',revdim);
if trigger_edge = rising then writeln('RISING',normal)
else writeln('FALLING',normal); writeln;
writeln(' o : change trigger offset : ',revdim,low_capture_bound,normal);
writeln;
writeln(' c : change trigger capture band : ',revdim,
high_capture_bound - low_capture_bound, normal);
writeln;
writeln(' s : change sample rate. Current rate = ',
revdim,sample_rate,normal);writeln;
writeln(' p : change pause rate : ',revdim,pause_rate,normal);
writeln;
writeln(' : quit');writeln;
writeln(' any other key returns to sampling');
while(not keypressed) do; read(kbd,ch);
if (CH in (['A'..'Z'] + ['a'..'z'] )) then begin
gotoxy(18,1);
case CH of
't','T': begin write('New trigger value : '); readln(dly); end;
'e','E': begin write('New trigger edge(0 for falling,1 for rising) : ');
readln(i);
trigger_edge := direction(i); end;
'o','O': begin write('New offset : '); readln(low_capture_bound);
if (high_capture_bound - low_capture_bound < min_capture_band)
then high_capture_bound := low_capture_bound + min_capture_band;
end;
'c','C': begin write('New capture band : '); readln(i);
if (i < min_capture_band) then
high_capture_bound := low_capture_bound + min_capture_band
else high_capture_bound := low_capture_bound + i;
end;
's','S': begin write('New sample rate : '); readln(sample_rate); end;
'p','P': begin write('New pause rate : '); readln(pause_rate); end;
end;
CH := ' ';
end;
clrscr;
end;

procedure pause_for_input; { user can change parameters via menu here }
begin
gotoxy(1,1);write(reverse_video,dim,'PAUSE',normal_video,bright);
for dlycntr := 1 to 20000 do if (keypressed) then read(KBD,CH);
if (CH <> #27) and (CH <> ' ') then menu;
gotoxy(1,1); write (' ');
end;

{******************** main ***********************}
begin
port[A_CONTROL]:= MODE; {initialize the pio}
port[A_CONTROL]:= INT;

terminal_customization;
write(cursor_off);
dly := 18; low_capture_bound := 2; high_capture_bound := 5;
sample_rate := 1; pause_rate := 5; trigger_edge := RISING;
clrscr; CH:=' ';
while(CH <> #27) do begin
for loopcntr := 1 to pause_rate do begin
trigger(trigger_edge, low_capture_bound, high_capture_bound);
get_samples(sample_rate); { point_buffer changed as a global here }
process_samples(point_buffer,pixel_buffer);
refresh_screen(pixel_buffer, old_pixel);
end;
pause_for_input;
end;

write(cursor_on);
end.