Use Delphi to create a precise counter
In many Windows scenarios, programming (such as industrial control and games) requires a relatively precise notebook. This article discusses several methods for implementing the notebook and their precision control in Delphi.
The Timer control is the most commonly used in Delphi. It is very convenient to set and use. Theoretically, its recording accuracy can reach 1 ms (ms ). However, as we all know, Timer has a very low accuracy when the interval is less than 50 ms. It is only applicable to scenarios with low precision requirements.
Here, I will introduce two methods to use Windows API functions to implement accurate time recording. The first method is to use the high-performance frequency notation (called by the author. This method requires two API functions: QueryPerformanceFrequency and QueryPerformanceCounter. The QueryPerformanceFrequency function obtains the fluctuation frequency of the high-performance frequency calculator.
After this function is called, the function saves the fluctuation frequency (in milliseconds) of the system frequency calculator to a LargeInteger. However, if this function is used for testing on several machines, the result is 1193180. You can try it on your machine.
The QueryPerformanceCounter function obtains the number of system frequency counters, and the results are saved to a Largenteger.
Obviously, if QueryPerformanceFrequency is used in timing to obtain the high-performance frequency calculator's shock count per millisecond, then the QueryPerformanceCounter function is used at the start of timing to obtain the current system frequency calculator's shock count. Call the QueryPerformanceCounter function at the end of the timer to obtain the number of system frequency counters. Subtract the two, and then divide the result by the frequency calculator's number of shocks per millisecond, you can get the exact time of an event. (Times divided by frequency equals to time)
Another accurate recording function is the multimedia recording function (which is also defined by the author, because the functions of this series are in Winmm. dll and is used for media playback ).
To implement multimedia recording, you must first use the timeSetEvent function to create timing events. This function is defined in mmsystem. pas in Delphi and is defined as follows:
Function timeSetEvent (uDelay, uResolution: UINT;
LpFunction: TFNTimeCallBack; dwUser: DWord; uFlags: UINT): MMRESULT; stdcall
In function definition, the uDelay parameter defines the latency in milliseconds. this parameter is equivalent to the Interval attribute of the Timer control. The uResolution parameter defines the recording precision. If the accuracy is as high as possible, set this parameter to 0. The lpFunction parameter defines the timeSetEvent function callback function. This function is equivalent to a scheduled interrupt processing function, which is called every time after a uDelay duration. programmers can add corresponding processing statements to the function. The dwUser parameter defines the user-defined callback value, which is passed to the callback function. The uFlags parameter defines the timing type. If there is no interruption, this value should be set to 1.
If the function is successfully called, a multimedia recording object is created in the system. The function specified by lpFunction is called every time a uDelay time is passed. At the same time, the function returns an object identifier. If you no longer need to remember, you must use the timeKillEvent function to delete the notebook object.
XML: namespace prefix = o ns = "urn: schemas-microsoft-com: office"/>
Because Windows is a multi-task operating system, the accuracy of API call-based memory is affected by many other factors. In the end, we use the following program to verify the accuracy of the two records:
Set three types of memory (Timer control, high-performance frequency memory, and multimedia memory ). Set their scheduled interval to 10 ms to keep them working until it reaches a relatively long time (such as 60 seconds), so that the error of the counter will be accumulated, then, their precision can be obtained by comparing them with the actual elapsed time.
The following is a specific detection program.
Unit Unit1; interfaceuses Windows, Messages, SysUtils, Classes, GraphiCS, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, mmSystem; type TForm1 = class (TForm) Edit1: TEdit; Edit2: TEdit; Edit3: TEdit; Button1: TButton; Button2: TButton; Timer1: TTimer; procedure alert (Sender: TObject); procedure Button1Click (Sender: TObject); procedure alert: TObject); procedure Button2Click (Sender: TObject); private {Private declarations} public {Public declarations} end; var Form1: TForm1; actTime1, actTime2: Cardinal; smmCount, sTimerCount, sPCount: single; hTimeID: Integer; iTen: Integer; proTimeCallBack: TFNTimeCallBack; procedure TimeProc (uTimerID, uMessage: UINT; dwUser, dw1, dw2: DWord) stdcall; procedure proEndCount; implementation {$ R *. DFM} // procedure proEndCount; begin actTime2: = GetTickCount-actTime1; Form1.Button2. enabled: = False; Form1.Button1. enabled: = TRue; Form1.Timer1. enabled: = False; smmCount: = 60; sTimerCount: = 60; spCount: =-1; timeKillEvent (hTimeID); end; procedure TimeProc (uTimerID, uMessage: UINT; dwUser, dw1, dw2: DWord) stdcall; begin Form1.Edit2. text: = FloatToStr (smmCount); smmCount: = smmCount-0.01; end; procedure TForm1.FormCreate (Sender: TObject); begin Button1.Caption: = 'start count'; Button2.Caption: = 'end count '; button2.Enabled: = False; Button1.Enabled: = True; Timer1.Enabled: = False; smmCount: = 60; sTimerCount: = 60; sPCount: = 60; end; procedure TForm1.Button1Click (Sender: TObject ); var lgTick1, lgTick2, lgPer: TLargeInteger; fTemp: Single; begin Button2.Enabled: = True; Button1.Enabled: = False; success: = True; Timer1.Interval: = 10; proTimeCallback: = TimeProc; // timeSetEvent uses the http://blog.csdn.net/xieyunc/archive/2009/04/29/4136125.aspx hTimeID: = timeSetEvent (10, 0, proTimeCallback,); actTime1: = GetTickCount; // gets the number of vibrations of the system's high-performance frequency counter within one second, reference http://www.cnblogs.com/del/archive/2008/02/16/1070610.html QueryPerformanceFrequency (lgPer); fTemp: = lgPer/1000; iTen: = Trunc (fTemp * 10); QueryPerformanceCounter (lgTick1); lgTick2: = lgTick1; sPCount: = 60; while sPCount> 0 do begin QueryPerformanceCounter (lgTick2); // If the clock shake times exceed 10 milliseconds, refresh the display of Edit3 If lgTick2-lgTick1> iTen Then begin lgTick1: = lgTick2; sPCount: = sPCount-0.01; Edit3.Text: = FloatToStr (sPCount); Application. processMessages; end; procedure tables (Sender: TObject); begin Edit1.Text: = FloatToStr (sTimerCount); sTimerCount: = sTimerCount-0.01; end; procedure tables (Sender: TObject ); begin proEndCount; // display the ShowMessage ('actual elapsed time' + IntToStr (actTime2) + 'millisecond ') from the start count to the actual elapsed time of the count; end.
Run the program and click "Start countdown". The program starts 60 seconds of Countdown, because the above program only involves the principle of the notebook program and does not add error handling to it, therefore, do not wait until the 60-second countdown ends. Click "End countdown" to end the countdown. In the displayed dialog box, the actual elapsed time (in milliseconds) is displayed. Multiply the time in the three text boxes by 1000, and then the actual elapsed time is closer to 60000, the higher the recording accuracy.
The following is the execution result on my machine.
XML: namespace prefix = v ns = "urn: schemas-microsoft-com: vml"/> ASPectratio = "t"> 2000/temp/msoclip1/01/clip_image001.jpg "o: title = "exact score">
From the above results, the accuracy of the Timer created by the Timer control of Delphi is very poor and cannot be used in practice. However, the error of the high-performance frequency counter and the multimedia counter method is less than 1%. This error can be completely ignored in the Application Considering the impact of time on the program in the text box.
In addition, when running the program, the author also found a problem. If you drag the window during the countdown, the display in the text box will stop. When you drag and drop the window, the multimedia note display will skip this time period, the other two types of records show that the countdown is still from the original time. This indicates that the multimedia notebook runs in an independent thread and is not affected by the program.
Based on the above introduction and examples, we can see that if you want to establish a high-precision notebook, it is better to use multimedia notebook. High-performance frequency notation is suitable for calculating the time consumed by a very short process (for example, analyzing the execution time of a program segment called multiple times in a program to optimize the program ), after all, the theory of high-performance frequency records can reach microseconds. Although the Timer control has much lower precision than the above two, it is easy to use and is the best choice for low requirements.