繁体   English   中英

调整串口读取参数

[英]Adjust parameters of serial port reading

我面临有关在Win32下进行串行通信的特定问题。 我正在与设备通信时,只能在尚未通信时接受帧。 因此,我必须找到一个有效的框架,然后立即发送我的请求。

我开发了一个名为Serial的类,该类处理串行端口上的基本操作(打开,关闭,读取,写入),然后在循环读取和写入函数中调用Thread。

线程循环

//Device is an object of class Serial
while( device->isOpen() && !terminate )
{
    unsigned int readed = 0;
    unsigned long error = ERROR_SUCCESS;
    unsigned char* data = device->read( &readed, &error );

    if( error==ERROR_SUCCESS )
    {
        //If data received, deliver to upper level
        if( readed>0 )
        {
            QByteArray output( (const char*)data, (signed int)readed );
            emit dataArrived( output, readed );
        }
    }
    else
    {
         //unrelated stuff
    }

    //Here I manage the writting issue
    //Only when nothing is received, and Upper layer wants to send a frame
    //(Upper layer only will mark as something to send when it detects a valid frame)
    if( readed==0 )
    {
         out_lock.lock();
         //If something to send...
         if( something_to_send > 0 )
         {
            if( device->write( output_buffer, output_size, &error ) )
            { //things...
            }
         }
     }
}

线程基本上保持读取状态,当什么也没收到时,查看是否有人发信号发送帧(这意味着刚刚接收到有效帧)。 发生这种情况时,它将通过串行端口写入帧。

这是我的问题。 在Serial :: read()函数内部:
我使用重叠的阅读方式:

::ClearCommError( handle, &dwErrors, &stat);
if( stat.cbInQue )
{
    //If there's something to read, read it, please note the bytes to read parameter, here 1.
    bool ok = ::ReadFile( handle, buffer_in, 1, &bytes_read, &ov_reader );
    if( !ok )
    {
         DWORD _error = ::GetLastError();
         if( _error == ERROR_IO_PENDING )
         {
             DWORD result = ::WaitForMultipleObjects( 2, waiters, FALSE,INFINITE );
             switch( result )
             {     //Eventshutdown
                   case WAIT_OBJECT_0:  /*code omitted*/break;
                   case WAIT_OBJECT_0+1:   ok = ::GetOverlappedResult( handle, &ov_reader, &bytes_read, true );
                                           //check ok value omitted
                                           break;
             } 
         } 
    }
}

if( bytes_read>0 )
{
   *size = bytes_read;
}

这开始了我的问题。 当设备向我发送较小的帧(大约30个字节)时,一切正常,但是发送较大的帧时,代码无法在帧之间找到任何空闲时间,导致线程永远无法发送任何帧,因为readed值永远不会为0。

如果增加read()函数中要读取的字节数,则无法检测设备何时“侦听”:bool ok = :: ReadFile(handle,buffer_in,50,&bytes_read,&ov_reader); 发生这种情况是因为我的应用程序可以接收到一帧的结尾以及下一帧的开始。 这种现象很常见。

另一方面,如果通过WaitForMultipleObjects函数中的有效超时更改INFINITE参数,则会丢失数据。

所以我的问题基本上是...我在做什么错? 为什么每次每次读取1个字节时都找不到空闲时间发送自己的帧?

谢谢

我不确定这是否会有所帮助,但是由于您已经知道串行设备的输入队列中有多少个字节( stat.cbInQue ),也许它将有助于读取那么多的字节,而不仅仅是1字节或任意数量的字节(如50):

bool ok = ::ReadFile( handle, buffer_in, stat.cbInQue, &bytes_read, &ov_reader );

当然,您需要确保buffer_in具有该字节数的容量,因此可能需要添加一些其他逻辑以确保没有缓冲区溢出。

另外,由于串行驱动程序和ReadFile() API在很大程度上依赖于缓冲来处理接收到的字符,因此您可以使用WaitCommEvent()SetCommMask() API来更精确地指示何时接收(不接收)字符。 。

“更大的框架”有多大? 一次调用一个字节的ReadFile时,显然将花费较长的时间来遍历整个帧,这可能比由于调用开销而发送帧本身所花费的时间更长。

一些替代方案:

  1. 设备是否会在需要时发送帧? 如果您有机会设计协议的两端,是否可以切换为命令/响应方式的通信?

  2. 您可以从数据包的开头预测一下其余数据包中的字符数吗? 如果是这样,您可以在read功能中构建状态机。 您可以一次轮询一个字节,然后在检测到数据包的开头时,一次调用就读取其余数据包的大部分,然后一次切换回一个字节。

  3. 您可以使用DSR / CTS来控制时间吗?

通常,很难从串行端口读取功能中读取整个数据包。 通常的过程是读取一堆字符,并将它们传递到更高级别以进行协议解析。 听起来,您必须拥有比该方法所允许的更严格的时序控制。 祝好运...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM