[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1829
  • Last Modified:

High resolution timer to Delphi 7

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
ejla51
Asked:
ejla51
2 Solutions
 
Geert GruwezOracle dbaCommented:
0
 
Ephraim WangoyaCommented:

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
 
ejla51Author Commented:
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
Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

 
RozaCommented:
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
 
ejla51Author Commented:
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
 
RozaCommented:
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
 
ejla51Author Commented:
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
 
ejla51Author Commented:
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
 
ejla51Author Commented:
Sri Peter,
well, I see ...  Your Time parameter allready include CurrentTime + Delay.
I had only Delay as Time parameter.
0

Featured Post

Take Control of Web Hosting For Your Clients

As a web developer or IT admin, successfully managing multiple client accounts can be challenging. In this webinar we will look at the tools provided by Media Temple and Plesk to make managing your clients’ hosting easier.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now