通过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和接收响应会导致计时问题。我该如何处理这个问题?
答
这可能是因为您在receiveFrame
读取循环中遇到的错误。当您收到的数据量少于所需的数据量时,会减少循环中下次要接收的数据量,但是当使用与上一个循环相同的指针时,将覆盖您读取的第一个数据。你需要增加指针以及减小尺寸:
bytesReceived = read(serHandle_, _frame, bytesToReceive);
if (bytesReceived > 0)
{
bytesToReceive -= bytesReceived;
_frame += bytesReceived;
}
发送数据时,您有类似的问题,你一遍又一遍的发送相同的数据,只是每次的要少。
我还建议您实际检查错误(当bytesReceived < 0
),并适当处理这些情况。
建议交换'aux_gpio_read_settings();'和'tcflush(serHandle_,TCIOFLUSH);'的顺序。冲洗_before_公共汽车周围。 – chux