山高疑日近,海阔觉天低

串口的SetCommTimeouts

对串口通讯中的COMMTIMEOUTS参数一直很疑惑。到底是怎么起作用的呢?

typedef struct _COMMTIMEOUTS {
  DWORD ReadIntervalTimeout;
  DWORD ReadTotalTimeoutMultiplier;
  DWORD ReadTotalTimeoutConstant;
  DWORD WriteTotalTimeoutMultiplier;
  DWORD WriteTotalTimeoutConstant;
} COMMTIMEOUTS, *LPCOMMTIMEOUTS;
      曾经写一个简单的串口通讯程序,其中的过程是发60个字节数据到设备,然后过一段时间后大概是1到2秒的时间,会返回两次各60字节的数据,结果因为COMMTIMEOUTS的作用不清楚,试了好久。现总结一下。
一、针对同步通讯专门试了一下其效用。
      COMMTIMEOUTS   CommTimeOuts;
1    WriteFile(m_hComm, cBufSend,  nBufLen ,  &dwNumBytesWritten, 0);
      写操作时间有两种设置模式:
      如下设置,写操作时,不考虑时间限制,直到写完成才返回

      CommTimeOuts.WriteTotalTimeoutMultiplier = 0;

CommTimeOuts.WriteTotalTimeoutConstant = 0;

     如下设置,即a,b中至少有一个大于0,此时以  b+ a*(发送字节数 nBufLen )  为时间限制,超时则返回
      CommTimeOuts.WriteTotalTimeoutMultiplier = a;
      CommTimeOuts.WriteTotalTimeoutConstant = b;
      实际试验中,可能由于我的写的数据量太少,所以发送很快,两种模式下都很快返回了,看不出什么区别。而且串口的另一端没有设备连接时也可以写数据,所以写操作设置可以随意一些。
2   ReadFile(m_hComm, cBufSend,  nBufLen ,  &dwNumBytesReaded, 0);
      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;
2.3   MSDN中提到如下的时限设置,无论是否读到数据,读操作立即返回,读缓冲区的已有内容需读取返回
         CommTimeOuts.ReadIntervalTimeout= MAXDWORD ;
         CommTimeOuts.ReadTotalTimeoutMultiplier=0;
         CommTimeOuts.ReadTotalTimeoutConstant=0;
2.4  注意:如下设置时,很可能阻塞,建议不使用
       CommTimeOuts.ReadIntervalTimeout=0;
       CommTimeOuts.ReadTotalTimeoutMultiplier=0;
       CommTimeOuts.ReadTotalTimeoutConstant=0;
3    在以上都清楚的情况下,进行如下设置就很快成功了
       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)   )
{
return true;
}
else
{
if(GetLastError()==ERROR_IO_PENDING)
{
if(WaitForSingleObject(m_hWRevent,5000)==WAIT_OBJECT_0)
return true;        //此处应该是
}
}
       上面编写的目的是希望  WaitForSingleObject(m_hWRevent,5000) 中 在读到  bufLen 个数据后m_hWRevent 才变为激活状态,才返回,但实际是很快返回,而 buf 中的内容仍然是初始状态。
        由于我当时并没有意识到是时限的问题,我就换了个函数,如下
        if(ReadFile(m_hComm, (LPVOID)buf, bufLen, &dwReadLen,&m_hOLP))
{
return true;
}
else
{
if(GetLastError()==ERROR_IO_PENDING)
{
if(GetOverlappedResult(m_hComm,&m_hOLP,&dwReadLen,TRUE)
&& dwReadLen==bufLen)
{
return true;
}
return true;
}
}
        因为我看到MSDN说 GetOverlappedResult 函数在第四个参数设置为TRUE后,会产生阻塞效果,直接异步操作完成,但实际运行时,仍然是GetOverlappedResult很快就返回了,且 buf 中并未读取到所需的值。
        最后没办法,在不太了解的情况下,我尝试如下,终于可以得到正确结果了
         CommTimeOuts.ReadIntervalTimeout = 0;
        CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
         CommTimeOuts.ReadTotalTimeoutConstant = 0;
 
三、 综上所述,我得出的结果是,COMMTIMEOUTS 在同步或异步通讯时都是起效果的,只是产生效果的地方不一样。
        在同步通讯中,对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时,会等待,但当事件状态为激活后,也就会返回。
未经允许不得转载:Mr.Zhang » 串口的SetCommTimeouts

评论 抢沙发

评论前必须登录!