Link to home
Avatar of ejla51
ejla51

asked on

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?
Avatar of Geert G
Geert G
Flag of Belgium image

SOLUTION
Avatar of Ephraim Wangoya
Ephraim Wangoya
Flag of United States of America image

Blurred text
THIS SOLUTION IS ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
Avatar of ejla51
ejla51

ASKER

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?
ASKER CERTIFIED SOLUTION
THIS SOLUTION IS ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
Avatar of ejla51

ASKER

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
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.
Avatar of ejla51

ASKER

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
   
Avatar of ejla51

ASKER

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

Avatar of ejla51

ASKER

Sri Peter,
well, I see ...  Your Time parameter allready include CurrentTime + Delay.
I had only Delay as Time parameter.