• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 33176
  • Last Modified:

how insert a delay in microseconds in C under VC++

Hi experts,

I'm lookiing for a function that allow me to insert delays in Microseconds. I tried Sleep but it's not possible. i didn't test yet the clock() function to do that.
thanks in advance
Said
0
saido
Asked:
saido
  • 9
  • 6
  • 5
  • +3
1 Solution
 
n_fortynineCommented:
sleep() does do this in milliseconds does it?
(for UNIX) #include <unistd.h>)
for Visual and MFC stuff I know of the default
::sleep() function that does the same trick.
0
 
n_fortynineCommented:
::Sleep() my bad
0
 
nietodCommented:
What sort of accuracy do you need?   Remeber that windows is a pre-emptive multitasking OS.  Accuracy can be very ellusive as you are sharing CPU time with dozens of other processes.   What exactly are you doing that you might want this?
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
SalteCommented:
Yes, I believe ::Sleep() sleep in milliseconds.

You can also use select():

struct tv time;
time.tv_sec = num_seconds_to_sleep;
time.tv_usec = num_microseconds_to_sleep;

select(NULL,NULL,NULL,& time);

This will sleep for time.tv_sec seconds and time.tv_usec microseconds.

Setting tv_sec to 0 and tv_usec to 1000 will wait for one millisecond. setting tv_usec to 500 will wait for 500 microseconds or half a millisecond. Not sure if that is meaningful to do though, sleep(x) only guarantees that you will not wake up BEFORE x time units has passed, you may wait longer than that and if you specify a very short time interval, for example 1 microsecond you will probably in reality wait much longer than you specify.

Alf
0
 
saidoAuthor Commented:
what i'm doing is that i'm develloping  bus protocols working on different timing (100khz, 200khz,1Mhz...), so when generating clock to write or read i need some delays to enable the data to be stable on the line.
Sleep doesn't work.
i will test select(), but what is the g=header file to include for this.
Said
0
 
SalteCommented:
depends on your system. If you're on a windows system you can get it from

#include <windows.h>

or

#include <winsock2.h>

or some such.

Write select() in the edit window and then press F1 and see what comes up.

Alf
0
 
SalteCommented:
If you're on a unix or linux system you can do:

man select

and get the name of the #include file to use.

Alf
0
 
nietodCommented:
>> what i'm doing is that i'm develloping  bus protocols working on
>> different timing (100khz, 200khz,1Mhz...),
Usually this sort of work has to be done via interrupt mechanisms.  Your program can easily be suspended for intervals that last 1/20th of a  second, and possibly much more.  that is 50 millisecond.  That means that no matter what you do, accuracy of better than 50 milliseconds is almost certainly impossible, accuracy of 100 millisconds is probably unlikely.   You can't reliably use these sorts of techniques for preccise timing in a preemptive multi-tasking OS.  This sort of thing is typically done by writting device drivers that are then invoked by interrypts as soon as some critical condition occurs, like if the bus goes quiet.   You almost certainly have to completely rethink your approach.
0
 
d_iegoCommented:
does any of you know how to delay or pause system in a win api aplication?
0
 
nietodCommented:
>> does any of you know how to delay or pause system in a win api aplication?
Accurately?  No.  you can't
0
 
saidoAuthor Commented:
what i'm doing is that i'm develloping  bus protocols working on different timing (100khz, 200khz,1Mhz...), so when generating clock to write or read i need some delays to enable the data to be stable on the line.
Sleep doesn't work.
i will test select(), but what is the g=header file to include for this.
Said
0
 
saidoAuthor Commented:
sorry for the previous message, it's duplicated.

About select(), I include windows.h, but still doesn't know  select as function for delay, nor the structure tv.
can you give me a complete example?
0
 
SalteCommented:
Unfortunatley I am sitting on a Unix machine right now and I don't have Visual C++ installed on my windows machine at home - I use CYGWIN and gcc at home for my windows programming :-)

However, I am very sure that if you just type select() in your source code somewhere, place the cursor on that word (select) and then press the F1 key you should get some info and if you follow the hyperlinks there it will tell you which include file to use etc.

Alf
0
 
SalteCommented:
btw,

I agree with nietod that you most likely have to completely rethink your approach.

If you're working on some bus thing which has to be very accurate you most likely have to use specific hardware to test that bus. Such hardware can then send interrupts to the PC etc and you have to use a driver which can hook itself unto those interrupts and respond to them.

Trying to run as a regular application will most likely not lead anywhere. Even a sleep on microseconds level as select() will only guarantee that you won't wake up BEFORE the specified time. It might take a very long time after and if you have a very short time specified (such as a couple of microseconds) you will most likely have an actual sleep time of several 100 times the time you specified. That is way too inaccurate to be reliable in any way. The thing is there's nothing you can do about that. As long as you run as application, your application can be stopped and set to wait in a multi tasking system.

In this way it is probably better if you just reboot the machine in MS-DOS 6.22 and take over some interrupts and handle it from there. Running MS-DOS 6.22 gives you full control over the CPU and you can do what you want. Of course, you don't get multi-tasking but that is exactly what you don't want in your case so that should be fine.

