?
Solved

High resolution timer to Delphi 7

Posted on 2011-02-16
9
Medium Priority
?
1,684 Views
Last Modified: 2013-11-22
Want a high resolution timer without wait and lot of CPU load...
GetTickCount and Sleep have only resolution doen to ms integer level....
My problem is as follow...
Need to set the delay, calculated by delay := 6000/Speed...
eg. delay := 6000/307 (= 19,54)  and delay := 6000/300 ( =20).
Any speed changes is not available between 300-307 because of rounded sepeed unit (integer).
Is there possibility to go down to microseconds level and change calculatimg form to eg. SpeedUnit := 60000/Speed, eg. 60000/304 (=1973 µs = 19.7 ms)?
How to do?
0
Comment
Question by:ejla51
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
9 Comments
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 34905879
0
 
LVL 32

Assisted Solution

by:Ephraim Wangoya
Ephraim Wangoya earned 800 total points
ID: 34908175

Have you considered what will happen when you are doing this kind of delay. At first glance seems to me your program will be locking up everytime you do this. Even if you were to use a thread, it will take lots of CPU time

think about this

procedure MyDelay(const AMicroSecs: Integer);
var
  Ellapsed: Integer;
  Start, Stop: Int64;
begin
  QueryPerformanceCounter(Start);
  while Ellapsed < AMicroSeconds do
  begin
     QueryPerformanceCounter(Stop);
     Ellapsed := Stop - Start;
     //since you cant call Sleep or ProcessMessages here because of your high resolution requirement
     //everything else has to stop and wait for this function to complete
  end;
end;

Exactly why is precision up to a millisecond not enough?
0
 

Author Comment

by:ejla51
ID: 34910377
Thanks,
yes I know that about CPU load and have to look for any "lightweight" alternative.
My app send Morse Code telegraphy and timing is quite important (if we want exact right speed).
One length unit has been calculated as 6000/speed (chars/min) .
Due to integer division, unit result will be rounded. What happend here... Light increasing or decreasing of speed have not any effect to really speed because rounded unit would not been changed. A little speed error can be accepted, but there is one, more serious problem....
The fault of the transmit... a  "hiccup" due to heavy CPU load (Sleep, TTimer, interrupts?). These may be noticeable especially on slow computers...
I know that some have managed to overcome those problems, but I do not know how ...
Have noticed that some have used separate applications to sending morse code... I guess there has used DDE channel to send variables and parameters to this client.

Has had some strange ideas to use serial port for this.
- Set custom baud rate referred to speed and send morse character pattern as binary number ... maybe a bit far-fetched idea?
0
Independent Software Vendors: 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!

 
LVL 2

Accepted Solution

by:
Roza earned 1200 total points
ID: 35098589
Following code is being used in latest version of VHFCtest4Win program.

procedure TCustomKeyer.WaitFor(Time: int64);
var CurrentTime: Int64;
    PreWaitStop: Int64;
    Counter: integer;
begin
  PrewaitStop:=Time-FSleepAccuracy;
  Counter:=0;
  QueryPerformanceCounter(CurrentTime);
  while PreWaitStop>CurrentTime do
  begin
    Sleep(1);
    Inc(counter);
    QueryPerformanceCounter(CurrentTime);
  end;

  while Time>CurrentTime do
  begin
    QueryPerformanceCounter(CurrentTime);
  end;
end;


function GetSleepAccuracy:integer;
const TestLength=500;
var counter: integer;
    PerformanceFrequency, CurrentTime: Int64;
    Times: array[0..TestLength] of Int64;
    Time, MaxTime: Int64;
begin
  QueryPerformanceFrequency(PerformanceFrequency);
  QueryPerformanceCounter(CurrentTime);
  Times[0]:=CurrentTime;
  for Counter:=1 to TestLength do
  begin
    sleep(1);
    QueryPerformanceCounter(CurrentTime);
    Times[Counter]:=CurrentTime;
  end;

  MaxTime:=0;

  for Counter:=1 to TestLength do
  begin
    Time:=(Times[Counter]-Times[Counter-1]);
    MaxTime:=Max(MaxTime,Time);
  end;
  Result:=Round(MaxTime*1.5);
end;

