implement a microsecond resolution Delay? (微秒级延迟)
implement a microsecond resolution Delay? (微秒级延迟)
https://github.com/fundamentalslib/fundamentals5/tree/master/Source
http://robotics.stackexchange.com/questions/7502/control-both-velocity-and-position-linear-actuator/7512#7512
http://electronics.stackexchange.com/questions/38573/smooth-a-motor-movement
http://delphi.cjcsoft.net//viewthread.php?tid=391
implement a microsecond resolution Delay?
Author: Lemy
Homepage: http://www.swissdelphicenter.com
0 Comments to this tip [Write new comment]
[ Print tip ]
Tip Rating (8):
epicTimer.pas
Author: Lemy
Homepage: http://www.swissdelphicenter.com
0 Comments to this tip [Write new comment]
[ Print tip ]
Tip Rating (8):
epicTimer.pas
// Wait 0.2ms
procedure PerformanceDelay;
var
hrRes, hrT1, hrT2, dif: Int64;
begin
if QueryPerformanceFrequency(hrRes) then
begin
QueryPerformanceCounter(hrT1);
repeat
QueryPerformanceCounter(hrT2);
dif := (hrT2 - hrT1) * 10000000 div hrRes;
until dif > 2;
end;
end;
---On Linux
Code:
#include
#include
#include
#include
#include
/* Helpful conversion constants. */
static const unsigned usec_per_sec = 1000000;
static const unsigned usec_per_msec = 1000;
/* These functions are written to match the win32
signatures and behavior as closely as possible.
*/
bool QueryPerformanceFrequency(int64_t *frequency){
/* Sanity check. */
assert(frequency != NULL);
/* gettimeofday reports to microsecond accuracy. */
*frequency = usec_per_sec;
return true;
}
bool QueryPerformanceCounter(int64_t *performance_count){
struct timeval time;
/* Sanity check. */
assert(performance_count != NULL);
/* Grab the current time. */
gettimeofday(&time, NULL);
*performance_count = time.tv_usec + /* Microseconds. */
time.tv_sec * usec_per_sec; /* Seconds. */
return true;
}
-------------
#include
#include
#include
#include
/* Helpful conversion constants. */
static const unsigned usec_per_sec = 1000000;
static const unsigned usec_per_msec = 1000;
/* These functions are written to match the win32
signatures and behavior as closely as possible.
*/
bool QueryPerformanceFrequency(int64_t *frequency){
/* Sanity check. */
assert(frequency != NULL);
/* gettimeofday reports to microsecond accuracy. */
*frequency = usec_per_sec;
return true;
}
bool QueryPerformanceCounter(int64_t *performance_count){
struct timeval time;
/* Sanity check. */
assert(performance_count != NULL);
/* Grab the current time. */
gettimeofday(&time, NULL);
*performance_count = time.tv_usec + /* Microseconds. */
time.tv_sec * usec_per_sec; /* Seconds. */
return true;
}
-------------
{******************************************************************************}
{ }
{ Library: Fundamentals 4.00 }
{ File name: cTimers.pas }
{ File version: 4.08 }
{ Description: Timer functions }
{ }
{ Copyright: Copyright 1999-2011, David J Butler }
{ All rights reserved. }
{ Redistribution and use in source and binary forms, with }
{ or without modification, are permitted provided that }
{ the following conditions are met: }
{ Redistributions of source code must retain the above }
{ copyright notice, this list of conditions and the }
{ following disclaimer. }
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
{ POSSIBILITY OF SUCH DAMAGE. }
{ }
{ Home page: http://fundementals.sourceforge.net }
{ Forum: http://sourceforge.net/forum/forum.php?forum_id=2117 }
{ E-mail: fundamentalslib at gmail.com }
{ }
{ Revision history: }
{ }
{ 1999/11/10 0.01 Initial version. }
{ 2005/08/19 4.02 Compilable with FreePascal 2.0.1 }
{ 2005/08/26 4.03 Improvements to timer functions. }
{ 2005/08/27 4.04 Revised for Fundamentals 4. }
{ 2007/06/08 4.05 Compilable with FreePascal 2.04 Win32 i386 }
{ 2009/10/09 4.06 Compilable with Delphi 2009 Win32/.NET. }
{ 2010/06/27 4.07 Compilable with FreePascal 2.4.0 OSX x86-64 }
{ 2011/05/04 4.08 Split from cDateTime unit. }
{ }
{ Supported compilers: }
{ }
{ Borland Delphi 5/6/7/2005/2006/2007 Win32 i386 }
{ Borland Delphi 2009 .NET }
{ FreePascal 2.0.1 Win32 i386 }
{ FreePascal 2.0.1 Linux i386 }
{ FreePascal 2.4.0 OSX x86-64 }
{ }
{******************************************************************************}
{$INCLUDE cDefines.inc}
unit cTimers;
interface
uses
{ System }
SysUtils;
{ }
{ Errors }
{ }
type
ETimers = class(Exception);
{ }
{ Tick timer }
{ }
{ The tick timer returns millisecond units. }
{ On some systems the tick is only accurate to 10-20ms. }
{ }
const
TickFrequency = 1000;
function GetTick: LongWord;
function TickDelta(const D1, D2: LongWord): Integer;
{ }
{ High-precision timer }
{ }
{ StartTimer returns an encoded time (running timer). }
{ StopTimer returns an encoded elapsed time (stopped timer). }
{ ResumeTimer returns an encoded time (running timer), given an encoded }
{ elapsed time (stopped timer). }
{ StoppedTimer returns an encoded elapsed time of zero, ie a stopped timer }
{ with no time elapsed. }
{ MillisecondsElapsed returns elapsed time for a timer in milliseconds. }
{ MicrosecondsElapsed returns elapsed time for a timer in microseconds. }
{ DelayMicroSeconds goes into a tight loop for the specified duration. It }
{ should be used where short and accurate delays are required. }
{ GetHighPrecisionFrequency returns the resolution of the high-precision }
{ timer in units per second. }
{ GetHighPrecisionTimerOverhead calculates the overhead associated with }
{ calling both StartTimer and StopTimer. Use this value as Overhead when }
{ calling AdjustTimerForOverhead. }
{ }
type
THPTimer = Int64;
procedure StartTimer(var Timer: THPTimer);
procedure StopTimer(var Timer: THPTimer);
procedure ResumeTimer(var StoppedTimer: THPTimer);
procedure InitStoppedTimer(var Timer: THPTimer);
procedure InitElapsedTimer(var Timer: THPTimer; const Milliseconds: Integer);
function MillisecondsElapsed(const Timer: THPTimer;
const TimerRunning: Boolean = True): Integer;
function MicrosecondsElapsed(const Timer: THPTimer;
const TimerRunning: Boolean = True): Int64;
procedure WaitMicroseconds(const MicroSeconds: Integer);
function GetHighPrecisionFrequency: Int64;
function GetHighPrecisionTimerOverhead: Int64;
procedure AdjustTimerForOverhead(var StoppedTimer: THPTimer;
const Overhead: Int64 = 0);
{ }
{ Test cases }
{ }
{$IFDEF DEBUG}{$IFDEF SELFTEST}
procedure SelfTest;
{$ENDIF}{$ENDIF}
implementation
{$IFDEF WindowsPlatform}
uses
Windows;
{$ENDIF}
{ }
{ Tick timer }
{ }
{$IFDEF WindowsPlatform}
function GetTick: LongWord;
begin
Result := GetTickCount;
end;
{$ELSE}
{$IFDEF UNIX}
function GetTick: LongWord;
begin
Result := LongWord(DateTimeToTimeStamp(Now).Time);
end;
{$ENDIF}{$ENDIF}
{$IFOPT Q+}{$DEFINE QOn}{$ELSE}{$UNDEF QOn}{$ENDIF}{$Q-}
function TickDelta(const D1, D2: LongWord): Integer;
begin
Result := Integer(D2 - D1);
end;
{$IFDEF QOn}{$Q+}{$ENDIF}
{ }
{ High-precision timing }
{ }
const
SHighResTimerNotAvailable = 'High resolution timer not available';
{$IFDEF WindowsPlatform}
{$DEFINE Defined_GetHighPrecisionCounter}
var
HighPrecisionTimerInit : Boolean = False;
HighPrecisionMillisecondFactor : Int64;
HighPrecisionMicrosecondFactor : Int64;
function CPUClockFrequency: Int64;
begin
if not QueryPerformanceFrequency(Result) then
raise ETimers.Create(SHighResTimerNotAvailable);
end;
procedure InitHighPrecisionTimer;
var F : Int64;
begin
F := CPUClockFrequency;
HighPrecisionMillisecondFactor := F div 1000;
HighPrecisionMicrosecondFactor := F div 1000000;
HighPrecisionTimerInit := True;
end;
function GetHighPrecisionCounter: Int64;
begin
if not HighPrecisionTimerInit then
InitHighPrecisionTimer;
QueryPerformanceCounter(Result);
end;
{$ENDIF}
{$IFDEF UNIX}
{$DEFINE Defined_GetHighPrecisionCounter}
{$IFDEF FREEPASCAL}
const
HighPrecisionMillisecondFactor = 1000;
HighPrecisionMicrosecondFactor = 1;
function GetHighPrecisionCounter: Int64;
var TV : TTimeVal;
TZ : PTimeZone;
begin
TZ := nil;
fpGetTimeOfDay(@TV, TZ);
Result := Int64(TV.tv_sec) * 1000000 + Int64(TV.tv_usec);
end;
{$ELSE}
function GetHighPrecisionCounter: Int64;
var T : Ttimeval;
begin
GetTimeOfDay(T, nil);
Result := Int64(T.tv_sec) * 1000000 + Int64(T.tv_usec);
end;
{$ENDIF}
{$ENDIF}
{$IFNDEF Defined_GetHighPrecisionCounter}
{$IFDEF CPU_386}
{$DEFINE Defined_GetHighPrecisionCounter}
function GetHighPrecisionCounter: Int64;
asm
rdtsc
end;
{$ENDIF}
{$ENDIF}
{$IFNDEF Defined_GetHighPrecisionCounter}
function GetHighPrecisionCounter: Int64;
begin
raise ETimers.Create(SHighResTimerNotAvailable);
end;
{$ENDIF}
procedure StartTimer(var Timer: THPTimer);
begin
Timer := GetHighPrecisionCounter;
end;
{$IFOPT Q+}{$DEFINE QOn}{$ELSE}{$UNDEF QOn}{$ENDIF}{$Q-}
procedure StopTimer(var Timer: THPTimer);
begin
Timer := Int64(GetHighPrecisionCounter - Timer);
end;
{$IFDEF QOn}{$Q+}{$ENDIF}
procedure ResumeTimer(var StoppedTimer: THPTimer);
var T : THPTimer;
begin
StartTimer(T);
StoppedTimer := Int64(T - StoppedTimer);
end;
procedure InitStoppedTimer(var Timer: THPTimer);
begin
Timer := 0;
end;
{$IFOPT Q+}{$DEFINE QOn}{$ELSE}{$UNDEF QOn}{$ENDIF}{$Q-}
procedure InitElapsedTimer(var Timer: THPTimer; const Milliseconds: Integer);
begin
{$IFDEF DELPHI5}
Timer := GetHighPrecisionCounter - (Milliseconds * HighPrecisionMillisecondFactor);
{$ELSE}
Timer := Int64(GetHighPrecisionCounter - (Milliseconds * HighPrecisionMillisecondFactor));
{$ENDIF}
end;
{$IFDEF QOn}{$Q+}{$ENDIF}
{$IFOPT Q+}{$DEFINE QOn}{$ELSE}{$UNDEF QOn}{$ENDIF}{$Q-}
function MillisecondsElapsed(const Timer: THPTimer; const TimerRunning: Boolean = True): Integer;
begin
if not TimerRunning then
Result := Timer div HighPrecisionMillisecondFactor
else
Result := Integer(Int64(GetHighPrecisionCounter - Timer) div HighPrecisionMillisecondFactor);
end;
{$IFDEF QOn}{$Q+}{$ENDIF}
{$IFDEF WindowsPlatform}
{$IFOPT Q+}{$DEFINE QOn}{$ELSE}{$UNDEF QOn}{$ENDIF}{$Q-}
function MicrosecondsElapsed(const Timer: THPTimer; const TimerRunning: Boolean = True): Int64;
begin
if not TimerRunning then
Result := Timer div HighPrecisionMicrosecondFactor
else
{$IFDEF DELPHI5}
Result := Int64((GetHighPrecisionCounter - Timer) div HighPrecisionMicrosecondFactor);
{$ELSE}
Result := Int64(Int64(GetHighPrecisionCounter - Timer) div HighPrecisionMicrosecondFactor);
{$ENDIF}
end;
{$IFDEF QOn}{$Q+}{$ENDIF}
{$ELSE}
{$IFDEF UNIX}
{$IFOPT Q+}{$DEFINE QOn}{$ELSE}{$UNDEF QOn}{$ENDIF}{$Q-}
function MicrosecondsElapsed(const Timer: THPTimer; const TimerRunning: Boolean = True): Int64;
begin
if not TimerRunning then
Result := Timer
else
Result := Int64(GetHighPrecisionCounter - Timer);
end;
{$IFDEF QOn}{$Q+}{$ENDIF}
{$ENDIF}{$ENDIF}
{$IFOPT Q+}{$DEFINE QOn}{$ELSE}{$UNDEF QOn}{$ENDIF}{$Q-}
{$IFDEF DELPHI5}{$IFOPT O+}{$DEFINE OOn}{$ELSE}{$UNDEF OOn}{$ENDIF}{$OPTIMIZATION OFF}{$ENDIF}
procedure WaitMicroseconds(const Microseconds: Integer);
var I, J, F : Int64;
begin
// start high precision timer as early as possible in procedure for minimal
// overhead
I := GetHighPrecisionCounter;
if Microseconds <= 0 then
exit;
// sleep milliseconds
if Microseconds >= 1000 then
Sleep(Microseconds div 1000);
// loop remaining microseconds
{$IFDEF DELPHI5}
F := Microseconds * HighPrecisionMicrosecondFactor;
{$ELSE}
F := Int64(Microseconds * HighPrecisionMicrosecondFactor);
{$ENDIF}
repeat
J := GetHighPrecisionCounter;
{$IFDEF DELPHI5}
until J - I >= F;
{$ELSE}
until Int64(J - I) >= F;
{$ENDIF}
end;
{$IFDEF QOn}{$Q+}{$ENDIF}
{$IFDEF DELPHI5}{$IFDEF OOn}{$OPTIMIZATION ON}{$ENDIF}{$ENDIF}
{$IFDEF WindowsPlatform}
function GetHighPrecisionFrequency: Int64;
begin
Result := CPUClockFrequency;
end;
{$ELSE}
{$IFDEF UNIX}
function GetHighPrecisionFrequency: Int64;
begin
Result := 1000000;
end;
{$ENDIF}{$ENDIF}
function GetHighPrecisionTimerOverhead: Int64;
var T : THPTimer;
I : Integer;
H : Int64;
begin
// start and stop timer a thousand times and find smallest overhead
StartTimer(T);
StopTimer(T);
H := T;
for I := 1 to 1000 do
begin
StartTimer(T);
StopTimer(T);
if T < H then
H := T;
end;
Result := H;
end;
{$IFOPT Q+}{$DEFINE QOn}{$ELSE}{$UNDEF QOn}{$ENDIF}{$Q-}
{$IFDEF DELPHI5}{$IFOPT O+}{$DEFINE OOn}{$ELSE}{$UNDEF OOn}{$ENDIF}{$OPTIMIZATION OFF}{$ENDIF}
procedure AdjustTimerForOverhead(var StoppedTimer: THPTimer;
const Overhead: Int64);
begin
if Overhead <= 0 then
{$IFDEF DELPHI5}
StoppedTimer := StoppedTimer - GetHighPrecisionTimerOverhead
{$ELSE}
StoppedTimer := Int64(StoppedTimer - GetHighPrecisionTimerOverhead)
{$ENDIF}
else
{$IFDEF DELPHI5}
StoppedTimer := StoppedTimer - Overhead;
{$ELSE}
StoppedTimer := Int64(StoppedTimer - Overhead);
{$ENDIF}
if StoppedTimer < 0 then
StoppedTimer :=0;
end;
{$IFDEF QOn}{$Q+}{$ENDIF}
{$IFDEF DELPHI5}{$IFDEF OOn}{$OPTIMIZATION ON}{$ENDIF}{$ENDIF}
{ }
{ Test cases }
{ }
{$IFDEF DEBUG}{$IFDEF SELFTEST}
{$ASSERTIONS ON}
procedure SelfTest;
var A, B : LongWord;
T : THPTimer;
begin
Assert(TickDelta(0, 10) = 10);
Assert(TickDelta($FFFFFFFF, 10) = 11);
{$IFDEF WindowsPlatform}
Assert(CPUClockFrequency > 0);
{$ENDIF}
// test timers using delay
StartTimer(T);
A := GetTick;
WaitMicroseconds(20000); // 20ms
B := GetTick;
StopTimer(T);
Assert(TickDelta(A, B) > 0); // FAILS sometimes for less than 20ms wait above
Assert(MillisecondsElapsed(T, False) >= 10);
end;
{$ENDIF}{$ENDIF}
end.
评论