Solved

Millisecond timing without assembly

Posted on 1998-01-29
3
626 Views
Last Modified: 2008-02-01
Hi

I am interested in having millisecond timing for
psychology experiments.  The timer...() routines below
were given to me, but dont seem to work properly on
my pentium (200 Mhz).  You will see i have been trying to
test them by timing the vertical refresh, just giving
output every second, or most recently just printing out
timer0count().  Things are generally ok for a little while
but then crazy numbers appear.  (I am making a DOS program
in Borland 5, and then running in a DOS window, or in
DOS mode)

timer0Init() seems to be the critical routine.  I am
hoping one of you can see something obviously wrong with
it, or suggest an alternative source of code.

Thanks

Mark Chappell

#include <time.h>
#include <process.h>
#include <dos.h>

#include <stdio.h>

/*VARIABLES USED TO MEASURE TIME*/

/* control register addr of 8253 timer counter chip */
#define CTRL_REG 0x0043
/* word to initialise channel 0 */
#define CTRL_INIT_WORD 0x0036
/* addr of channel 0 */
#define CH2 0x0040
/* number of system clock ticks in a timer tick */

#define CLOCK_DIVISOR 1193
/* #define CLOCK_DIVISOR 1193
       1.193 MHz divided by 1193 gives a timer tick every 1 ms */

/* BIOS interrupt number for tick generated by 8253 channel 0 */
#define TICK_INT_NR 0x1C

/* Below taken from setvect Example.  MC 25/11/97 */
#ifdef __cplusplus
    #define __CPPARGS ...
#else
    #define __CPPARGS
#endif

static int initialised = 0;  /* false */
/* static int ch = 0, notstalled = 1 */;
static unsigned long tickCnt = 0 /* , timecount = 0 */ ;
static void interrupt (*origTickHandler)(__CPPARGS); /* arg was empty MC */
static void interrupt newTickHandler(__CPPARGS); /* arg was void MC */


void timer0Init(void), timer0Dispose(void), timer0Reset(void);
unsigned long timer0TickCount(void);

main()
{
unsigned char ch;
int i, ok, c;
long arr[1000];

timer0Init();

for(i = 0; i < 100; i++)
      {
    printf("%u ", timer0TickCount());
/*   while(timer0TickCount() < (i + 1) * 1000)
         {
      if(timer0TickCount() > 30000)
            printf("%d ", timer0TickCount());
         }
   printf("\n%d ", i + 1);      */
   }

for(i = 0; i < 0; i++)
      {
   ok = 0;  ch = 1;
   while(ch != 0)
         {
      ch = inportb(0x3DA)&8;
/*      ok++;
      printf("h1 %X ", ch);
      if(ok > 1000)
            exit(0);              */
      }
  /*    printf("\n");                */

       while(ch == 0)
         {
            ch = inportb(0x3DA)&8;
/*       ok++;
     printf("h2 %X ", ch);
      if(ok > 1000)
            exit(0);            */
      }
/*   printf("\n");                   */

arr[i] = timer0TickCount();

   printf("%u ", timer0TickCount());
   }

timer0Dispose();

for(i = 0; i < 100; i++)
      printf("%ld ", arr[i]);
}

void timer0Init(void)
{
      if (!initialised)
      {
            initialised = 1;  /* true */
            /* install new ISR for bios tick interrupt, and save
current one */
            origTickHandler = getvect(TICK_INT_NR);
            disable();
            setvect(TICK_INT_NR, newTickHandler);
            enable();
            /* set channel 0 count period */
            outport(CTRL_REG, CTRL_INIT_WORD);
             outportb(CH2, CLOCK_DIVISOR & 0x00FF); /*  LSB     */
            outportb(CH2, CLOCK_DIVISOR >> 8);  /* MSB */
   /*   outportb(CH2, CLOCK_DIVISOR);      */
        /* init tick count */
      tickCnt = 0;
      }
}

void timer0Dispose(void)
{
      if (initialised)
      {
            initialised = 0;  /* false */
            /* restore channel 0 count period to 18.203 Hz */
            outport(CTRL_REG, CTRL_INIT_WORD);
            outportb(CH2, 0);
            outportb(CH2, 0);
            /* reinstall original ISR for bios tick */
            disable();
            setvect(TICK_INT_NR, origTickHandler);
            enable();
      }
}

/* the new interrupt handler for the BIOS tick interrupt */
static void interrupt newTickHandler(__CPPARGS)
{
  tickCnt++;
}

void timer0Reset(void)
{
      tickCnt = 0;
}

unsigned long timer0TickCount(void)
{
      return (tickCnt);
}
0
Comment
Question by:markc2
3 Comments
 

Expert Comment

by:rjh107
ID: 1257119
I have a similar piece of code which essently times the vertical retrace which I wrote a while back. Just having a quick look at it, I have at the very end of my interrupt handler the following
    outp(0x20,0x20);                  
This was with BC3.11 and I'm not sure if you'll need it with BC5. Also BC3.11 docs say don't compile with 'Test stack overflow' on, I don't know if you are doing this or it is required with BC5.

Just a few thoughts.

0
 
LVL 15

Accepted Solution

by:
Tommy Hui earned 100 total points
ID: 1257120
If this is running on a Pentium, you can use its time counter, using the rdtsc instruction. There's code to do this with Visual C++, you search for pentium counter on the web. There may be code to do this with Borland C++. The counter is maintained by the hardware, so it is very accurate. You might want to search the web for the Zen Timer by Michael Abrash.
0
 

Author Comment

by:markc2
ID: 1257121
Thanks, i found ztimer22.zip, after a bit.  I am wondering
if there is a more recent version (it seems to be early
to mid 96); i cant seem to find it.  With this i seem
to be getting sensible timing.
0

Featured Post

Free learning courses: Active Directory Deep Dive

Get a firm grasp on your IT environment when you learn Active Directory best practices with Veeam! Watch all, or choose any amount, of this three-part webinar series to improve your skills. From the basics to virtualization and backup, we got you covered.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Have you thought about creating an iPhone application (app), but didn't even know where to get started? Here's how: ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Important pre-programming comments: I’ve never tri…
This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so…
The goal of this video is to provide viewers with basic examples to understand opening and writing to files in the C programming language.
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use for-loops in the C programming language.

828 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question