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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

多媒体定时器

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

一、簡介

在工業生產控制系統中,有許多需要定時完成的操作,如數據采集程序。Win32提供了一個基于消息機制的定時器,使用SetTimer函數創建一個內存對象,設定間隔時間,當到達要求的間隔時,計時器對象發送一個WM_TIMER消息,由相應函數處理。但是由于WM_TIMER優先級低,只有等待消息隊列中的其他消息都處理完畢后系統才會響應該消息。而且消息隊列中的多個WM_TIMER會被合并,因此Win32定時器的精度低,不能滿足工業實時控制系統的要求。

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

多媒體定時器相關API如下:

MMRESULTtimeGetDevCaps(

??? LPTIMECAPSptc,

??? UINTcbtc??????

??? );

函數功能:獲取定時器設備能力

參數:ptc指向一個TIMECAPS型的結構,TIMECAPS有兩個成員,wPeriodMin和WperiodMax,表示定時器設備支持的最小時間周期和最大時間周期;cbtc表示TIMECAPS結構的大小

MMRESULTtimeBeginPeriod(

??? UINTuPeriod

??? );

函數功能:設置定時器設備的最小時間分辨率

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

MMRESULTtimeEndPeriod(

??? UINTuPeriod

??? );

函數功能:清除之前對定時器設備的設置

參數:timeBeginPeriod中指定的最小分辨率

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

MMRESULTtimeSetEvent(

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

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

??? LPTIMECALLBACKlpTimeProc,

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

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

??? );

函數功能:創建并初始化定時器事件,給定定時器回調函數的入口地址

參數:

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

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

LpTimeProc:定時器觸發的事件的回調函數的地址

dwUser:傳遞給回調函數的數據

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

MMRESULTtimeKillEvent(

??? UINTuTimerID

??? );

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

參數:指向要刪除的定時器事件的ID

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

函數功能:回調函數

參數:uID,多媒體定時器的ID,ID值由timeSetEvent創建定時器事件時返回

uMsg,保留,當前未使用

dwUser,由timeSetEvent傳遞的用戶數據

dw1,dw2保留未使用

二、實現

本程序將多媒體定時器封裝成一個類MMTimer,下面是核心代碼:

#pragma once #include <mmsystem.h> #pragma comment(lib,"winmm.lib") typedef void (*TIMERCALLBACK)(DWORD); //函數的指針 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定時器的精度,我們實現了一個測試軟件,即定時器指定一個時間間隔(單位:ms),再測試出真實的時間間隔(采用高精度計時函數QueryPerformanceFrequency和QueryPerformanceCounter),下面是測試結果,可以發現win32定時器設定1ms間隔,但實際時間間隔為15.6ms,而多媒體定時器設定1ms,真實的時間間隔就是1ms 。

三、相關問題

(1)如何在回調函數中調用類內成員

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

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

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

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

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

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

在VS中加斷點調試,并選擇調試->窗口->線程,可以發現當開啟一個定時器后,會出現一個工作線程


更正-----2017.1.15

多媒體定時器回調函數應更正為:

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

timeSetEvent調用時也相應做更改:


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

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



同樣的Win32定時器回調函數第三個參數也應該為UINT_PTR才能在x64下編譯通過。


源碼已更新!


源碼下載


參考:

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

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



總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。