精华内容
下载资源
问答
  • 大家在开发过程中,经常遇到需要定时的功能,特别是在工业控制方面,需要高精度毫秒级定时器,而VS提供的这三种定时器,都不够准确 1.定义在System.Windows.Forms里 2.定义在System.Threading.Timer类里 3.定义在...
  • 毫秒级定时器

    千次阅读 2009-12-23 10:31:00
    1. windows平台用微软提供的多媒体定时器。2. linux平台用select方案。 多媒体定时器方案: Visual C++中提供了很多关于时间操作的函数,利用它们控制程序能够精确地完成定时和计时操作。Visaul C++中的WM_TIMER...

    1.       windows平台用微软提供的多媒体定时器。

    2.       linux平台用select方案。

     

      多媒体定时器方案

       Visual C++中提供了很多关于时间操作的函数,利用它们控制程序能够精确地完成定时和计时操作。Visaul C++中的WM_TIMER消息映射能进行简单的时间控制。首先调用函数SetTimer()设置定时间隔(退出程序时别忘了调用和SetTimer()配对使用的KillTimer()函数),如SetTimer(0,200,NULL)即为设置200ms的时间间隔。然后在应用程序中增加定时响应函数OnTimer(),并在该函数中添加响应的处理语句,用来完成到达定时时间的操作。这种定时方法非常简单,但其定时功能如同Sleep()函数的延时功能一样,精度非常低,只可以用来实现诸如位图的动态显示等对定时精度要求不高的情况。

      微软公司在其多媒体Windows中提供了精确定时器的底层API支持。利用多媒体定时器可以很精确地读出系统的当前时间,并且能在非常精确的时间间隔内完成一个事件、函数或过程的调用。利用多媒体定时器的基本功能,可以通过两种方法实现精确定时。1)使用timeGetTime()函数,该函数定时精度为ms级,返回从Windows启动开始所经过的时间。由于使用该函数是通过查询的方式进行定时控制的,所以,应该建立定时循环来进行定时事件的控制。2)使用timeSetEvent()函数,该函数原型如下:

     

     

    MMRESULT timeSetEvent(UINT uDelayUINT uResolutionLPTIMECALLBACK lpTimeProcDWORD dwUserUINT fuEvent)

     

     

    该函数的参数说明如下:参数uDelay表示延迟时间;参数uResolution表示时间精度,在Windows中缺省值为1mslpTimeProc表示回调函数,为用户自定义函数,定时调用; 参数dwUser表示用户提供的回调数据;参数fuEvent为定时器的事件类型,TIME_ONESHOT表示执行一次;TIME_PERIODIC:周期性执行。具体应用时,可以通过调用timeSetEvent()函数,将需要周期性执行的任务定义在lpTimeProc回调函数中(如:定时采样、控制等),从而完成所需处理的事件。需要注意的是:任务处理的时间不能大于周期间隔时间。另外,在定时器使用完毕后,应及时调用timeKillEvent()将之释放。

     

     

    #ifdef WIN32

        if (NULL != g_TimerID)

        {

            MMRESULT ret;

            ret = timeKillEvent(g_TimerID);

            if (TIMERR_NOERROR != ret)

            {           

                g_debug("timeKillEvent failed.");

            }

            else

            {

                g_TimerID = NULL;    

            }

        } 

       

        {

            g_TimerID = timeSetEvent(40, 1,    //40毫秒

                (LPTIMECALLBACK) DoProcess,

                (DWORD)this,TIME_PERIODIC);

           

            if (NULL == g_TimerID)

            {

                g_debug("create mm timer failed.");

            }

        }   

    #endif

     

     

     

    select方案:  

     

    struct timeval tv;

        struct sched_param task_param;   

        //提高优先级

        task_param.sched_priority = 80;

       

        if( pthread_setschedparam(pthread_self(), SCHED_FIFO, &task_param) )

        {

            g_debug("set task priority failed: %s/n", strerror(errno));

        }

     

        BOOL32 bActive = TRUE;

       

        while(bActive)

        {       

          

            bActive = GetActiveStatus();

     

            //定时器

            for (l32 i = 0; i < 40; i++)  //40毫秒

            {

                tv.tv_sec = 0;  

                tv.tv_usec = 1000;          

                select(0, NULL, NULL, NULL, &tv); 

            }       

               

            g_mutex_lock((GMutex*)(ptLock));

            g_cond_signal((GCond*)(ptCond));

            g_mutex_unlock((GMutex*)(ptLock));                

        }

     

     

     

    Select方案关键点:  

    1)      select作定时器要单独起线程并且提高线程优先级。

    2)      线程中除了给信号不做其它任何有负载的工作。

    3)      Select语句要用循环实现。

     

     

    内核信息:

    Linux localhost.localdomain 2.6.18-8.el5 #1 SMP Thu Mar 15 19:57:35 EDT 2007 i68

     

    展开全文
  • 定时器功能:用户指定时间间隔和回调函数,每隔一段时间判断是否经过设定间隔,若是,执行回调函数。定时器共两个类型,DelayCall仅用于一次调用,AddTimer用于循环调用。 类型定义: /* 定时器 */ class Timer...

    本文的重点还是类的实现,获取本地时间的WINAPI是GetLocalTime(),程序中仅此一个与平台相关的系统函数。
    定时器功能:用户指定时间间隔和回调函数,每隔一段时间判断是否经过设定间隔,若是,执行回调函数。定时器共两个类型,DelayCall仅用于一次调用,AddTimer用于循环调用。
    类型定义:

    /*  定时器 */
    class Timer{
        friend class TimerMgr;
    protected:
        TimerIdType nTimerId;
        unsigned short nInterval;
        CallBackType emCallBackType;
        vector<void *> vCallBack;   //用于传参,第一个元素是函数指针,之后是该函数的参数指针
        TimerType emTimerType;
    
        unsigned short  lastMillSec;        //上次计时的毫秒数
        inline unsigned short _getLastMillSec(){ return lastMillSec; }
        inline void _setLastMillSec(unsigned short lastMillSec_arg){ lastMillSec = lastMillSec_arg; }
        Timer(  TimerIdType nTimerId_arg,
                unsigned short nInterval_arg, 
                CallBackType emCallBackType_arg, 
                vector<void *>vCallBack_arg, 
                TimerType emTimerType_arg = AddTimer
                ) 
                :nTimerId(nTimerId_arg), 
                 nInterval(nInterval_arg), 
                 emCallBackType(emCallBackType_arg), 
                 vCallBack(vCallBack_arg),
                 emTimerType(emTimerType_arg)
                 {
                     SYSTEMTIME sys;
                     GetLocalTime(&sys);
                     lastMillSec = sys.wMilliseconds;
                }
    public:
        ~Timer(){}
    
        inline TimerIdType getTimeId(){ return nTimerId; }
        inline unsigned short getInterval(){ return nInterval; }
        inline TimerType getTimerType(){ return emTimerType; }
        pair<bool, bool> Update(){ return CallBack(emCallBackType, vCallBack); }
    
    };
    
    
    
    class TimerMgr{
    protected:
        static TimerMgr * pTimerMgrInstance;
    
        typedef unsigned int BitArrayType;  //暂时最多能注册32个定时器
    #define TimerMaxNum (sizeof(BitArrayType) << 3)
    
        list<Timer *>   l_TimerList;
        BitArrayType    i_BitArray;         //每位的0/1值表示TimerId的占用情况
    
        class { //以时间间隔为升序排序标准,设计为嵌套类防止命名污染
        public:
            inline bool operator()(Timer* pTimer1, Timer* pTimer2)
            {
                return pTimer1->getInterval() < pTimer2->getInterval();
            }
        }   SortByInterval;
    
        TimerMgr() :i_BitArray(0){}
    
        /*  获取空闲定时器ID   */
        TimerIdType _getIdleTimerId();
        unsigned short _getEachTimerInterval(unsigned short now, unsigned short last);
        inline list<Timer *>::iterator _closeTimerByIter(list<Timer *>::iterator iter){ return l_TimerList.erase(iter); }
    public:
        ~TimerMgr();
        static TimerMgr * GetTimerMgrInstance();
    
        inline size_t getTimerNum(){ return l_TimerList.size(); }
    
        TimerIdType Register(unsigned short nInterval_arg,
                            CallBackType emCallBackType_arg,
                            vector<void *>vCallBack_arg,
                            TimerType emTimerType_arg = AddTimer
                            );
        void CloseTimerById(TimerIdType nTimerId);
        map<TimerIdType, pair<bool, bool> > Update();
    };

    Timer就是一个具体的定时器,里边的数据成员有定时器id、时间间隔、回调函数类型、回调函数(及参数)的指针、定时器类型和上次计时的毫秒数。回调函数的调用是通过将函数指针和参数指针传入到一个vector中,根据回调函数类型来决定调用方法。其中用到了自己写的另两个文件commonfunc.h和commonfunc.c。
    设计一个TimerMgr来管理所有的Timer。使用单例模式保证程序中该类型只有一个对象。TimerMgr中的数据成员有包含所有注册的Timer指针的List、表示TimerId占用情况的BitArray和用于list排序的嵌套类型函数对象。

    设计思想:一个程序中的唯一TimerMgr实例维护一个列表,管理所有注册的Timer。Timer每次注册在TimerMgr中时,都会在BitArray中从低到高找一个空闲位标记,该位的编号为此定时器的ID。TimerMgr在Update方法中遍历列表,若历经时间到达时间间隔,则执行回调函数。若是一次性的定时器,回调函数执行完即删除该定时器,删除后BitArray中的该位置为空闲。

    TimerMgr的操作细节:

    /*
     * 用于获取空闲的定时器ID。
     * 在定时器个数还没饱和的情况下,在32位二进制中找第一个为0的位,
     * 该位的下标号就是空闲的定时器ID。
     * 说起来找二进制第一个1/0这样的问题有比循环的时间复杂度更低的方法,
     * 但是要么运用的数学原理过于高深,要么使用汇编指令bsf、bsr之类的。
     */
    TimerIdType TimerMgr::_getIdleTimerId()
    {
        unsigned char i = 0;
        for (; i_BitArray & (1 << i); i++);
        return i;
    }
    
    
    /*
     * 用于注册一个定时器。
     * 跳过一些检查语句,首先会获取空闲TimerId,然后将该位置位。
     * 动态分配Timer对象,将其放入TimerList。
     * 最后对List排序,排序规则是按照时间间隔的升序排序。这样方便遍历的
     * 的时候优先运行时间间隔小的定时任务。排序时传入可调用对象
     * SortByInterval,它是TimerMgr的嵌套类对象,仅类内可见且不影响
     * 外界命名。
     */
    TimerIdType TimerMgr::Register( unsigned short nInterval_arg,
                                    CallBackType emCallBackType_arg,
                                    vector<void *>vCallBack_arg,
                                    TimerType emTimerType_arg /* = AddTimer */
                                    )
    {
        if (getTimerNum() >= TimerMaxNum){
            cout << "[TimerMgr] can't register timer, there is no idle timer id ." << endl;
            return _TIMER_INVALID_VAL;
        }
    
        if (emCallBackType_arg >= emCallBackNum){
            cout << "[TimerMgr] can't register timer, CallBackType is invalid." << endl;
            return _TIMER_INVALID_VAL;
        }
    
        if (emTimerType_arg >= TimerTypeNum){
            cout << "[TimerMgr] can't register timer, TimerType is invalid." << endl;
            return _TIMER_INVALID_VAL;
        }
    
        TimerIdType newId = _getIdleTimerId();
        i_BitArray |= (1 << newId); //置位
        Timer * pTimer = new Timer(newId, nInterval_arg, emCallBackType_arg, vCallBack_arg, emTimerType_arg);
        l_TimerList.push_back(pTimer);
        l_TimerList.sort(SortByInterval);   //按照时间间隔排序
    
        return newId;
    }
    
    
    /*
     * 若到达时间间隔,执行所有定时器的回调函数并更新上次运行时间。
     * 返回类型是定时器ID和函数运行结果。
     * 首先获取当前时间,遍历定时器列表,若有时间间隔到达回调标准的定时
     * 器任务则执行并将结果记录以便返回。然后判断定时器类型,若是一次性
     * 的则删除这个节点,iter指向下一个节点。若刚删的节点是尾节点,则
     * 跳出循环。否则更新定时器时间基准。
     */
    map<TimerIdType, pair<bool, bool> > TimerMgr::Update()
    {
        map<TimerIdType, pair<bool, bool> > m_CallBackResults;
        SYSTEMTIME sys;
        GetLocalTime(&sys);
        auto iter = l_TimerList.begin();
        for (; iter != l_TimerList.end(); iter++)
        {
            if (_getEachTimerInterval(sys.wMilliseconds, (*iter)->_getLastMillSec()) >= (*iter)->getInterval())
            {
                cout << (int)(*iter)->getTimeId() << '\t';
    
                m_CallBackResults[(*iter)->getTimeId()] = (*iter)->Update();
                if ((*iter)->getTimerType() == DelayCall)   //删掉一次性的定时任务
                {
                    //CloseTimerById((*iter)->getTimeId()); //不能用这个
                    iter = _closeTimerByIter(iter);
                    if (iter == l_TimerList.end())          //刚才删除的节点为尾节点
                        break;
                    continue;
                }
                (*iter)->_setLastMillSec(sys.wMilliseconds);        //更新时间基准
            }
        }
        return m_CallBackResults;
    }
    
    
    
    /*
     * 主函数测试用例。
     * 这个定时器类是主函数循环更新的,没写成异步驱动。
     */
    int main(void)
    {   
        vector<void *> v1, v2;
        v1.push_back(fun1);
        v2.push_back(fun2);
    
        TimerMgr::GetTimerMgrInstance()->Register(999, emCallBack0_void, v1, DelayCall);
        TimerMgr::GetTimerMgrInstance()->Register(500, emCallBack0_void, v2, DelayCall);
        TimerMgr::GetTimerMgrInstance()->Register(459, emCallBack0_void, v1, AddTimer);
        TimerMgr::GetTimerMgrInstance()->Register(550, emCallBack0_void, v2, DelayCall);
        TimerMgr::GetTimerMgrInstance()->Register(699, emCallBack0_void, v1, DelayCall);
        TimerMgr::GetTimerMgrInstance()->Register(300, emCallBack0_void, v2, AddTimer);
    
        while (true){
            TimerMgr::GetTimerMgrInstance()->Update();
        }
    
        system("pause");
        return 0;
    }
    

    这个定时器类可以放入中断处理函数,每隔几个时钟周期更新一次。
    完整内容在github中。
    https://github.com/castleKaoCK/C-Class—Millseconds-Timer.git

    展开全文
  • windows下的定时器

    2010-08-06 00:03:23
    windows下的settimer是一个毫秒级定时器,但是有时候我们需要更加精确的定时器功能,这个例子可以帮我们了解windows下的微妙级的定时器的用法
  • //精确时钟查询。  void TestHighTimer(void)  {  //  LARGE_INTEGER nFreq;  LARGE_INTEGER nLastTime1;  LARGE_INTEGER nLastTime2;    //获取是否支持精确定时器。  if
     //精确时钟查询。
      void TestHighTimer(void)
      {
             //
             LARGE_INTEGER nFreq;
             LARGE_INTEGER nLastTime1;
             LARGE_INTEGER nLastTime2;
     
             //获取是否支持精确定时器。
            if (QueryPerformanceFrequency(&nFreq))
             {
                   //
                   const int nBufSize = 256;
                   TCHAR chBuf[nBufSize];
            
                   //显示定时器的频率。
                   wsprintf(chBuf,_T("LastTime=%I64d/r/n"),nFreq);
                   OutputDebugString(chBuf);
     
                   //获取定时器的值。
                  QueryPerformanceCounter(&nLastTime1);
                   wsprintf(chBuf,_T("LastTime=%I64d/r/n"),nLastTime1);
                   OutputDebugString(chBuf);
                  
                   Sleep(0);
     
                   //获取定时器的值。
                  QueryPerformanceCounter(&nLastTime2);
                   wsprintf(chBuf,_T("LastTime=%I64d/r/n"),nLastTime2);
                   OutputDebugString(chBuf);
     
     
                   //计算时间是花费多少秒。
                   float fInterval = nLastTime2.QuadPart - nLastTime1.QuadPart;
                   swprintf(chBuf,nBufSize,_T("花费:%f/r/n"),fInterval/(float)nFreq.QuadPart);
                   OutputDebugString(chBuf);
             }
             
      }
    展开全文
  • Windows微秒定时方法

    千次阅读 2017-04-03 01:08:06
    在做硬件相关的程序时,需要... **C语言本身提供的睡眠或者定时器方法最小单位为毫秒级(据了解最小时间为30毫秒左右,而且不够精准),对于要求高精准的硬件程序通常需要微妙级甚至纳秒级的精度,而C语言提供的方法远

      在做硬件相关的程序时,需要大量的数据传输,当数据发送量大于设备接口接收量时会造成字节bit位覆盖的问题(比如单根串口线每次发送或者接收一个bit如果发送速度大于接收速度会造成前一个bit位被下一个bit位数据覆盖);
      C语言本身提供的睡眠或者定时器方法最小单位为毫秒级(据了解最小时间为30毫秒左右,而且不够精准),对于要求高精准的硬件程序通常需要微妙级甚至纳秒级的精度,而C语言提供的方法远远达不到要求;
    在这种情况下需要通过硬件支持高精度计数器来达到程序要求,通过查找相关资料及实践,封装了一个微秒级延时方法

      函数定义如下:

    int UsSleep(int us);//返回实际的微秒延时时间
    

      代码实现如下:

    //参数一表示 需要等待的时间 微秒为单位
    int UsSleep(int us)
    {
    	//储存计数的联合
    	LARGE_INTEGER fre;
    	//获取硬件支持的高精度计数器的频率
    	if (QueryPerformanceFrequency(&fre))
    	{
    		LARGE_INTEGER run,priv,curr,res;
    		run.QuadPart = fre.QuadPart * us / 1000000;//转换为微妙级
    		//获取高精度计数器数值
    		QueryPerformanceCounter(&priv);
    		do 
    		{
    			QueryPerformanceCounter(&curr);
    		} while (curr.QuadPart - priv.QuadPart < run.QuadPart);
    		curr.QuadPart -= priv.QuadPart;
    		int nres = (curr.QuadPart * 1000000 / fre.QuadPart);//实际使用微秒时间
    		return nres;
    	}
    	return -1;//
    }
    

      在实际的使用过程中方法时间误差在1微秒。

    展开全文
  • 虽然GetTickCount返回值的单位是1ms,但...Windows 内部有一个精度非常高的定时器, 精度在微秒, 但不同的系统这个定时器的频率不同, 这个频率与硬件和操作系统都可能有关。利用 API 函数 QueryPerformanceFrequ
  • 最近需要写一个微秒级的计时器,查了一圈,发现基本是毫秒级的计时器,如: HAL库中的HAL_GetTick(); C语言中的time()和clock();windows.h中的timeGetTime(),GetTickCount(),及QueryPerformanceCounter()(该函数...
  • 如果需要精度更高一些的定时器(精 确到1ms),可以使用下面的高精度多媒体定时器进行代码优化,可以达到毫秒级的精度,而且使用方便。先要包含头文件"mmsystem.h"和库文 件"winmm.lib"。 虽然Win95下可视化开发...
  • windows编程资料大全

    2008-10-26 13:55:44
    调用函数GetLastInputInfo()以后, 结构成员lpi.dwTime 中的值便是自上次输入事件发生以后的毫秒数。这个值也就是键盘、鼠标处于空闲状态的时间。可惜的是这个函数只能在Windows 2000中使用,Windows 9x 或Windows ...
  • SleepTest.zip

    2019-08-15 17:35:00
    Windows6种Sleep1毫秒的精度测试源码,vs2015可以直接编译运行 测试类别分别包括:  1、Windows中的原生Sleep  2、C++11的this_thread::sleep_for以及timeBeginPeriod调整定时器精度两个方式  3、socket连接的...
  • giCell zlg-gui

    2008-11-02 13:54:10
    支持毫秒级定时器,内核定时器周期为一毫秒; 17. 支持 X387/287 硬件浮点协处理器的任务状态保护,被动方式的任务浮点状态切换(开 中断执行,由于使用了特权指令实现,因此只能在纯DOS实模式下或虚拟机X386/X...
  • 如何获得毫秒级的系统时间 如何让定时器精确到毫秒 如何对当前的系统时间进行操作 如何获得和修改目录的日期和时间 第14章 数学算法 中文和英文字符所占的字节数是一样的吗 如何统计一段中英文混合字符的字符数 ...
  • SuperCx 是面向过程监控与工业自动化的 HMI/SCADA 软件开发平台(俗称组态软件),运行于Windows系统上,可以广泛应用于... 支持毫秒级时间打印。 支持直接调用Excel输出报表。 标签:SuperCxHMI
  • 易语言 茶凉专用模块

    2010-05-04 12:26:36
    参数 窗口句柄, 整数型, 可空, 为空则为系统级定时器(通常为空) .参数 时钟周期, 整数型, , 毫秒级单位 1秒=1000毫秒 .参数 定时器事件处理, 子程序指针, , 定时器触发事件 .子程序 创建多级目录, 逻辑型, 公开, ...
  • VC++/6.0编程范例大全

    热门讨论 2011-05-16 09:10:34
    实例038——使用定时器显示毫秒级的时间 第3章 实例039——创建和使用下压按钮、单选框和复选框 实例040——实现位图按钮,设定控件文本的字体 实例041——实现超链接风格的按钮 实例042——实现动画按钮 ...
  • Visual C++范例大全

    2012-07-18 13:02:34
    实例38:使用定时器显示毫秒级的时间 62 第二篇 VC基本程序开发要素 第3章 Windows基本控件的开发使用 65 3.1 按钮控件的使用 65 实例39:创建和使用下压按钮、单选框和复选框 65 实例40:实现位图按钮,设定控件...
  • 实例038——使用定时器显示毫秒级的时间 第3章 实例039——创建和使用下压按钮、单选框和复选框 实例040——实现位图按钮,设定控件文本的字体 实例041——实现超链接风格的按钮 实例042——实现动画按钮 ...
  • 实例038——使用定时器显示毫秒级的时间 第3章 实例039——创建和使用下压按钮、单选框和复选框 实例040——实现位图按钮,设定控件文本的字体 实例041——实现超链接风格的按钮 实例042——实现动画按钮...
  • C++范例大全(400)

    2013-06-29 21:23:07
    实例038——使用定时器显示毫秒级的时间 第3章 实例039——创建和使用下压按钮、单选框和复选框 实例040——实现位图按钮,设定控件文本的字体 实例041——实现超链接风格的按钮 实例042——实现动画按钮 实例...
  • 实例038——使用定时器显示毫秒级的时间 第3章 实例039——创建和使用下压按钮、单选框和复选框 实例040——实现位图按钮,设定控件文本的字体 实例041——实现超链接风格的按钮 实例042——实现动画按钮 ...
  • VC++6.0示例程序光盘

    热门讨论 2012-03-18 13:40:03
    实例038——使用定时器显示毫秒级的时间 第3章 实例039——创建和使用下压按钮、单选框和复选框 实例040——实现位图按钮,设定控件文本的字体 实例041——实现超链接风格的按钮 实例042——实现动画按钮 ...
  • VC++6.0示例程序光盘.part1

    热门讨论 2011-02-21 09:17:43
    实例038——使用定时器显示毫秒级的时间 第3章 实例039——创建和使用下压按钮、单选框和复选框 实例040——实现位图按钮,设定控件文本的字体 实例041——实现超链接风格的按钮 实例042——实现动画按钮 ...
  • 实例038——使用定时器显示毫秒级的时间 第3章 实例039——创建和使用下压按钮、单选框和复选框 实例040——实现位图按钮,设定控件文本的字体 实例041——实现超链接风格的按钮 实例042——实现动画按钮 ...
  • 实例038——使用定时器显示毫秒级的时间 第3章 实例039——创建和使用下压按钮、单选框和复选框 实例040——实现位图按钮,设定控件文本的字体 实例041——实现超链接风格的按钮 实例042——实现动画按钮 ...
  • 采用分层设计,整体总共分三界面,一界面是整体布局,二界面是单个功能模块,三界面是单个控件。 子控件包括饼图+圆环图+曲线图+柱状图+柱状分组图+横向柱状图+横向柱状分组图+合格率控件+百分比控件+进度...

空空如也

空空如也

1 2
收藏数 28
精华内容 11
关键字:

windows毫秒级定时器