|
习惯了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, 杜汶泽)
|