[comp.lang.pascal] millisecond timer

woody@eos.UUCP (Wayne Wood) (02/09/90)

okay, i've heard the msdos gurus out there tell me 1000 ways not to do this...
can anybody tell me **HOW** to do it?

i need to be able to take millisecond measurements for a "real-time" project...
i'll take C, Assembler, or <shudder> Pascal.  just explain what i have to
do where to make the damn thing work without screwing up my disk drives or
memory refresh.

currently i'm using the screen retrace, but it don't cut it.

/***   woody   ****************************************************************
*** ...tongue tied and twisted, just an earth bound misfit, I...            ***
*** -- David Gilmour, Pink Floyd                                            ***
****** woody@eos.arc.nasa.gov *** my opinions, like my mind, are my own ******/

woody@eos.UUCP (Wayne Wood) (02/09/90)

okay, i've heard the msdos gurus out there tell me 1000 ways not to do this...
can anybody tell me **HOW** to do it?

i need to be able to take millisecond measurements for a "real-time" project...
i'll take C, Assembler, or Pascal.  just explain what i have to
do where to make the damn thing work without screwing up my disk drives or
memory refresh.

currently i'm using the screen retrace, but it don't cut it.

/***   woody   ****************************************************************
*** ...tongue tied and twisted, just an earth bound misfit, I...            ***
*** -- David Gilmour, Pink Floyd                                            ***
****** woody@eos.arc.nasa.gov *** my opinions, like my mind, are my own ******/

KRW1%LEHIGH.BITNET@IBM1.CC.Lehigh.EDU (02/10/90)

Okay - here's a simple-minded Turbo Pascal unit that uses the speaker
timer to return a reference time in units of 10 microseconds.  Works as
long as you don't need the speaker.  Accuracy is on the order of 30 to
300 microseconds, depending on your system.  Use inittimer to begin
counting, and function timervalue to get current reading.  Be careful of
the 32-bit counter overflowing for long time periods.
-------------------------------------------------------------------

unit timer;

INTERFACE

type
  userproc = procedure;

var
  timeractive, hirestimer: boolean;
  procpointer: userproc;

function systime: longint;
function timervalue: longint;
procedure inittimer;
procedure resettimer;
procedure suspendtimer;
procedure defproc(proc: userproc);


IMPLEMENTATION

uses dos, crt;

var
  oldtimer, exitsave: pointer;
  exacttime, restart, starttime: longint;
  lowbyte, highbyte, ref: word;

{$f+}
procedure dummy;
  begin
  end;
{$f-}

procedure defproc(proc: userproc);

  { Define optional user procedure to call at clock interrupt }

  begin
    procpointer := proc;
  end;

function systime: longint;

  { Return system time in milliseconds }

  var
    h, m, s, hs: word;

  begin
    gettime(h,m,s,hs);
    systime := (((longint(h)*60+m)*60+s)*100+hs)*10;
  end;

procedure clock; interrupt;

  {Update 10-microsecond timer}

  const
    incr = 5493;                       {Timer increment per interrupt}

  begin
    inline($fa);                       {Disable interrupts}
    port[$43] := $80;                  {Latch timer 2}
    lowbyte := port[$42];
    highbyte := port[$42];
    ref := (highbyte shl 8) + lowbyte; {Base for subsequent readings
                                          within current clock interval}
    exacttime := exacttime + incr;     {New 10-mic timer value}
    inline($fb);                       {Enable interrupts}

(* ---- disabled
    procpointer;                       {Execute user procedure}
*)
  end;

function timervalue: longint;

  {Get value of 10-microsecond timer}

  var
    dif, low, high: word;
    t: longint;

  begin
    if hirestimer then
      begin
        inline($fa);
        port[$43] := $80;
        low := port[$42];
        high := port[$42];
        dif := ref - ((high shl 8) + low);
        timervalue := exacttime + (longint(dif)*100 div 1193);
        inline($fb);
      end
    else
      begin
        t := systime;
        if t < starttime then t := t + 8640000;
        timervalue := (t - starttime) * 100;
      end;
  end;

procedure resettimer;

  begin
    if timeractive and hirestimer then
      begin
        setintvec($1c, oldtimer);
        timeractive := false;
      end;
  end;

procedure inittimer;

  begin
    if not timeractive then
      begin
        exacttime := restart;
        if hirestimer then
          begin
            getintvec($1c, oldtimer);
            setintvec($1c, @clock);
            {Start high-precision timer}
            port[$43] := $b2;   {Mode 1 - countdown
                                 (approx .84 microsecond ticks)}
            port[$42] := $ff;   {Initialize timer value}
            port[$42] := $ff;
            timeractive := true;
            delay(25);                     {Allow for first tick}
            if timervalue = timervalue then
              begin                        {Not incrementing - use low res}
                resettimer;
                hirestimer := false;
              end;
          end;
      end;
  end;

procedure suspendtimer;

  begin
    restart := exacttime - 2500;
    resettimer;
    timeractive := false;
  end;

procedure cleartimer;

  begin
    suspendtimer;
    starttime := systime;
    restart := 0;
    inittimer;
  end;

{$f+}
procedure timerexit;

  {Exit procedure}

  begin
    exitproc := exitsave;
    resettimer;
  end;
{$f-}

begin
  timeractive := false;
  hirestimer := true;
  restart := 0;
  starttime := systime;
  exitsave := exitproc;              {Save exit address}
  exitproc := @timerexit;
  procpointer := dummy;
end.