串口的SetCommTimeouts
(2014-07-31 22:54:07)分类: wince |
对串口通讯中的COMMTIMEOUTS参数一直很疑惑。到底是怎么起作用的呢?
曾经写一个简单的串口通讯程序,其中的过程是发60个字节数据到设备,然后过一段时间后大概是1到2秒的时间,会返回两次各60字节的数据,结果因为 COMMTIMEOUTS的作用不清楚,试了好久。现总结一下。
COMMTIMEOUTS
CommTimeOuts;
写操作时间有两种设置模式:
如下设置,写操作时,不考虑时间限制,直到写完成才返回
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 0;
如下设置,即a,b中至少有一个大于0,此时以
b+ a*(发送字节数 nBufLen ) 为时间限制,超时则返回
CommTimeOuts.WriteTotalTimeoutMultiplier = a;
CommTimeOuts.WriteTotalTimeoutConstant = b;
实际试验中,可能由于我的写的数据量太少,才60个字节,所以发送很快,两种模式下都很快返回了,看不出什么区别。而且串口的另一端没有设备连接时也可以写数据,所以写操作设置可以随意一些。
CommTimeOuts.ReadIntervalTimeout
与
(CommTimeOuts.ReadTotalTimeoutMultiplier 、 CommTimeOuts.ReadTotalTimeoutConstant)
分两组共同起影响。
2.1
CommTimeOuts.ReadIntervalTimeout 管理单个字符的读时限。
CommTimeOuts.ReadIntervalTimeout=0;
表示对单个字符的读不加时限。
CommTimeOuts.ReadIntervalTimeout=a; (a>0)
表示 从读操作(即 ReadFile)启动开始每a毫秒内能读到下一个字符(包括第一个字符),则OK,否则返回。
2.2
CommTimeOuts.ReadTotalTimeoutMultiplier
和 CommTimeOuts.ReadTotalTimeoutConstant
管理总的读数时限
如下设置时表示不加限制
CommTimeOuts.ReadTotalTimeoutMultiplier =0;
CommTimeOuts.ReadTotalTimeoutConstant=0;
如下设置时, b,c中至少有一个大于0, c+ b*(读取字节数nBufLen )
为总时限,超过则返回
CommTimeOuts.ReadTotalTimeoutMultiplier =b;
CommTimeOuts.ReadTotalTimeoutConstant=c;
CommTimeOuts.ReadIntervalTimeout= MAXDWORD ;
CommTimeOuts.ReadTotalTimeoutMultiplier =0;
CommTimeOuts.ReadTotalTimeoutConstant=0;
CommTimeOuts.ReadIntervalTimeout=0;
CommTimeOuts.ReadTotalTimeoutMultiplier =0;
CommTimeOuts.ReadTotalTimeoutConstant=0;
CommTimeOuts.ReadIntervalTimeout=0;
//对单个字符不设限制,无限等待
CommTimeOuts.ReadTotalTimeoutMultiplier =0;
CommTimeOuts.ReadTotalTimeoutConstant=5000;
//限制总的时限不超过5秒,
主要考虑到设备返回数据没那么快, 且防止永久阻塞
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
//以下两个设置在使用没发现太大效果
CommTimeOuts.WriteTotalTimeoutConstant = 1000;
在异步通讯下,时限设置也是有影响的。
试验中,曾串口异步通讯中如下设置
CommTimeOuts.ReadIntervalTimeout = 100;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 250;
读串口内容时,如下
if(
ReadFile(m_hComm,
(LPVOID)buf, bufLen,
&dwReadLen, &m_hOLP)
)
上面编写的目的是希望
WaitForSingleObject(m_hWRevent,5000)
中 在读到
bufLen
个数据后m_hWRevent 才变为激活状态,才返回,但实际是很快返回,而 buf
中的内容仍然是初始状态。
由于我当时并没有意识到是时限的问题,我就换了个函数,如下
if(ReadFile(m_hComm,
(LPVOID)buf, bufLen, &dwReadLen,&m_hOLP))
因为我看到MSDN说 GetOverlappedResult
函数在第四个参数设置为TRUE后,会产生阻塞效果,直接异步操作完成,但实际运行时,仍然是GetOverlappedResult很快就返回了,且 buf
中并未读取到所需的值。
最后没办法,在不太了解的情况下,我尝试如下,终于可以得到正确结果了
CommTimeOuts.ReadIntervalTimeout = 0;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
在同步通讯中,对ReadFile和WriteFile的何时完成返回产生作用。
在异步通讯中,Read和WriteFile是立即返回的,当返回值时为TRUE时,当然就不提了,但当返回FALSE且
GetLastError()==ERROR_IO_PENDING
时,就对异步操作相关事件的状态起影响。
我认为假设同步通讯时,读写根据时限设置应该返回了,相应的在异步通讯状态下,读写的事件就应该变为激活状态了。
当事件激活后
WaitForSingleObject(m_hWRevent,5000)==WAIT_OBJECT_0
此时就为真了
而
GetOverlappedResult(m_hComm,&m_hOLP,&dwReadLen,TRUE)
的第四个参数为TRUE时,会等待,但当事件状态为激活后,也就会返回。
一、针对同步通讯专门试了一下其效用。
1
WriteFile(m_hComm, cBufSend,
nBufLen ,
&dwNumBytesWritten, 0);
2
ReadFile(m_hComm, cBufSend, nBufLen ,
&dwNumBytesReaded, 0);
2.3
MSDN中提到如下的时限设置,无论是否读到数据,读操作立即返回,读缓冲区的已有内容需读取返回
2.4
注意:如下设置时,很可能阻塞,建议不使用
3
在以上都清楚的情况下,进行如下设置就很快成功了
二、串口异步通讯时,时限设置的影响
{
return true;
}
else
{
if(GetLastError()==ERROR_IO_PENDING)
{
if(WaitForSingleObject(m_hWRevent,5000)==WAIT_OBJECT_0)
return true;
//此处应该是
}
}
{
return true;
}
else
{
if(GetLastError()==ERROR_IO_PENDING)
{
if(GetOverlappedResult(m_hComm,&m_hOLP,&dwReadLen,TRUE)
&& dwReadLen==bufLen)
{
return true;
}
return true;
}
}
三、
综上所述,我得出的结果是,COMMTIMEOUTS 在同步或异步通讯时都是起效果的,只是产生效果的地方不一样。