If you let the PC run MS-DOS you can just do RDTSC to read the timer and loop until the time has elapsed. The RDTSC timer ticks once every 100th nanosecond and is available on pentiums. If you use Borland C++ 3.1 or some such compiler you can do code like this:

struct sysclock_t {
   int LL, LH, HL, HH;
};

void sleep(long ns)
{
   // make the sleep in 100th nanoseconds.
   ns = (ns + 99)/100;
   ns -= FACTOR;

   __asm {
      rdtsc
      // clock in EDX:EAX
      // we ignore EDX since we asume ns is
      // of shorter duration than that.
      add eax,dword ptr ns
      mov ebx,eax // save eax into ebx.
      jnc loop2

      // new time is after wrapping around
loop1:
      rdtsc
      // again we ignore EDX
      // wait for time to wrap around.
      cmp eax,ebx
      jae loop1

// Time has wrapped around and present time < wait time.
loop2:
      rdtsc
      // again we ignore EDX
      cmp eax,ebx
      jb loop2
    }
}

Several notes here:

First, It is quite possible that an old Borland C++ compiler or old version of MSVC won't understand 'rdtsc'. However, these compilers have ways that you can specify ways to emit specific codes as instructions and rdtsc is a simple 2 byte instruction if I rmeember correctly. It has no operands so it should be easy enough. Just look it up in Intel's instruction set for pentium.

Second, The result is a 64 bit counter counting time since midnight January 1st 1601 or something like that. We are not interested in long durations here so I ignore the upper 32 bits and only uses the lower 32 bits.

Third, I also subtract a FACTOR. This FACTOR is a value you must find by running your sleep function. It is suppoed to subtract for the time you take doing the rdtsc and adding the value etc. These things also take time and exactly how much time I don't know. However, if you run sleep on 1 microsecond a million times that should take approx 1 second and tuning FACTOR so that it takes more or less exactly one second is a way to get the value that. The more times you do a wait the more accurate you can tune FACTOR.

Fourth, the function gets a long argument giving count in nanoseconds. This is way too accurate and the function already at beginning turns it into a count of 100th nanoseconds, it is quite possible that even that is too accurate and so you might want to consider using microseconds as your unit yourself or even higher.

Changing it to microseconds is easy:

void sleep(long ms)
{
   ms *= 10;
   // ms is now in 100th of nanoseconds and can be added
   // to clock value.
   ....proceed as before...
}

Although it is possible that the compiler doesn't know about rdtsc it does know about 32 bit programming (32 bit mode has been available since 386) so the mov ebx,eax and cmp instructions should be good as is, they work fine even in 16 bit code. The compiler will insert codes to tell the cpu that "here comes a 32 bit instruction" so that they are executed correctly.

Since I ignore the upper 32 bits I ignore the EDX register completely and just compares the EAX(the lower 32 bits).

This gives you two possibilities. if 'now' is the value at present time and 'end' is the value at the time after the wait, you have two situations:

now < end - no wrap around.
now > end - we wrap around.

At wrap around we first have to wait until 'now' wraps around so that now < end is established, the first loop loop1 does that wait. If we have the situation with no wrap around already we skip that loop and go directly to loop2.

When now < end we enter loop2 and wait until now has reached end and when now >= end we're done looping.

This code will only run properly on a non-multi-tasking system. Trying code like this on Win32 will NOT give the desired result. Reboot old MS-DOS 6.22 and run your program there.

Alf
0
 
nietodCommented:
>> In this way it is probably better if you just reboot the machine in
>> MS-DOS 6.22 and take over some interrupts and handle it from there
That would certainly work, if this is just some sort of timing test, not some sort of "real" program to be run under windows.  However, the problem with this is that you can't (realistically) run a VC program under DOS.  You will have to find an older compiler, probably a C compiler to do this.  If you can find a copy of VC 1.5x, that will still create a program that can run under DOS.
0
 
SalteCommented:
I would think that MSVC 4.0 can compile 16 bit programs that can run under MS-DOS 6.22 - as can Borland C++ 3.1 do or perhaps even Borland C++ builder 2.0 or some such.

But you can forget about VC 6.0 or Borland C++ builder 5.0 etc. I don't think they can handle 16 bit code.

Alf
0
 
nietodCommented:
>> I would think that MSVC 4.0 can compile 16 bit programs that can run under MS-DOS 6.22
I am 99.9% sure it can't.  AFAIK VC 1.52 is the last one to produce 16 bit code, which is why it is still used by driver developers.  
0
 
SalteCommented:
Ok, probably just my memory slipping...when you mention it, I believe it was 1.52 I used at that time for the MS-DOS version of the program. we kept a program at both windows and MS-DOS version and I used MSVC 4.0 at the time but when you mention it, I guess we used 1.52 to compile the Win3.1 version of the program.

Back in those days we also had the Win32s system which was a Win32 like system for MS-DOS and Win3.1 and I believe 1.52 also had support for that.

