日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

多媒体定时器

發(fā)布時間:2023/12/15 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 多媒体定时器 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、簡介

在工業(yè)生產(chǎn)控制系統(tǒng)中,有許多需要定時完成的操作,如數(shù)據(jù)采集程序。Win32提供了一個基于消息機制的定時器,使用SetTimer函數(shù)創(chuàng)建一個內(nèi)存對象,設(shè)定間隔時間,當?shù)竭_要求的間隔時,計時器對象發(fā)送一個WM_TIMER消息,由相應(yīng)函數(shù)處理。但是由于WM_TIMER優(yōu)先級低,只有等待消息隊列中的其他消息都處理完畢后系統(tǒng)才會響應(yīng)該消息。而且消息隊列中的多個WM_TIMER會被合并,因此Win32定時器的精度低,不能滿足工業(yè)實時控制系統(tǒng)的要求。

本文將介紹一種精度較高的多媒體定時器,該定時器并不依賴于消息機制,可以實現(xiàn)1ms的定時精度。由于多媒體定時器另外開辟一個獨立線程執(zhí)行定時器回調(diào)函數(shù),因此當回調(diào)函數(shù)耗時較多時并不會導(dǎo)致UI的“假死”,相對而言,Win32定時器隸屬于主線程,一旦定時器回調(diào)函數(shù)耗時較多,就會導(dǎo)致UI的“假死”。

多媒體定時器相關(guān)API如下:

MMRESULTtimeGetDevCaps(

??? LPTIMECAPSptc,

??? UINTcbtc??????

??? );

函數(shù)功能:獲取定時器設(shè)備能力

參數(shù):ptc指向一個TIMECAPS型的結(jié)構(gòu),TIMECAPS有兩個成員,wPeriodMin和WperiodMax,表示定時器設(shè)備支持的最小時間周期和最大時間周期;cbtc表示TIMECAPS結(jié)構(gòu)的大小

MMRESULTtimeBeginPeriod(

??? UINTuPeriod

??? );

函數(shù)功能:設(shè)置定時器設(shè)備的最小時間分辨率

參數(shù):最小時間分辨率,以毫秒為單位

MMRESULTtimeEndPeriod(

??? UINTuPeriod

??? );

函數(shù)功能:清除之前對定時器設(shè)備的設(shè)置

參數(shù):timeBeginPeriod中指定的最小分辨率

注:timeBeginPeriod和timeEndPeriod必須配對存在,并且指定的參數(shù)值也相同。

MMRESULTtimeSetEvent(

??? UINT??????????uDelay,????

??? UINT??????????uResolution,

??? LPTIMECALLBACKlpTimeProc,

??? DWORD_PTR?????dwUser,????

??? UINT??????????fuEvent????

??? );

函數(shù)功能:創(chuàng)建并初始化定時器事件,給定定時器回調(diào)函數(shù)的入口地址

參數(shù):

uDelay:定時器觸發(fā)的時間間隔,以毫秒為單位

uResolution:定時器設(shè)備的時間精度,以毫秒為單位,應(yīng)大于或等于timeBeginPeriod中設(shè)置的值,默認為1ms,精度越高,系統(tǒng)在定時器上的負載就越大,通常選擇適合于應(yīng)用程序的最大值

LpTimeProc:定時器觸發(fā)的事件的回調(diào)函數(shù)的地址

dwUser:傳遞給回調(diào)函數(shù)的數(shù)據(jù)

fuEvent:定時類型,TIME_ONESHOT表示uDelay毫秒后只產(chǎn)生一次事件,TIME_PERIODIC表示每隔uDelay毫秒周期性的產(chǎn)生事件

MMRESULTtimeKillEvent(

??? UINTuTimerID

??? );

函數(shù)功能:刪除一個指定的定時器事件

參數(shù):指向要刪除的定時器事件的ID

void CALLBACKTimeProc(UINTuID,UINTuMsg,DWORDdwUsers,DWORDdw1,DWORDdw2);

函數(shù)功能:回調(diào)函數(shù)

參數(shù):uID,多媒體定時器的ID,ID值由timeSetEvent創(chuàng)建定時器事件時返回

uMsg,保留,當前未使用

dwUser,由timeSetEvent傳遞的用戶數(shù)據(jù)

dw1,dw2保留未使用

二、實現(xiàn)

本程序?qū)⒍嗝襟w定時器封裝成一個類MMTimer,下面是核心代碼:

