1. 程式人生 > >MFC精確定時器

MFC精確定時器

上一篇部落格介紹瞭如何利用QueryPerformanceCounter()來精確計時。我們 在上一篇部落格裡看到了,Qt的QTimer類是不能非常精確的定時的。本例介紹一種MFC自己提供的定時器函式timeSetEvent,實現毫秒量級的定時觸發。

h檔案:

#ifndef QTPRECISETIMER_H
#define QTPRECISETIMER_H

#include <QtWidgets/QMainWindow>
#include "ui_qtprecisetimer.h"
#include <Windows.h>
#include <QDebug>
#include <stdio.h>
#include <mmsyscom.h>

#pragma warning(disable:4996)
#pragma comment(lib, "winmm.lib")
void WINAPI OnTimer(UINT, UINT, DWORD, DWORD, DWORD);


class QtPreciseTimer : public QMainWindow
{
	Q_OBJECT

public:
	QtPreciseTimer(QWidget *parent = 0);
	~QtPreciseTimer();
	
public slots:
	void				OnClickStart(void);
private:
	Ui::QtPreciseTimerClass ui;
};

#endif // QTPRECISETIMER_H

cpp檔案:

#include "qtprecisetimer.h"

MMRESULT g_timerID;
FILE		*		m_fp = NULL;
LARGE_INTEGER		m_nBegin;
LARGE_INTEGER		m_nFreq;
QtPreciseTimer::QtPreciseTimer(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);
	connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(OnClickStart()));
	m_fp = fopen("TimerRcd.txt", "w");
}

QtPreciseTimer::~QtPreciseTimer()
{
	fclose(m_fp);
}

void QtPreciseTimer::OnClickStart(void)
{
	QueryPerformanceFrequency(&m_nFreq);//獲取頻率
	QueryPerformanceCounter(&m_nBegin);//獲取起始時間

	g_timerID = timeSetEvent(100, 1, (LPTIMECALLBACK)OnTimer, DWORD(50), TIME_PERIODIC);
	fprintf(m_fp, "m_timerID = %d\n", (int)g_timerID);
}

void WINAPI OnTimer(UINT uiID, UINT uiMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
	static int iCount  = 0;
	if(iCount < 20)
	{
		LARGE_INTEGER nTime;
		QueryPerformanceCounter(&nTime);//獲取時間 
 
		//計算從起始時間開始,到當前的時間間隔,單位毫秒
		int iInterval = (nTime.QuadPart - m_nBegin.QuadPart) / (double)m_nFreq.QuadPart * 1000;
		iCount++;
		fprintf(m_fp, "uiID = %d, uiMsg = %d, dwUser = %d, dw1 = %d, dw2 = %d, Time = %d ms\n", uiID, uiMsg, dwUser, dw1, dw2, iInterval);
	}
	else
	{
		timeKillEvent(g_timerID);
	}
}

執行後的介面:

可見,1)定時誤差在1毫秒範圍內; 2)回撥函式OnTimer的第一個輸入引數uiID其實就等於timeSetEvent的返回值,也就是定時器的ID; 3)timeSetEvent()的第一個輸入引數 代表定時的間隔,單位毫秒,第二個引數代表定時的解析度,或者說精確度,第三個引數指向回撥函式;第四個引數是一個DWORD型,回撥函式的第三個引數的取值與其相等;最後的 引數決定定時器是週期性觸發TIME_PERIODIC還是單次觸發TIME_ONESHOT 。

結束timer時,呼叫timeKillEvent()