通过RS485通信

问题描述:

我有一个单板计算机通过RS485连接到另一个设备。计算机应向设备发送请求并接收响应(使用设备相关协议)。我可以毫无问题地发送消息,设备也会收到消息(例如,我可以更改设备的参数)。当我想从设备读取参数时会出现问题。在这种情况下,我收到错误的回应(错误的字符,转移的消息,不完整的消息,...)。通过RS485通信

这里是我的initalization代码:

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)st RS485可以发送或接收数据。

如果我使用我的Linux台式机上的代码,它工作正常,因为USB/RS485适配器在发送和接收模式之间自动切换。在我的单板电脑上,我必须手动完成。因此,我认为设置GPIO和接收响应会导致计时问题。我该如何处理这个问题?

+0

建议交换'aux_gpio_read_settings();'和'tcflush(serHandle_,TCIOFLUSH);'的顺序。冲洗_before_公共汽车周围。 – chux

这可能是因为您在receiveFrame读取循环中遇到的错误。当您收到的数据量少于所需的数据量时,会减少循环中下次要接收的数据量,但是当使用与上一个循环相同的指针时,将覆盖您读取的第一个数据。你需要增加指针以及减小尺寸:

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

发送数据时,您有类似的问题,你一遍又一遍的发送相同的数据,只是每次的要少。

我还建议您实际检查错误(当bytesReceived < 0),并适当处理这些情况。

+0

谢谢你的快速回答。我会尽快检查它。 – DBPST

+0

现在的反应要好得多。但是,有时候我没有得到任何回应,有时候会有一个转换(通常是1或2个字节的移位),有时候是readiny块(因此没有输入)。我认为后者可以用超时解决。 – DBPST

+0

有时,响应的前1-3个字节也是错误的。 – DBPST