簡體   English   中英

通過RS485通訊

[英]Communication via RS485

我有一台單板計算機通過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()用於設置UART(通過GPIO),從而RS485可以發送或接收數據。

如果我在linux台式計算機上使用該代碼,則可以正常工作,因為USB / RS485適配器會自動在發送和接收模式之間切換。 在單板計算機上,我必須手動進行操作。 因此,我認為設置GPIO和接收響應會導致時序問題。 我該如何解決這個問題?

可能是與receiveFrame讀取循環中的錯誤有關。 當收到的數據少於所需的數據量時,將減少循環中下次要接收的數據量,但是當使用與上一個循環相同的指針時,將覆蓋讀取的第一個數據。 您需要增加指針並減小大小:

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

您在發送數據時遇到類似的問題,一次又一次地發送相同的數據,每次發送的次數都更少。

我還建議您實際檢查錯誤(當bytesReceived < 0 ),並適當地處理這些情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM