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.
评论