2

シングルボード コンピュータを RS485 経由で別のデバイスに接続しています。コンピューターはデバイスに要求を送信し、応答を受信する必要があります (デバイス依存のプロトコルを使用)。問題なくメッセージを送信でき、デバイスはそれらを受信します (たとえば、デバイスのパラメータを変更できます)。この問題は、デバイスからパラメーターを読み取りたいときに発生します。この場合、私は間違った応答を受け取ります (間違った文字、シフトされたメッセージ、不完全なメッセージなど)。

ここに私の初期化コードがあります:

Bool
SerialCommunicator::initPort()
{
if (isInitialized_)
    return true;

if (!paramSet())
    return false;

bzero( &termIO_, sizeof ( struct termios ));
termIO_.c_iflag    |= IGNBRK | IGNPAR;
termIO_.c_cflag    |= CREAD | CLOCAL;
termIO_.c_cflag    |= CS8;
termIO_.c_oflag    |= 0;
termIO_.c_lflag    |= 0;

termIO_.c_cc[VTIME]    = 0;
termIO_.c_cc[VMIN]     = 13; // number of frame characters

String path("/dev/tty" + portSuffix_);
serHandle_ = open(path.c_str(), O_RDWR /*| O_NOCTTY*/);
if (serHandle_ > -1)
{
    isInitialized_ = (cfsetispeed(&termIO_, B19200) == 0)
                        && (cfsetospeed(&termIO_, B19200) == 0);
    isInitialized_ = isInitialized_ && (tcsetattr(serHandle_, TCSANOW, &termIO_) == 0);


    return isInitialized_;
}
else
    return false;
}

コードを送信:

Bool
SerialCommunicator::sendFrame(UByte *_frame, UInt _size)
{
FD_ZERO( &wrFd_ );
FD_ZERO( &rdFd_ );
FD_SET( serHandle_, &wrFd_);
FD_SET( serHandle_, &rdFd_);

Int retVal;
aux_gpio_write_settings();
retVal = select(serHandle_+1, &rdFd_, &wrFd_, NULL, &timeval_);
if (retVal > 0)
{
  if( FD_ISSET(serHandle_, &wrFd_) )
  {

    UInt    bytesToSend     = _size;
    UInt    bytesSent       = 0;
    UInt    bytesSentTotal  = 0;
    while ( bytesToSend > 0 )
    {
        bytesSent   = write( serHandle_, _frame + bytesSentTotal, bytesToSend );
        if (bytesSent > 0)
        {
            bytesToSend     -= bytesSent;
            bytesSentTotal  += bytesSent;
        }

    }
    aux_gpio_read_settings();
    tcflush(serHandle_, TCIOFLUSH);
    return true;
  }
}
usleep(SLEEPTIME);
return false;
}

コードを受け取る:

Bool
SerialCommunicator::receiveFrame(UByte *_frame, UInt _size)
{
FD_ZERO( &rdFd_ );
FD_ZERO( &wrFd_ );
FD_SET( serHandle_, &rdFd_ );
FD_SET( serHandle_, &wrFd_ );

Bool retVal;
aux_gpio_read_settings();
retVal = select(serHandle_+1, &rdFd_, &wrFd_, NULL, &timeval_);
if (retVal > 0)
{
  if( FD_ISSET(serHandle_, &rdFd_) )
  {

    UInt    bytesToReceive      = _size;
    UInt    bytesReceived       = 0;
    UInt    bytesReceivedTotal  = 0;
    while ( bytesToReceive > 0 )
    {
        bytesReceived   = read( serHandle_, _frame + bytesReceivedTotal, bytesToReceive );
        if (bytesReceived > 0)
        {
            bytesToReceive      -= bytesReceived;
            bytesReceivedTotal  += bytesReceived;
        }
    }
    return true;
  }
}
return false;
}

関数aux_gpio_write_settings()aux_gpio_read_settings()は、RS485 がデータを送受信できるように、(GPIO を介して) UART を設定するために使用されます。

Linux デスクトップ コンピューターでコードを使用すると、USB/RS485 アダプターが送信モードと受信モードを自動的に切り替えるため、問題なく動作します。私のシングルボードコンピューターでは、手動で行う必要があります。そのため、GPIO を設定してレスポンスを受信すると、タイミングの問題が発生すると思います。どうすればこの問題を処理できますか?

4

1 に答える 1

1

receiveFrame読み取りループにバグがある可能性があります。必要な量よりも少ないデータを受け取ると、ループで次に受け取るデータの量が減りますが、前のループと同じポインターを使用すると、最初に読み取ったデータが上書きされます。サイズを小さくするだけでなく、ポインターを大きくする必要があります。

bytesReceived   = read( serHandle_, _frame, bytesToReceive );
if (bytesReceived > 0)
{
    bytesToReceive -= bytesReceived;
    _frame += bytesReceived;
}

データを送信するときにも同様の問題があり、同じデータを何度も送信しますが、毎回送信するデータは少なくなります。

また、実際にエラーをチェックして ( の場合bytesReceived < 0)、それらのケースを適切に処理することもお勧めします。

于 2013-08-06T13:55:44.513 に答える