Precise Timing based on windows in VC
Youzhiyu, Institute of optoelectronic technology, Chinese Emy of Sciences Download Sample project In the industrial production control system, there are many operations that require timed completion, such as regularly displaying the current time, regularly refreshing the progress bar on the screen, topThe machine regularly sends commands and transmits data to the lower computer. In particular, real-time control systems and data collection systems that require high control performance require precise and scheduled operations. As we all know, Windows is a message-based system, and any event is executed by sending and receiving messages.This brings about some problems, such as when the computer's CPU is occupied by a process, or when the system resources are insufficient, it is sent to the message queue.Messages in are temporarily suspended and cannot be processed in real time. Therefore, you cannot simply raise a timing requirement through Windows messages.Strict events. In addition, because the access to the underlying hardware of the computer has been encapsulated in windowsIt is also difficult to access hardware to complete accurate timing. Therefore, in actual application, the appropriate timing method should be adopted according to the specific timing precision requirements. VC provides a lot of time-related functions, using which the control program can accurately complete timing and timing operations. This topic describesSeven methods of precise timing based on windows in VC are shown in: Figure 1 Image Description
Method 1: wm_timer message ing in VC can be used for simple time control. First, call the settimer () function to set the timing.For example, settimer (0,200, null) sets the interval of Ms. Then add the scheduled response function to the application.Ontimer (), and add the Response Processing statement to the function to complete the operation at the scheduled time. This timing method is veryIt is simple and can implement certain timing functions, but its timing function is the same as the delay function of the sleep () function, with low precision and minimumThe timer accuracy is only 30 ms, the CPU usage is low, and the priority of timer messages in the multitasking operating system is very low, so it cannot be timelyApplications in real-time control environments are often not satisfied. It can only be used to achieve low timing precision requirements, such as dynamic display of Bitmap. For example, timer1 In the example project. Method 2: Use the sleep () function in VC to implement latency. Its unit is ms. For example, if the latency is 2 seconds, use sleep (2000 ). Extremely accurateLow, the minimum timing accuracy is only 30 ms, the disadvantage of using the sleep function is that other messages cannot be processed during the delay period, if the time is too longLong, just like a dead machine, the CPU usage is very high, can only be used in a latency program that does not require high. For example, timer2 In the example project. Method 3: Use the coledatetime class and coledatetimespan class in combination with the Windows message processing process to achieve latency in seconds. For example, timer3 and timer3_1 In the example project. The following is a two-second latency code: Coledatetime start_time = coledatetime: getcurrenttime (); coledatetimespan end_time = coledatetime: getcurrenttime ()-start_time; while (end_time.gettotalseconds () <2) // implement latency of 2 seconds {MSG; getmessage (& MSG, null,); translatemessage (& MSG); dispatchmessage (& MSG); // the preceding four rows can process other messages during the delay or scheduled period, // although this can reduce the CPU usage, // It reduces the latency or timing accuracy and can be removed in practical applications. End_time = coledatetime: getcurrenttime ()-start_time;} // in this way, other messages can be processed during latency. Method 4: In case of high precision requirements, the gettickcount () function can be used in VC. the return value of this function isDWORD type, indicating the time interval after a computer starts in ms. The message ing accuracy is higher than that of wm_timer.In a short period, the timing error is 15 ms. In a long period, the timing error is low. If the timing time is too long, it is like a dead end, and the CPU usage is very high, it can only be used in latency programs with low requirements. For example, timer4 and timer4_1 In the example project. The following code can implement accurate timing within 50 ms: DWORD dwStart = GetTickCount(); DWORD dwEnd = dwStart; do { dwEnd = GetTickCount()-dwStart; }while(dwEnd <50); To enable the gettickcount () function to process other messages during a delay or scheduled period, you can change the code: DWORD dwStart = GetTickCount(); DWORD dwEnd = dwStart; do { MSG msg; GetMessage(&msg,NULL,0,0); TranslateMessage(&msg); DispatchMessage(&msg); dwEnd = GetTickCount()-dwStart; }while(dwEnd <50); This can reduce the CPU usage and process other messages during the delay or scheduled period, but reduces the latency or scheduled precision. Method 5: DWORD timegettime (void), a multimedia timer function similar to the gettickcount () functionReturns the number of milliseconds that have elapsed since Windows was started. Microsoft provides a precise timer in its multimedia Windows system.Layer API persistence, the multimedia timer can accurately read the current time of the system, and can completeEvents, functions, or processes. The difference is that before calling the DWORD timegettime (void) functionAnd mmsystem. h are added to the project. Otherwise, the DWORD timegettime (void) function is prompted during compilation. Because of thisThe function is scheduled to be controlled through queries. Therefore, a scheduled cycle should be set up to control scheduled events. For example, timer5 and timer5_1 In the example project. Method 6: Use the multimedia timer timesetevent () function. The timer precision of this function is ms. This function can be used to implement periodic function calls. For example, timer6 and timer6_1 In the example project. The function prototype is as follows: MMRESULT timeSetEvent( UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, WORD dwUser, UINT fuEvent ) This function sets a scheduled callback event, which can be a one-time event or periodic event. Once an event is activated, the specified callback function is called,Return the identifier code of the event after success. Otherwise, return null. Function parameters are described as follows: Udelay: Specifies the event cycle in milliseconds. Uresolution: Specify the latency precision in milliseconds. The smaller the value, the higher the timer event resolution. The default value is 1 ms. Lptimeproc: point to a callback function. Dwuser: stores user-provided callback data. Fuevent: Specify the timer event type: time_oneshot: udelay only generates one event time_periodic in milliseconds: events are generated cyclically every udelay millisecond. You can call the timesetevent () function to define the tasks to be periodically executed in the lptimeproc callback function.(For example, scheduled sampling and Control) to complete the events to be processed. Note that the task processing time cannot be greater than the cycle interval. In addition, after the timer is used,Timekillevent () should be called to release it in a timely manner. Method 7: Use queryperformancefrequency () andQueryperformancecounter () function. These two functions are accurate time functions provided by VC only for Windows 95 and later versions, and require computers to support accurate timers on hardware. For example, timer7, timer7_1, timer7_2, and timer7_3 In the example project. The following is a prototype of the queryperformancefrequency () and queryperformancecounter () functions: BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency); BOOL QueryPerformanceCounter(LARGE_INTEGER *lpCount); The data type arge_integer can be an 8-byte long integer or a union structure of two 4-byte long integer numbers,The specific usage depends on whether the compiler supports 64-bit. This type is defined as follows: Typedef union _ large_integer {struct {DWORD lowpart; // 4-byte integer long highpart; // 4-byte integer}; Longlong quadpart; // 8-byte integer} large_integer; Before timing, call the queryperformancefrequency () function to obtain the clock frequency of the machine's Internal timer,Then, call the queryperformancecounter () function before and after a strictly scheduled event. Calculate the eventThe exact time of the calendar. Run the following code to implement accurate timing within 1 ms: Large_integer litmp; Longlong qpart1, qpart2; double dfminus, dffreq, dftim; queryperformancefrequency (& litmp); dffreq = (double) litmp. quadpart; // obtain the counter clock frequency queryperformancecounter (& litmp); qpart1 = litmp. quadpart; // obtain the initial value do {queryperformancecounter (& litmp); qpart2 = litmp. quadpart; // get the abort value dfminus = (double) (QPart2-QPart1); dftim = dfminus/dffreq; // get the corresponding time value, unit: seconds} while (dftim <0.001 ); Its timing error is no more than 1 microsecond, and its precision is related to machine configurations such as CPU. The following program is used to test the exact duration of the function sleep (100: Large_integer litmp; Longlong qpart1, qpart2; double dfminus, dffreq, dftim; queryperformancefrequency (& litmp); dffreq = (double) litmp. quadpart; // obtain the counter clock frequency queryperformancecounter (& litmp); qpart1 = litmp. quadpart; // get the initial value sleep (100); queryperformancecounter (& litmp); qpart2 = litmp. quadpart; // get the abort value dfminus = (double) (QPart2-QPart1); dftim = dfminus/dffreq; // get the corresponding time value, in seconds Due to the error of the sleep () function, each execution result of the preceding program has a slight error. The following code implements precise timing in 1 microsecond: Large_integer litmp; Longlong qpart1, qpart2; double dfminus, dffreq, dftim; queryperformancefrequency (& litmp); dffreq = (double) litmp. quadpart; // obtain the counter clock frequency queryperformancecounter (& litmp); qpart1 = litmp. quadpart; // obtain the initial value do {queryperformancecounter (& litmp); qpart2 = litmp. quadpart; // get the abort value dfminus = (double) (QPart2-QPart1); dftim = dfminus/dffreq; // get the corresponding time value, unit: seconds} while (dftim <0.000001 ); Its timing error generally does not exceed 0.5 microseconds, and its accuracy is related to the configurations of machines such as CPU. (End) |