Ubuntu串行通信:读取失败然后立即全部进入 [英] Ubuntu Serial Communication: reads failing and then coming in all at once

查看:23
本文介绍了Ubuntu串行通信:读取失败然后立即全部进入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个程序,该程序在运行 Ubuntu 服务器 14.04 的 MIO-3260 单板计算机上运行,​​并与 AMC DPRANIE C100A400 驱动器通信.该程序向驱动器发送一串十六进制代码,并且应该接收它发送的每条消息的响应.当我在 windows 上的 realTerm 中尝试它时,效果很好,所以我认为这不是驱动器的问题.但是,当我尝试从串行端口读取时,read() 几乎总是返回 -1,直到突然在一个看似随机的点,我一次得到大量消息转储.

I'm writing a program that runs on a MIO-3260 single board computer running Ubuntu server 14.04 and communicates with a AMC DPRANIE C100A400 drive. The program sends a string of hex codes to the drive and is supposed to receive a response for every message it sends. When I try it in realTerm on windows this works well so I don't think it's an issue with the drive. However, when I try to read from the serial port read() returns -1 almost all the time, until suddenly at a seemingly random point I get a massive dump of messages all at once.

我正在使用 termios 来设置串行端口.这是我的代码.我尝试将其设置为阻塞配置,但如果我这样做,代码只会在第一次 read() 时无限期挂起.

I'm using termios to set up the serial port. Here's my code for that. I've tried setting it up in a blocking configuration but if I do that the code just hangs indefinitely at the first read().

int fd;
fd = open("/dev/ttyS0",O_RDWR | O_NOCTTY | O_NDELAY);
struct termios SerialPortSettings;

tcgetattr(fd, &SerialPortSettings); //get current settings of serial port
cfsetispeed(&SerialPortSettings,B115200);//set input baud rate
cfsetospeed(&SerialPortSettings,B115200);//set output baud rate
SerialPortSettings.c_cflag &= ~PARENB;//clear parity bit (no parity)
SerialPortSettings.c_cflag &= ~CSTOPB;//Stop bits = 1
SerialPortSettings.c_cflag &= ~CSIZE;//clears the mask
SerialPortSettings.c_cflag |= CS8; //set data bits = 8
SerialPortSettings.c_cflag &= ~CRTSCTS; //turn off hardwar based flow ctrl
SerialPortSettings.c_cflag |= CREAD | CLOCAL;//Turn on the reciever

SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY); //Turn off software
//based flow control
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);//Non-canonical mode
SerialPortSettings.c_oflag &= ~OPOST;//no output processing
//set the termios struct now
if(tcsetattr(fd,TCSANOW,&SerialPortSettings) != 0)
    printf("
 ERROR: setting attributes");
else
    printf("
 Baudrate = 115200 	 Stopbits = 1 	 Parity = none");

从串口读取,我的代码如下:

To read from the serial port, my code is as follows:

uint8_t buf[1024];//Rx buffer
int bytes_read;
bytes_read = read(fd,&buf,1024);
if(bytes_read != -1){
        for(int i=0;i<bytes_read;i++)    /*printing only the received characters*/
                printf("%02X	",buf[i]);
        puts("
");
}

这是我应该收到的消息类型示例 {0xA5 0xFF 0x10 0x01 0x00 0x00 0xD4 0x11}.它应该是大约 8-14 字节长.相反,我一次收到一个巨大的数字,而在其他时间没有收到(例如,我在发送 946 个没有响应的命令后一次收到 810 个字节).

Here's a sample of the kind of message I should be receiving {0xA5 0xFF 0x10 0x01 0x00 0x00 0xD4 0x11}. It should be about 8-14 bytes long. Instead I receive a huge number all at once and none at other times (for example I just received 810 bytes at once after sending 946 commands with no response).

过去几天我一直在对其进行故障排除,但不知道发生了什么.有时我运行它,它大部分时间都会响应,然后神秘地停止,然后间歇性地回来.

I've been troubleshooting it for the last few days and have no idea what's going on. Sometimes I run it and it responds most of the time and then mysteriously it just stops and then comes back intermittently.

如果我可以提供更多信息,请告诉我.

Let me know if there's anymore information I can provide.

任何帮助将不胜感激!

更新:我也将我的笔记本电脑连接到了串行端口,这样我就可以使用 RealTerm 监视传输,并且我已经验证了 MIO-3260 正确地发送了命令并且驱动器正确地响应了命令.所以问题似乎出在我尝试从端口读取时.

UPDATE: I've connected my laptop to the serial port as well so I can spy on the transmissions using RealTerm, and I've verified that commands are being sent by the MIO-3260 correctly AND being responded to correctly by the drive. So the issue seems to be when I try to read from the port.

推荐答案

我尝试将其设置为阻塞配置,但如果我这样做,代码只会在第一次 read() 时无限期挂起.

I've tried setting it up in a blocking configuration but if I do that the code just hangs indefinitely at the first read().

您描述的结果类似于阻止规范模式(当您真正想要(阻止)原始模式时).
read() 应该阻塞,直到收到 EOL(行尾)字符.

The results you describe are similar to blocking canonical mode (when you actually want (blocking) raw mode).
The read() is supposed to block until an EOL (end of line) character is received.

但是,当我尝试从串行端口读取时,read() 几乎总是返回 -1,直到突然在一个看似随机的点,我一次得到大量消息转储.

However, when I try to read from the serial port read() returns -1 almost all the time, until suddenly at a seemingly random point I get a massive dump of messages all at once.

您描述的结果类似于非阻塞规范模式(当您真正想要(阻塞)原始模式时).
当缓冲区中没有数据(即完整的行)时, read() 将返回 -1 和 errno (你这样做懒得检查)设置为-EAGAIN.
但是当二进制数据巧合匹配一个EOL(end of line)字符时,满足规范read()的条件就满足了,缓存的数据就返回了.

The results you describe are similar to non-blocking canonical mode (when you actually want (blocking) raw mode).
When no data (i.e. a complete line) is available in the buffer, the read() will return -1 and errno (which you do not bother to examine) is set to -EAGAIN.
But when the binary data coincidentally matches an EOL (end of line) character, the condition to satisfy the canonical read() is met, and the buffered data is returned.

串口终端实际上​​没有配置为非规范模式的原因是因为从错误成员中清除了ICANON和相关标志.

The reason why the serial terminal is not actually configured for non-canonical mode is because the ICANON and related flags are cleared from the wrong member.

SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);//Non-canonical mode 

ICANON 在 c_lflag 成员中,而不是在 c_iflag 中.
所以声明应该是

ICANON is in the c_lflag member, and not in c_iflag.
So the statement should be

SerialPortSettings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // Non-canonical mode 

推测串行终端默认为规范模式,而您的程序从未成功地将模式更改为任何不同的模式.

Presumably that serial terminal defaulted to canonical mode, and your program has never successfully changed the mode to anything different.

此外,对于原始模式,需要定义 VMIN 和 VTIME 成员.
例如:

Additionally, for raw mode, the VMIN and VTIME members need to be defined.
For example:

SerialPortSettings.c_cc[VMIN]  = 1;
SerialPortSettings.c_cc[VTIME] = 1;

<小时>

代码中的另一个错误是在数组地址足够时使用指向数组地址的指针(即地址的地址).


Another bug in your code is the use of pointer to array address (i.e. address of address) when the array address would suffice.

bytes_read = read(fd,&buf,1024);

应该是

bytes_read = read(fd, buf, 1024);

<小时>

附录

OP 的代码非常类似于 this question,具有相同的错误 termios 语句.
该张贴者最终解决了他自己的问题,但错误地将修复归因于添加了一个(不相关的)ECHONL 标志,而没有意识到他实际上是在更正结构成员的名称.

The OP's code is remarkably similar to this question, which has the identical bad termios statement.
That poster eventually solved his own problem, but mistakenly attributed the fix to adding an (irrelevant) ECHONL flag and not realizing that he was actually correcting the name of the structure member.

附录 2

这个 c_iflagICANON 错误的起源似乎是这个 来自 xanthium.in 的串口教程.两年多以前,作者就收到了该错误的通知,但尚未修复.

The origin of this c_iflag and ICANON bug seems to be this serial port tutorial from xanthium.in. The author was notified over two years ago of the bug, but has not fixed it.

这篇关于Ubuntu串行通信:读取失败然后立即全部进入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