After many years of experiments, keying is accurate and I am affraid to correct line of code in keyer unit HI

73 Peter, S52AA
0
 

Author Comment

by:ejla51
ID: 35100449
Hi Peter and thank you for the nice tip!

In the quick test I  can't  do it working... propably due to my Keying threads syncronization...
WaitrFor does not  "wait"  anything but passed in zero time...
My CW component  have abt. 1500 rows  so its a little too long to show here.

Have you used separatly Thread  for  keying?

73 Erkki, SM5NBE / SA5N
0
 
LVL 2

Expert Comment

by:Roza
ID: 35107141
Hi Erkki

I use seperate thread with Time priority set to tpTimeCritical;

Usage example:

  private
    { Private declarations }
    procedure WaitFor(Time: int64);
  public
    { Public declarations }
    FSleepAccuracy: Integer;
  end;


procedure TForm1.Button1Click(Sender: TObject);
var CurrentTime,
    StopTime,
    PerformanceFrequency: Int64;
    DelayInMSec: integer;
begin
  QueryPerformanceFrequency(PerformanceFrequency);
  DelayInMSec:=3000;
  Label1.Caption:='Start';
  Label1.Update;
  QueryPerformanceCounter(CurrentTime);

  StopTime:=CurrentTime+Round(DelayInMSec/1000*PerformanceFrequency);
  WaitFor(StopTime);
  Label1.Caption:='Stop';
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FSleepAccuracy:=GetSleepAccuracy;
end;

Process of keying is following:

I operate with performancecounter which measures my time.
Ex: KeyOn function first waits for NextEventTime, then sets key and adds Dot/Dash length to NextEventTime.
KeyOff function then waits for NextEventTime and adds necessary pause to NextEventTime.

With this approach all calculation is done at begining of wait time and no unwanted delay is added to keying process because of calculating something.

If Windows switches context away from my thread, the worst thing is that happens during busy waiting of WaitFor function. But when thread continues and time is overrun it imediately turns key on/off or whatewer it should do next and reducing overrun time to minimum.
0
 

Author Comment

by:ejla51
ID: 35146459
ok... thanks.
I have been very busy and haven't had time to work with this project...
I'll accept your tip.
Because ewancoya had same principe to use QueryPerformanceCounter, I have to split points.
If there is some more questions I sent private mail to you Peter.
Regards,
Erkki
   
0
 

Author Comment

by:ejla51
ID: 35184830
Peter,
have looked little more your code...

Is there structure error in WaitFor...??!!

I debugged procedure and found that PreWaitStop would newer be higher than the CurrentTime?
I added a row before While loop :

 Time := Time * 10000; // My original Time is in milliseconds
 Counter:=0;
 QueryPerformanceCounter(CurrentTime);
 PreWaitStop := CurrentTime + (Time - FSleepAccuracy); // Have got FSleepAccuracy value to 10600 with GetSleepAccuracy

  while PreWaitStop > CurrentTime do
  begin
   ...
 
Regards,
Erkki

procedure TCustomKeyer.WaitFor(Time: int64);
var CurrentTime: Int64;
    PreWaitStop: Int64;
    Counter: integer;
begin
  PrewaitStop:=Time-FSleepAccuracy;
  Counter:=0;
  QueryPerformanceCounter(CurrentTime);
  while PreWaitStop>CurrentTime do
  begin
    Sleep(1);
    Inc(counter);
    QueryPerformanceCounter(CurrentTime);
  end;

  while Time>CurrentTime do
  begin
    QueryPerformanceCounter(CurrentTime);
  end;
end;

Open in new window

0
 

Author Comment

by:ejla51
ID: 35188003
Sri Peter,
well, I see ...  Your Time parameter allready include CurrentTime + Delay.
I had only Delay as Time parameter.
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
In this brief tutorial Pawel from AdRem Software explains how you can quickly find out which services are running on your network, or what are the IP addresses of servers responsible for each service. Software used is freeware NetCrunch Tools (https…
In this video, Percona Solution Engineer Dimitri Vanoverbeke discusses why you want to use at least three nodes in a database cluster. To discuss how Percona Consulting can help with your design and architecture needs for your database and infras…
Suggested Courses
Course of the Month9 days, 1 hour left to enroll

764 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