最近做一个项目,需要用到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();