Solved

Millisecond timing without assembly

Posted on 1998-01-29
3
623 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
Comment Utility
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
Comment Utility
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
Comment Utility
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

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

This tutorial is posted by Aaron Wojnowski, administrator at SDKExpert.net.  To view more iPhone tutorials, visit www.sdkexpert.net. This is a very simple tutorial on finding the user's current location easily. In this tutorial, you will learn ho…
Windows programmers of the C/C++ variety, how many of you realise that since Window 9x Microsoft has been lying to you about what constitutes Unicode (http://en.wikipedia.org/wiki/Unicode)? They will have you believe that Unicode requires you to use…
The goal of this video is to provide viewers with basic examples to understand recursion in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use conditional statements in the C programming language.

743 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

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now