因此,我使用运行Linux的ARM9处理器(i.mx28)通过RS232 (高级协议基于CANOpen协议)与BLDC控制器进行通信。发送给控制器的消息通常后面跟着响应。
控制器侧连接器具有RX、TX以及GND等功能,因此没有流量控制线等.控制器手册规定,必须使用不使用软件流控制来设置连接。因此,我将端口配置为忽略DCD (使用CLOCAL)、RTS/CTS (使用~CRTSCTS)和软件流控制(使用~IXON、~IXOFF和~IXANY)。
我的问题如下:在设置串口后,编写工作非常好,例如软重置之类的命令会立即执行。然而,试图阅读提到的响应会导致"Errno 11:资源暂时不可用“。当我试图监视运行终端的计算机上的消息时,read()返回0而不是-1,因此没有设置errno。反之亦然,我尝试将BLDC控制器连接到所述终端,并手动重新启动它以查看启动时发送的启动消息。这件事也很好。
在过去的三天里,我一直在滥用谷歌,寻找类似的问题,但都没有用。在几种不同的非阻塞IO设置组合中,我还尝试了几种阻塞行为的方法,但是这导致了永远的阻塞,而且仍然没有读取任何东西。
我怀疑串行端口(虽然termios配置状态不同)仍然期望握手/流控制,因为将系统连接到提供RTS/CTS线路的计算机上是很好的。
int configureSerialPort() {
//Open Serial Port--------------------------------------------
int fileDescr = open("/dev/ttyS3", O_RDWR | O_NDELAY);
if (fileDescr < 0){
std::cout << "Unable to open Serial Port." << std::endl;
exit(1);
}
else std::cout << "Serial Port opened." << std::endl;
fcntl(fdSerial, F_SETFL, O_NONBLOCK);
//Configure Serial Port for B115200, 8N1---------
struct termios PortParams;
if (tcgetattr(fileDescr, &PortParams) < 0) {
std::cout << "Could not get Attributes." << std::endl;
exit(1);
}
else std::cout << "Got Attributes." << std::endl;
cfsetispeed(&PortParams, 115200);
cfsetospeed(&PortParams, 115200);
PortParams.c_cflag |= (CLOCAL | CREAD);
PortParams.c_cflag &= ~PARENB;
PortParams.c_cflag &= ~CSTOPB;
PortParams.c_cflag &= ~CSIZE;
PortParams.c_cflag |= CS8;
PortParams.c_cflag &= ~CRTSCTS;
PortParams.c_lflag &= ~(ICANON | ECHO | ECHONL | IEXTEN | ISIG);
PortParams.c_iflag &= ~(INPCK | ISTRIP | IGNPAR | PARMRK | IXON | IXOFF | IXANY);
PortParams.c_oflag &= ~OPOST;
PortParams.c_cc[VMIN] = 0;
PortParams.c_cc[VTIME] = 0;
if (tcsetattr(fileDescr, TCSANOW, &PortParams) != 0) {
std::cout << "Could not set Attributes." << std::endl;
exit(1);
}
else std::cout << "Port configured." << std::endl;
usleep(1000000);
tcflush(fdSerial, TCIFLUSH);
return fileDescr;
}到目前为止,这是我的配置,这对我的理解应该是很好的。
写作和阅读是由各自的系统完成的:
wrLenSerial = write(fdSerial, &resetNode, sizeof(resetNode));
if (wrLenSerial < sizeof(resetNode)) {
std::cout << "Could not send Write Command." << std::endl;
}
else std::cout << "Reset Command sent." << std::endl;
usleep(60000);
memset(inBufSerial, '\0', sizeof(inBufSerial));
rdlenSerial = read(fdSerial, inBufSerial, (sizeof(inBufSerial) - 1));
if (rdlenSerial < 0) {
std::cout << "Read Error. " << errno << std::strerror(errno) << std::endl;
}
else if (rdlenSerial == 0) {
std::cout << "Nothing read." << std::endl;
}
else {
std::cout << "Node Response: ";
for (int i = 0; i < rdlenSerial; i++) {
int r = inBufSerial[i];
std::cout << std::hex << r << std::dec << " " << std::endl;
}
}我真的希望这篇文章不要太长时间阅读,任何想法都是感激的!
发布于 2019-08-13 23:59:38
然而,试图阅读提到的响应会导致"Errno 11:资源暂时不可用“。
考虑到您的配置,完全可以期望errno 11。您已经尽了一切可能将串行终端配置为非阻塞模式.
首先,使用O_NDELAY选项打开串行终端。
然后修改(未初始化的)文件描述符以设置O_NONBLOCK选项。
最后,尽管这在非阻塞模式中配置无效,但termios参数VMIN和VTIME都被配置为零(即轮询模式)。
errno引用的“不可用资源”只是数据。syscall无法在用户缓冲区中返回数据。
我也尝试过几种阻止行为的方法,但是这导致了永远的阻塞,而且仍然没有阅读任何东西。
如果没有实际的代码,就没有什么可调试的。
您需要决定您的程序是使用阻塞模式还是非阻塞模式。
主程序需要同时读取来自给定控制器的电势输入和通过i2c连接的eeprom的8位值。
您不需要非阻塞模式来确保“同时”数据捕获。
读取设备的实际输入由执行与应用程序完全异步的内核驱动程序执行。
您的应用程序代码根本无法控制这些输入操作实际发生的时间。
只要UART不报告接收器溢出错误,就可以确保接收到所有串行数据,并将其最初存储在驱动程序的接收缓冲区中。
该数据最终将被复制到串行终端的缓冲区中,该缓冲区通常大小为4096字节。
从I2C设备读取数据还应该包含一个系统缓冲区,但我看不到从EEPROM读取数据的任何时间组件。
这是一个非易失性存储设备,它响应写和读命令。
您的应用程序代码只是试图从内核缓冲区中获取数据。
EEPROM可以随时随地读取,方便程序使用。
需要以足以防止系统缓冲区溢出的速率读取串行终端。
由于程序与BLDC控制器之间的通信结构为请求/响应对话框,因此请求串行终端输入,即程序只在发送请求后才期望输入。
非阻塞模式非常适合于这种情况。
改变
fcntl(fdSerial, F_SETFL, O_NONBLOCK);至
fcntl(fileDescr, F_SETFL, 0);将刚刚打开的文件描述符置于阻塞模式。
顶替
PortParams.c_cc[VMIN] = 0;
PortParams.c_cc[VTIME] = 0;有这样的东西:
PortParams.c_cc[VMIN] = MIN(255, (sizeof(inBufSerial) - 1));
PortParams.c_cc[VTIME] = 1;将尝试检索每个syscall尽可能多的响应字节。
如果您喜欢或需要更少的延迟,那么学习this answer
写入后的usleep(60000);语句应该被删除,或者替换为调用 The ()。
一般来说,任何固定的延迟/睡眠系统都是有问题的。
https://stackoverflow.com/questions/57479555
复制相似问题