从零开始学VC系列教程之 浅谈额外知识点1(延时函数的实现)
习惯了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);
}
}
}
以上一些,限于本人知识不足,不一定非常专业,仅抛砖引玉 ./emotion/em025.gif 呵呵,windows 上通过应用程序完成us的延时,很难实现。倒不是因为不能做到,而是无法保证短延时的精确性,分时多任务操作系统本质决定了。
Sleep(1) 看上去是延时1个ms,其实最短也是超过10个ms的。
msdn上有说,比方Sleep(100),那么Windows只能保证延时的时间一定大于或等于100ms,但不保证正好100个ms就会调度到您进程继续执行。
所以,实际上边一段代码跟 SetTimer 并没有本质上的不同。 楼主的教程怎么不写了啊 顶楼主,楼主写的东西,通俗易懂,希望继续发表你的教程。 楼主好久不见了~ 呵呵,期待楼主继续带来cool帖 没学过VC,我电脑有个雅琦880想学来做串口,不知道比VC容易入门否?
页:
[1]