Alf
0
 
saidoAuthor Commented:
As my application must be windows95/98/NT/2000/XP compatible, do you think using interrupts will be a solution ( just a note i use i2c Bus, SPI bus ...)

i'm working on Windows 2000.

Said
0
 
SalteCommented:
Saido,

Why must your application be WinNT/Win2000/XP compatible? Are you aware that you are asking for the impossible?

WinNT/2000/XP are multi tasking systems. To some extent Win95/98/ME are as well.

You simply CANNOT wait for very short delays on those systems, it just isn't possible. Yes, you can use select and specify a very short delay such as 2 Microseconds. The only thing you know for certain si that you will sleep AT LEAST 2 microseconds. Most likely you will sleep at least 50 milliseconds which is 25000 times more than what you asked for and that is an error factor which simply aren't acceptible to the things you want to do. If your boss tells you to make this kind of application tell him you need a dedicated machine that can run MS-DOS or some similar non-multi tasking system and the program must run on that machine. That machine can be hooked on a network and communicate with another application running on a Win2K/XP system which can display the graph or whatever in a regular windows Win32 fashion, just the way a moronic boss wants it. However, the statistics must be collected on a machine that does NOT run any multi tasking system, is dedicated to the task and where you have complete control over everything.

It's that simple.

Of course, there IS another way - there always is. Here is how:

Design and make a specific hardware card that have some smart cpu that can do the statistics collection. Then put this card on the PCI bus of the computer and install a WDM driver that communicates with the card. This WDM driver must of course be written by you :-)

Now, your application can run under Win32 in WinNT/2000/XP and can use DeviceIoControl to talk with the driver which collects the statistics from your hardware card.

The card must of course also have connection to the bus you want to collect statistics about, if that happen to be the PCI bus then you're already there, if not you have to really do something smart on that card to hook it up to the bus you want to collect statistics about - for example the bus to the AGP port will probably best be done by making a card that connects on the AGP port and itself provide an AGP port which you can hook the graphics card to. Similar settings for other busses.

I think the dedicated CPU running MS-DOS is WAY simpler, cheaper and easier to both program maintain and expand.

Alf
0
 
nietodCommented:
>> As my application must be windows95/98/NT/2000/XP compatible,
>> do you think using interrupts will be a solution
Probably not.

>> You simply CANNOT wait for very short delays
>> on those systems, it just isn't possible
To be more specific, you canot wait for short delays with an accuracy.  Your program is probalby executing less than 10% of the time.  Most of the time other programs are executing   That means that every few milliseconds  your program stops excuting and then does not resume executing for a while.  This is going on all the time.  This has nothing to do with sleeping, it happens to all programs no matter what they do.   So there is no way you can accurately wait for say 10 milliseconds, if your program is typcally suspended for 90 milliseconds out of every 100.  Your 10 millisecond wait might right out, then your program might be suspended for another 80 millisconds before it continues.

This sort of work must be done by device drivers and VXDs that can be invoked at interrupt time.  

>> Design and make a specific hardware card that have some smart
>> cpu that can do the statistics collection.
That shouldn't be necessary, I assume that you can write a device drinver to do this with the existing hardware.  I'm assuming that the necessary interrupts etc are available to allow this to be done.

It might help if you coudl tell us _exactly_ what you are trying to do and why.  But almost certainly, your approach to doing it will have to change.
0
 
saidoAuthor Commented:
ok,
I have a board supporting multiple buses including I2c and SPI that i have to controle from PC via parallel port. for the I2c the function frequency must be about 200Khz and SPI about 1Mhz.

so when develloping the protocol,  i have to insert delays when sending/receiving bits ( either for the clock or data) to let them be stable on the line.

Said
0
 
SalteCommented:
Sounds like you very much need to write a device driver to me.

Since it is connected to the PC via the paralell port you don't need to make any hardware card (you appearantly have that already) but you do need to write a driver that can work on the paralell port and handle the timing accurately.

In any event, a regular application cannot possibly handle such timing. In a multi tasking environment your application may be stopped at any time and put to sleep by the OS in order to allow other processes (servers, system tasks, etc etc, do a CTRL+ALT+DEL in Win2K or WinXP and see the task manager and click on the 'processes' tab to see all the processes that require at one time or another the ability to run and whenever they run your application can not run, so it is forced to sleep).

It doesn't matter if you wake up after sleeping for exactly 3 milliseconds and then immediately is put to sleep for 300 milliseconds before you can do anything you were planning to do after that sleep.

Code like this:

void do_something()
{
A:
   sleep_for_very_short_interval();
B:
   do_something_else();
}

Now, if the sleep_for_very_short_interval() correctly wakes up after that interval but while you're at label B and before you get to do_something_else you are forced into sleep by the OS because some other high priority task require the CPU then you won't get chance to do_something_else until after the OS let you continue your task again.

Alf
0
 
tinchosCommented:
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:

Please Review

Please leave any comments here within the next seven days.

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!

Tinchos
EE Cleanup Volunteer
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

  • 9
  • 6
  • 5
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now