|
本帖最后由 liucqa 于 2012-11-17 16:08 编辑
timeSetEvent与Settimer的区别是前者是内核模式在新的线程上工作,timeSetEvent会生成一个独立的Timer回调线程。
Settimer为用户模式,性能会好些?
在timeSetEvent调用中设置定时器回调函数时要遵循其规则,即回调函数的定义要严格遵照MSDN中的格式,而且在回调函数中除了PostMessage、timeGetSystemTime、timeGetTime、timeSetEvent、timeKillEvent、midiOutShortMsg、midiOutLongMsg、OutputDebugString几个函数外,不能调用其他Windows API函数,否则易造成系统出错甚至崩溃,故在实际运用中,使用要特别小心。
Option Explicit
Public Declare Function timeSetEvent Lib "winmm.dll" (ByVal uDelay As Long, ByVal uResolution As Long, ByVal lpFunction As Long, ByVal dwUser As Long, ByVal uFlags As Long) As Long
Public Declare Function timeKillEvent Lib "winmm.dll" (ByVal uID As Long) As Long
Public Declare Function Beep Lib "kernel32.dll" (ByVal dwFreq As Long, ByVal dwDuration As Long) As Long
Public lTimeID As Integer
Public lTimeID2 As Integer
Public n&, m&
Public busy1 As Boolean
Public busy2 As Boolean
'timeSetEvent (ByVal uDelay As Long, ByVal uResolution As Long, ByVal lpFunction As Long, ByVal dwUser As Long, ByVal uFlags As Long) As Long
'该函数的参数说明如下:
'参数uDelay表示延迟时间;
'参数uResolution表示时间精度,在Windows中缺省值为1ms;
'参数lpFunction表示回调函数,为用户自定义函数,定时调用;
'参数dwUser表示用户提供的回调数据;
'参数uFlags为定时器的事件类型,TIME_ONESHOT=0表示执行一次;TIME_PERIODIC=1:周期性执行。
'具体应用时,可以通过调用timeSetEvent()函数,将需要周期性执行的任务定义在lpTimeProc回调函数中,从而完成所需处理的事件?
'特别需要注意的是: 任务处理的时间不能大于周期间隔时间?!!
'另外,在定时器使用完毕后,应及时调用timeKillEvent()将之释放。
Public Sub startATimer()
busy1 = False
busy2 = False
lTimeID2 = timeSetEvent(2000, 1, AddressOf TimeProc, 1, 1) '注意定时器的时间要长于回调函数的执行时间
If lTimeID2 = 0 Then
MsgBox "cannot excute timesetevent2"
End If
lTimeID = timeSetEvent(3000, 0, AddressOf TimeProcAcq, 1, 1) '如果短了会造成后继的代码无法执行,例如启动第二个计时器或者终止计时器
If lTimeID = 0 Then
MsgBox "cannot excute timesetevent"
End If
End Sub
Sub TimeProcAcq(ByVal uID As Long, ByVal uMsg As Long, ByVal dwUser As Long, ByVal dw1 As Long, ByVal dw2 As Long) '回调函数的固定格式,不能自行更改,且只能是sub
If busy1 Then Exit Sub
busy1 = True
Beep 659, 200
m = m + 1
[a2] = Timer & "|" & uID & "|" & uMsg & "|" & dwUser & "|" & dw1 & "|" & dw2
busy1 = False
End Sub
Sub TimeProc(ByVal uID As Long, ByVal uMsg As Long, ByVal dwUser As Long, ByVal dw1 As Long, ByVal dw2 As Long)
If busy2 Then Exit Sub
busy2 = True
Beep 1059, 200
n = n + 1
[a1] = Timer & "|" & uID & "|" & uMsg & "|" & dwUser & "|" & dw1 & "|" & dw2
busy2 = False
End Sub
Public Sub stopSTimer()
If lTimeID Then timeKillEvent (lTimeID)
If lTimeID2 Then timeKillEvent (lTimeID2)
Exit Sub
End Sub
使用多媒体定时器应遵循以下3个步骤:
1. 确定最大和最小周期
可以用timeGetDevCaps函数确定多媒体定时器服务提供的最大和最小定时器事件周期,这些数值对不同的计算机是不同的,也与Windows运行方式有关。
2. 建立最小定时器精度
在启动定时器事件前,应用程序必须建立想要使用的最小定时器精度,在定时器服务事件结束之后,还必须清除该精度。
最小定时器精度可以根据第一步返回的结果确定。可以使用timeBeginPeriod和timeEndPeriod函数来设置和清除最小定时器精度,每个timeBeginPeriod调用都必须有一个timeEndPeriod与之对应,而且两个函数必须指定相同的最小精度。
3. 启动定时器事件
与该步骤相关的两个函数为timeSetEvent和timeKillEvent,详细细节可以查阅MSDN中这两个函数的定义。有三个要注意的地方:
一是一旦启动定时器就一定不要忘记把它关闭,因为小于100毫秒的定时器对CPU 的消耗是非常大的,而且下次启动定时器会造成多个定时器同时运行,使得数据采集的结果是错误的;
二是在timeSetEvent调用中设置定时器回调函数时要遵循其规则,即回调函数的定义要严格遵照MSDN中的格式,而且在回调函数中除了PostMessage、timeGetSystemTime、timeGetTime、timeSetEvent、timeKillEvent、midiOutShortMsg、midiOutLongMsg、OutputDebugString几个函数外,不能调用其他Windows API函数,否则易造成系统出错甚至崩溃;
三是回调函数应编写得短小精悍,因为定时器事件发生的周期非常短,程序很长会造成延时,影响数据采集的实时性。
|
|