MFC中SetTimer定时不准确?试试用多媒体定时器吧

时间:2021-09-27 20:35:24

最近做一个项目,需要用到1ms的定时器中断,但用SetTimer总是觉得不准确,后来用程序一测试,还真是不准,定时时间设为1ms,但实际大约没10ms触发一次中断,至于如何测试的后面有代码。网上很多人也说了SetTimer定时不准确的问题,后来用多媒体定时器,就比较准了。

多媒体定时器使用方法:

添加头文件

#include "mmsystem.h"  //head file
#pragma comment(lib,"winmm")  //lib file

下面是函数

 
 
void CALLBACK SendFun(UINT wTimerID, UINT msg, DWORD dwUser, DWORD dwl, DWORD dw2);
MMRESULT g_wTimerID = 0;
 int   timeRes = 1 ;bool CIExample0042aDlg::CreateTimer(){ TIMECAPS tc; UINT wTimerRes; //设置多媒体定时器 if(timeGetDevCaps(&tc,sizeof(TIMECAPS))!=TIMERR_NOERROR)//向机器申请一个多媒体定时器 return false;//获得机器允许的时间间隔(一般可达到1毫秒) wTimerRes=min(max(tc.wPeriodMin,1),tc.wPeriodMax); //定时器开始工作 timeBeginPeriod(wTimerRes); timeRes=wTimerRes;//每过6毫秒调用回调函数timerback(),wTimerID为定时器ID.TIME_PERIODIC表周期性调用,TIME_ONESHOT表只产生一次事件 g_wTimerID = timeSetEvent(10, timeRes, (LPTIMECALLBACK)SendFun, (DWORD)this, TIME_PERIODIC); if(g_wTimerID == 0)return false;return true;}/******************************************************************\ function name : DestroyTimer desc : destroy the timer created by calling CreateTimer argument void ret code void\******************************************************************/void CIExample0042aDlg::DestroyTimer()//关闭时调用该函数{timeKillEvent(g_wTimerID);timeEndPeriod(timeRes);}void CALLBACK SendFun(UINT wTimerID, UINT msg, DWORD dwUser, DWORD dwl, DWORD dw2){CIExample0042aDlg *timer =(CIExample0042aDlg *)dwUser;timer->SendMessage(WM_UPDATETIME,0,0);//由于这是个静态函数,所以这里调用了另一个函数,响应中断消息//这里即为1ms中断的回调函数} 
 添加响应消息 

ON_MESSAGE(WM_UPDATETIME,&OnUpdateTime)      //创建消息映射
响应消息函数
afx_msg LRESULT CIExample0042aDlg::OnUpdateTime(WPARAM, LPARAM)
{
	//响应1ms中断消息的函数,可以添加处理函数
	return TRUE;
}

当关闭程序时,需要kill多媒体定时器,否则会报错

void CIExample0042aDlg::OnDestroy() 
{
	CDialog::OnDestroy();	
	DestroyTimer();
}
同样需要添加消息

ON_WM_DESTROY()


下面就是程序时间测试的函数,还是比较准确的

LARGE_INTEGER   litmp; 
LONGLONG   QPart1;
LONGLONG   QPart2;
double   dfMinus,   dfFreq,   dfTim; 
CString time_his;
void CIExample0042aDlg::Time_Start(){ if(start_tim==1){QueryPerformanceFrequency(&litmp); //获得计数器的时钟频率 dfFreq = (double)litmp.QuadPart; QueryPerformanceCounter(&litmp); //获得初始值    QPart1 = litmp.QuadPart; }}void CIExample0042aDlg::Time_Stop()//CIExample0042aDlg::{if(start_tim==1){QueryPerformanceCounter(&litmp); //获得中止值 QPart2 = litmp.QuadPart; dfMinus = (double)(QPart2 - QPart1);//获得对应的时间值 dfTim = dfMinus / dfFreq; CString strrr,strrr1; strrr.Format("%.3lf", dfTim*1000); time_his+=strrr;time_his+="ms\r\n";m_time.SetWindowText(time_his);m_time.LineScroll(m_time.GetLineCount()); }}
 


其中start_tim连接了一个button,用来控制是否启动时间检测。m_time是文本框,可以显示时间。

使用方法

Time_Start();
//需要测试的代码
Time_Stop();