#pragma once #include <mmsystem.h> #pragma comment(lib,"winmm.lib") typedef void (*TIMERCALLBACK)(DWORD); //函數(shù)的指針 class MMTimer { public:MMTimer();~MMTimer();bool Start(UINT Delay,UINT Resolution,TIMERCALLBACK lpTimeProc,DWORD fParam);void Stop(); private:bool m_RunningFlag;UINT m_ID;UINT m_Delay;TIMERCALLBACK m_pfCallback;DWORD m_Fparam;static void CALLBACK TimeProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2); }; #include "stdafx.h" #include "MMTimer.h" MMTimer::MMTimer() {m_pfCallback=NULL;m_Fparam=0;m_RunningFlag=false;m_Delay=0;m_ID=0; }MMTimer::~MMTimer() {if (m_RunningFlag){Stop();} } void MMTimer::TimeProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) {MMTimer *ptimer=(MMTimer*)dwUser;(ptimer->m_pfCallback)(ptimer->m_Fparam); }bool MMTimer::Start(unsigned int Delay,unsigned int Resolution,TIMERCALLBACK lpTimeProc,DWORD fParam) {bool Result = true;if (!m_RunningFlag){m_pfCallback=lpTimeProc;m_Fparam=fParam;if ((m_ID=timeSetEvent(Delay,Resolution,TimeProc,(DWORD)(this), TIME_PERIODIC))!=NULL){m_RunningFlag=true;}else{Result=false;}}return Result; }void MMTimer::Stop() {if (m_RunningFlag){timeKillEvent(m_ID);m_RunningFlag=false;} }

為了對比多媒體定時器與Win32定時器的精度,我們實現(xiàn)了一個測試軟件,即定時器指定一個時間間隔(單位:ms),再測試出真實的時間間隔(采用高精度計時函數(shù)QueryPerformanceFrequency和QueryPerformanceCounter),下面是測試結(jié)果,可以發(fā)現(xiàn)win32定時器設(shè)定1ms間隔,但實際時間間隔為15.6ms,而多媒體定時器設(shè)定1ms,真實的時間間隔就是1ms 。

三、相關(guān)問題

(1)如何在回調(diào)函數(shù)中調(diào)用類內(nèi)成員

void CALLBACKTimeProc(UINTuID,UINTuMsg,DWORDdwUsers,DWORDdw1,DWORDdw2);

可以將TimeProc聲明為全局函數(shù),但通常會將其放入類中,如本程序就將其放入MMTimer類中。此時需要將其聲明為static類型(因為非靜態(tài)成員函數(shù)的指針與靜態(tài)成員函數(shù)的指針是不同的,主要是由于非靜態(tài)成員函數(shù)的參數(shù)中隱含一個this指針,導(dǎo)致函數(shù)指針的類型不匹配)。

然而將TimeProc聲明為static,它只能訪問類中的靜態(tài)成員(變量與函數(shù)),這里的解決方法是利用參數(shù)dwUsers,改參數(shù)對應(yīng)timeSetEvent中的dwUser,我們將自定義類MMTime的this指針作為參數(shù)傳進TimeProc函數(shù)中:

timeSetEvent(Delay,Resolution,TimeProc,(DWORD)(this),TIME_PERIODIC)

然后在TimeProc中使用該this指針就可以調(diào)用類中的任意成員。

(2)多媒體定時器屬于多線程的驗證如下:

在VS中加斷點調(diào)試,并選擇調(diào)試->窗口->線程,可以發(fā)現(xiàn)當開啟一個定時器后,會出現(xiàn)一個工作線程


更正-----2017.1.15

多媒體定時器回調(diào)函數(shù)應(yīng)更正為:

typedef void (CALLBACKTIMECALLBACK)(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1,DWORD_PTR dw2);

timeSetEvent調(diào)用時也相應(yīng)做更改:


DWORD_PTR是DWORD型指針,其字節(jié)數(shù)與sizeof(void*)相同,我們都知道,sizeof(void*)大小是平臺相關(guān)的。在VS中將解決方案平臺設(shè)為Win32,sizeof(void*)=4,設(shè)為X64,則sizeof(void*)=8.

故之前用DOWRD類型傳遞指針是存在極大風(fēng)險的,在X64下指針為8字節(jié)但DWORD只有4字節(jié),這樣就可能出現(xiàn)如下運行錯誤:



同樣的Win32定時器回調(diào)函數(shù)第三個參數(shù)也應(yīng)該為UINT_PTR才能在x64下編譯通過。


源碼已更新!


源碼下載


參考:

[1]http://www.cnblogs.com/liuhao2638/archive/2013/06/13/3134109.html

[2] http://www.codeproject.com/Articles/1236/Timers-Tutorial



總結(jié)

以上是生活随笔為你收集整理的多媒体定时器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。