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

查看:154
本文介绍了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("\n ERROR: setting attributes");
else
    printf("\n Baudrate = 115200 \t Stopbits = 1 \t 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\t",buf[i]);
        puts("\n");
}

这是我应该收到的消息类型的示例{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().

您描述的结果类似于阻止规范模式(当您实际需要(阻止)原始模式时).
在接收到EOL(行尾)字符之前, read()应该会阻塞.

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(行尾)字符时,满足规范的 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的代码非常类似于

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_iflag ICANON 错误的起源似乎是此中的rel ="nofollow noreferrer">串行端口教程.该错误已在两年前通知作者,但尚未修复.

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天全站免登陆