简体   繁体   English

通过RS485通讯

[英]Communication via RS485

I have a single-board computer connected to another device via RS485. 我有一台单板计算机通过RS485连接到另一台设备。 The computer should send a request to the device and receive a response (using a device dependent protocol). 计算机应向设备发送请求并接收响应(使用设备相关协议)。 I can send messages without any problems and the device receives them (eg I can change parameters of the device). 我可以毫无问题地发送消息,并且设备可以接收它们(例如,我可以更改设备的参数)。 The problem occurs when I want to read parameters from the device. 当我想从设备读取参数时,会出现问题。 In this case I'm getting wrong responses (wrong characters, shifted messaged, incomplete messages, ...). 在这种情况下,我得到了错误的响应(错误的字符,错误的消息,不完整的消息……)。

Here is my initalization code: 这是我的初始化代码:

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;
}

Send code: 发送代码:

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;
}

Receive code: 接收代码:

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;
}

The functions aux_gpio_write_settings() and aux_gpio_read_settings() are used to set the UART(via GPIOs) st the RS485 can send or receive data. 函数aux_gpio_write_settings()aux_gpio_read_settings()用于设置UART(通过GPIO),从而RS485可以发送或接收数据。

If I use the code on my linux desktop computer it works fine since the USB/RS485 adapter switches automatically between sending and receiving mode. 如果我在linux台式计算机上使用该代码,则可以正常工作,因为USB / RS485适配器会自动在发送和接收模式之间切换。 On my single-board computer I have to do it manually. 在单板计算机上,我必须手动进行操作。 Because of that, I think that setting the GPIOs and receiving the response cause a timing problem. 因此,我认为设置GPIO和接收响应会导致时序问题。 How can I handle this problem? 我该如何解决这个问题?

It might be with a bug you have in the receiveFrame read-loop. 可能是与receiveFrame读取循环中的错误有关。 When you receive less than the wanted amount of data, you decrease the amount of data to receive the next time in the loop, but then when using the same pointer as the previous loop you overwrite the first data you read. 当收到的数据少于所需的数据量时,将减少循环中下次要接收的数据量,但是当使用与上一个循环相同的指针时,将覆盖读取的第一个数据。 You need to increase the pointer as well as decrease the size: 您需要增加指针并减小大小:

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

You have a similar problem when sending data, you send the same data over and over again, just less of it each time. 您在发送数据时遇到类似的问题,一次又一次地发送相同的数据,每次发送的次数都更少。

I also recommend you to actually check for errors (when bytesReceived < 0 ), and handle those cases appropriately. 我还建议您实际检查错误(当bytesReceived < 0 ),并适当地处理这些情况。

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

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