PRECISE TIMING ON IBM PC/AT COMPATIBLE
Bob Stout
Bob.Stout at p6.f506.n106.z1.fidonet.org
Mon Jul 24 17:58:09 AEST 1989
In an article of <20 Jul 89 21:39:07 GMT>, (Leonard J. Trejo) writes:
>Say, we're trying to measure human reaction times (<1ms) by timing the
>interval between a video field and a keypress (on the keyboard) on
>our PC-compatible (Compaq 386/25) using the C subroutine call
>"ftime()", which purports to provide millisecond accuracy (MSC 5.1).
Most PC C compilers use the basic system clock interrupt interval (18.2 Hz
or 55 msec.) for their minimum timing resolution. Following is a public domain
source for achieving 1 usec. timing accuracy in a PC or close compatible. I've
used it on Compaqs before and it should work just fine for your application.
Note that this code has a few rough spots. I adapted it for use in a
commercial library which is considerably cleaner. This should get you going,
but if you want more info on the library (it's currently only available for TC
and ZTC although MSC should be out in the next few months), let me know...
--------------------------------- Cut here ---------------------------------
/* clock.c -- Microsecond resolution clock routine. */
/* */
/* Written by David L. Fox. */
/* Implements in C the timer chip tweaking described by */
/* Byron Sheppard, _Byte_, Jan 1987, p 157-164. */
/* Replaces standard clock() from the library. */
/* The definition of CLK_TCK in time.h may have to */
/* be changed to 1000000L. */
/* Does not correctly handle intervals spanning */
/* midnight or intervals greater than about 6 hrs. */
#include <time.h>
/* Interrupt handling and i/o ports are compiler dependent. */
/* The following set of preprocessor directives selects the */
/* correct include files and macros for various compilers. */
#ifdef __ZTC__
#include <dos.h>
#include <int.h>
#define inportb inp
#define outportb outp
#else
#ifdef __TURBOC__
#include <dos.h>
#define int_off disable
#define int_on enable
#else
#error Unknown compiler
#endif
#endif
/* Constants */
#define CONTVAL 0x34 /* == 00110100 Control byte for 8253 timer. */
/* Sets timer 0 to 2-byte read/write, mode 2, binary. */
#define T0DATA 0x40 /* Timer 0 data port address. */
#define TMODE 0x43 /* Timer mode port address. */
#define BIOS_DS 0x40 /* BIOS data segment. */
#define B_TIKP 0x6c /* Address of BIOS (18.2/s) tick count. */
#define SCALE 10000 /* Scale factor for timer ticks. */
/* The following values assume 18.2 BIOS ticks per second resulting from
the 8253 being clocked at 1.19 MHz. */
#define us_BTIK 54925 /* Micro sec per BIOS clock tick. */
#define f_BTIK 4595 /* Fractional part of micro sec per BIOS tick.*/
#define us_TTIK 8381 /* Micro sec per timer tick * SCALE. (4/4.77 MHz) */
clock_t
clock(void) {
unsigned char msb, lsb;
unsigned int tim_ticks;
static int init = 0;
unsigned long count, us_tmp;
static unsigned long init_count;
if (0 == init) {
init = 1; /* This is the first call, have to set up timer. */
int_off();
outportb(TMODE, CONTVAL); /* Write new control byte to timer. */
outportb(T0DATA, 0); /* Initial count = 0 = 65636. */
outportb(T0DATA, 0);
init_count = *(unsigned long int far *)MK_FP(BIOS_DS, B_TIKP);
int_on();
return 0; /* First call returns zero. */
}
int_off(); /* Don't want an interrupt while getting time. */
outportb(TMODE, 0); /* Latch count. */
lsb = inportb(T0DATA); /* Read count. */
msb = inportb(T0DATA);
/* Get BIOS tick count (read BIOS ram directly for speed and
to avoid turning on interrupts). */
count = *(unsigned long far *)MK_FP(BIOS_DS, B_TIKP) - init_count;
int_on(); /* Interrupts back on. */
tim_ticks = (unsigned)-1 - ((msb << 8) | lsb);
us_tmp = count*us_BTIK;
return us_tmp + ((long)tim_ticks*us_TTIK + us_tmp%SCALE)/SCALE;
}
More information about the Comp.lang.c
mailing list