搜索
bottom↓
回复: 8

从零开始学VC系列教程之 浅谈额外知识点1(延时函数的实现)

[复制链接]

出0入0汤圆

发表于 2011-4-8 22:50:21 | 显示全部楼层 |阅读模式
习惯了MCU写法的朋友们往往对VC很不顺手,通常我们的MCU裸机程序都是单线程的,按流程执行。于是,用到的延时程序也是阻塞式的,也就是说,MCU可以在某个地方弄一个死循环等在那里什么也不干,而VC之中是不行的,例如我们弄了以下的函数用于延时,会造成一些不好的后果。
void Delayms(unsigned int nms)
{
    unsigned int i = 0;
    while(--nms)
    {
         //假定这个for循环正好延时1us
         for(i=0;i<1000;i++);
    }
}

    延时一段时间看看?会发现程序好像死了,鼠标都不动了。延时完成后,又正常了。原因是windows是消息机制的,鼠标的移动会通过一个消息传输,当主线程阻塞时(例如开个死循环),会导致消息不能及时传输。当然,VC里面还有一个可以实现MS级延时的函数,Sleep(nms);使用该函数可以让出本线程时间给其它线程,但如果这个函数用在主线程里面,也是不行的,除非需要一个几毫秒的延时。基于以上问题,不难看出,如果让消息能顺利传输,就会好多了,至少不会看起来好像系统死机了。
    怎么实现呢?有一个函数PeekMessage可以取得消息队列中的消息,同时,可以通过TranslateMessage传输出去。所以,可以把延时函数改一下,试试以下的函数。

void Delayms(DWORD wDelayms)
{
    MSG m_Msg;
    while(--wDelayms)
    {
        //让出时间给其它线程
        Sleep(1);
        PeekMessage(&m_Msg,NULL,0,0,PM_REMOVE);
        TranslateMessage(&m_Msg);
        DispatchMessage(&m_Msg);
    }
}

    这样就可以让消息传输出去了,同时也可以实现延时,当然,如果程序在系统中的优先级不够,这种延时也不一定准确,延时时间越长,会误差越大。另外,我们也可以用定时器来延时,让一些延时执行的函数在定时器中调用。开定时器很简单SetTimer();这个定时器很像MCU中的硬件定时器,MCU的定时器时间到时,可以直接引发中断,在中断函数中执行一些功能或者实现计数,而SetTimer设定时间到后,则会有一个消息发出,同时,也有一个函数OnTimer自动响应。VC中的定时器消息优先级非常低,很多消息都可以优先执行,所以其实这个定时器也不会非常准确。

    以下是一个例子了,网上很多,利用CPU的频率来延时,理论上是非常准确的,可以精确到us 当然,虽然这个函数可以实现us延时,那也是理想状态,因为操作系统不会让时间全部花在一个函数上面,所以时间查询可以认为是精确的,但延时后面的函数能否得到立即执行,还要依赖于很多的东西,这里就不再细论了。

void Delayms(DWORD wInterval)
{
        LARGE_INTEGER frequence,lInterval;

        //取高精度运行计数器的频率,若硬件不支持则返回FALSE
        if(!QueryPerformanceFrequency( &frequence))
                AfxMessageBox("Not Support!");

        QueryPerformanceFrequency(&frequence);
        lInterval.QuadPart = frequence.QuadPart * wInterval * 1000 / 1000000;
        LARGE_INTEGER privious,current;

        QueryPerformanceCounter(&privious);
        current=privious;

        MSG m_Msg;

        while(current.QuadPart-privious.QuadPart < lInterval.QuadPart)
        {
                QueryPerformanceCounter(¤t);  

                if(wInterval > 10) //大于10ms
                {
                        //传递系统消息
                        PeekMessage(&m_Msg,NULL,0,0,PM_REMOVE);
                        TranslateMessage(&m_Msg);
                        DispatchMessage(&m_Msg);
                        //让出时间给其它线程
                        Sleep(1);
                }
        }
}

以上一些,限于本人知识不足,不一定非常专业,仅抛砖引玉

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2011-4-8 23:52:49 | 显示全部楼层

出0入0汤圆

发表于 2011-4-9 02:16:54 | 显示全部楼层
呵呵,windows 上通过应用程序完成us的延时,很难实现。倒不是因为不能做到,而是无法保证短延时的精确性,分时多任务操作系统本质决定了。
Sleep(1) 看上去是延时1个ms,其实最短也是超过10个ms的。
msdn上有说,比方Sleep(100),那么Windows只能保证延时的时间一定大于或等于100ms,但不保证正好100个ms就会调度到您进程继续执行。
所以,实际上边一段代码跟 SetTimer 并没有本质上的不同。

出0入0汤圆

发表于 2011-12-7 13:00:59 | 显示全部楼层
楼主的教程怎么不写了啊

出0入0汤圆

发表于 2011-12-7 14:20:46 | 显示全部楼层
顶楼主,楼主写的东西,通俗易懂,希望继续发表你的教程。

出0入0汤圆

发表于 2012-9-18 10:33:13 | 显示全部楼层
楼主好久不见了~

出0入0汤圆

发表于 2012-9-25 16:06:22 | 显示全部楼层
呵呵,期待楼主继续带来cool帖

出0入0汤圆

发表于 2013-11-19 22:53:38 | 显示全部楼层
没学过VC,我电脑有个雅琦880想学来做串口,不知道比VC容易入门否?
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-23 22:11

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表