第3章定时器的应用返回目录3.1概述3.2定时器的使用方法3.3其它定时方法概述3.1概述4.1完成上述这些功能的代码都是按照一定的时间间隔周期性地执行的,这是就需要用到一个新的组件——定时器(TIMER)。在计算机程序设计领域,有很多功能是周期性执行的,如:数据采集程序,系统时间的显示等。定时器是Windows系统的资源,VisualC++提供了定时器消息和一些与定时相关的函数。使用这些函数可以完成程序代码的周期性执行。数据采集:周期性地获得现场的物理量信息系统时间的显示:周期性地获得系统时间,并显示出来。返回3.2定时器的使用方法3.2.1Sleep函数3.2.2WM_TIMER消息3.2.3多媒体定时器返回ViusalC++提供了三种完成周期性操作的方法:1、Sleep函数(延时函数)。2、WM_TIMER消息(Windows窗口消息)。3、多媒体定时器。返回3.2.1Sleep函数while(1){i=i+1;//此处添加需要周期性执行的代码。Sleep(1000);}Sleep函数:延时函数参数:延时的时间(单位ms)返回Sleep函数分析缺点:(1)CPU占用率高,一般适用于单任务的程序(如DOS操作系统的程序)(2)程序能够完成的功能比较简单。(3)定时精度低,(据资料)最小误差为54.915ms,每秒18.2次。优点:(1)使用简单。(2)移植方便。返回3.2.2WM_TIMER4.1Windows系统提供了WM_TIMER消息来实现多任务系统的定时操作。WM_TIMER是一个Windosws的窗口消息1、WM_TIMER的功能:(1)可以完成定时操作。(2)定时任务执行完毕后,将控制权交回给程序。程序可以进行其它的操作。众所周知,Windows系统是一个多任务的操作系统。即可以有多个任务并行,这时,周期性(定时)执行的任务在执行完毕后,应该将控制权交给系统,这样程序的其它功能才能得以执行。返回应用程序启动定时器系统监控到定时时间到应用程序触发WM_TIMER消息应用程序响应WM_TIMER消息(即执行WM_TIMER相应的响应函数)应用程序响应其他消息或执行其它的操作WM_TIMER方式定时的工作原理返回参数说明:nIDEvent:非0值标识Timer的id。nElapse:以毫秒为单位的定时间隔时间lpfnTimer指向定时事件到达时调用的函数的指针,如果为NULL,那么调用OnTimer()1)SetTimer()功能:设置定时间隔并启动定时器。函数原型:UINTSetTimer(UINTnIDEvent,UINTnElapse,void(CALLBACKEXPORT*lpfnTimer)(HWND,UINT,UINT,DWORD));例:SetTimer(1,200,NULL)设置并启动一个时间间隔为200ms的定时器。消息响应函数为OnTimer()2、使用WM_TIMER消息需要用到的函数返回功能:取消定时器,此函数调用后,相应的定时器将被关闭不再起作用。参数:用SetTimer()函数创建的定时器标识。定时器使用总结:1、在WM_CREATE消息中启动定时器(SetTimer)2、在WM_TIMER消息中编写定时函数(即需要周期性完成的工作)3、在定时工作完成之后关闭/停止定时器。(可选)例:SetTimer(2,1000,TimerProc);设置并启动一个实间间隔为1s的定时器,该定时器的响应函数为TimerProc。2)KillTimer(1)返回3、程序示例4.1程序设计目标:设计一个定时器程序,窗口内显示的数字每隔100毫秒自动加1。程序设计步骤:1、生成应用程序框架(基于对话框TimerSample)。2、编辑对话框资源。3、添加定时器消息响应函数。4、添加定时器消息响应代码。5、增加启动和停止定时器的按钮消息响应函数。返回步骤1生成应用程序框架4.1步骤2:编辑对话框资源。在对话框上增加一个编辑框和两个按钮,控件属性如下:CaptionID关联变量----------IDC_EDIT1m_Edit1启动定时器IDC_BUTTONSTARTTIMER停止定时器IDC_BUTTONKILLTIMER选择基于对话框的程序,名称为TimerSample。返回步骤3添加WM_TIMER的消息响应函数(略)步骤4添加定时器消息响应代码。voidCTimerSampleDlg::OnTimer(UINTnIDEvent){m_Edit1=m_Edit1+1;UpdateData(FALSE);//将变量的值送给控件显示。CDialog::OnTimer(nIDEvent);}返回voidCTimerSampleDlg::OnButtonkilltimer(){KillTimer(1);}voidCTimerSampleDlg::OnButtonstarttimer(){SetTimer(1,100,NULL);}步骤5、增加启动和停止定时器的消息响应函数。返回程序运行效果WM_TIMER的缺点:1、精度低,最小计时精度大约为55ms(Win95),或10ms左右(Win2000/xp)2、定时器消息在多任务操作系统中的优先级较低,有时不能得到及时响应。(一旦计算机的CPU被某个进程占用,或系统资源紧张时,发送到消息队列中的消息就暂时被挂起,WM_TIMER消息得不到及时处理。)返回3.2.3多媒体定时器1、针对前两种定时器的缺点,MicroSoft公司提供了一种精度更高的定时器——多媒体定时器。优点:(1)精度较高:多媒体定时器最小误差为1毫秒。(2)优先级较高,可以减轻资源紧张对定时器运行的影响。返回timeSetEvent函数功能:设置并启动一个多媒体定时器。函数原型:MMRESULTtimeSetEvent(UINTuDelay,UINTuResolution,LPTIMECALLBACKlpTimeProc,WORDdwUser,UINTfuEvent)函数头文件:#includemmsystem.h2、多媒体定时器的使用返回参数说明:FuEvent:指定定时器事件类型:TIME_ONESHOT:uDelay毫秒后只产生一次事件。TIME_PERIODIC:每隔uDelay毫秒周期性地产生事件。uDelay:以毫秒指定时的周期Uresolution:以毫秒指定延时的精度,数值越小定时器事件分辨率越高。缺省值为1ms。LpTimeProc:指向一个回调函数,该回调函数包含需要定时执行的代码。DwUser:存放用户提供的回调数据。MMRESULTtimeSetEvent(UINTuDelay,UINTuResolution,LPTIMECALLBACKlpTimeProc,WORDdwUser,UINTfuEvent)返回2、使用举例1)在TimerSample程序的主窗口上增加一个编辑控件程序功能:实现窗口内数字每隔100毫秒自动加1。返回2)在对话框的头文件中定义代码classCTimerSampleDlg:publicCDialog{…….staticvoidCALLBACKTimeProc(UINTuID,UINTuMsg,DWORDdwUser,DWORDdw1,DWORDdw2);//定时器回调函数intTimerID;//定时器ID…….};注意:使用多媒体定时器必须指明回调函数。返回voidCTimerSampleDlg::OnButtonstarttimer(){TimerID=timeSetEvent(100,1,LPTIMECALLBACK)TimeProc,0,TIME_PERIODIC);//新加代码SetTimer(1,100,NULL);//原来代码}3)在OnButtonstarttimer添加启动多媒体定时器的语句返回4)编写回调函数代码voidCALLBACKCTimerSampleDlg::TimeProc(UINTuID,UINTuMsg,DWORDdwUser,DWORDdw1,DWORDdw2){m_Cal=m_Cal+1;}回调函数参数说明:uID——定时器标识,其值和TimerID一致。uMsg,dw1,dw2保留参数,目前不起作用dWUser——存放用户的回调数据。5)在OnTimer中增加代码显示Cal的值。voidCTimerSampleDlg::OnTimer(UINTnIDEvent){m_Edit1=m_Edit1+1;m_Edit2=m_Cal;//添加的代码UpdateData(FALSE);CDialog::OnTimer(nIDEvent);}返回4.1程序运行结果返回4.11、使用GetTickCount函数2、使用QueryPerformanceFrequency()和QueryPerformanceCounter()函数。3.3其它定时方法在精度要求较高的情况下,如要求定时误差不大于1ms时,还可以利用GetTickCount()函数返回自计算机启动后的时间,该函数的返回值是DWORD型,表示以ms为单位的计算机启动后经历的时间间隔。通过两次调用GetTickCount()函数,然后控制它们的差值来取得定时效果。.下列的代码可以实现50ms的精确定时,其误差是毫秒级的。返回4.13、使用QueryPerformanceFrequency()和QueryPerformanceCounter()函数对于更精确的定时操作,使用QueryPerformanceFrequency()和QueryPerformanceCounter()函数。这两个函数是VisualC++提供并且仅供Windows95及其后续版本使用,其精度与CPU的时钟频率有关,它们要求计算机从硬件上支持精确定时器。QueryPerformanceFrequency()函数和QueryPerformanceCounter()函数的原型如下:BOOLQueryPerformanceFrequency(LARGE_INTEGER*lpFrequency);BOOLQueryPerformanceCounter(LARGE_INTEGER*lpCount);返回使用QueryPerformanceFrequency()和QueryPerformanceCounter()函数进行精确定时的步骤如下:1、首先调用QueryPerformanceFrequency()函数取得高精度运行计数器的频率f,单位是每秒多少次(n/s),此数一般很大;2、在需要定时的代码的两端分别调用QueryPerformanceCounter()以取得高精度运行计数器的数值n1、n2,两次数值的差值通过f换算成时间间隔,t=(n2-n1)/f,当t大于或等于定时时间长度时,启动定时器;返回