Ubuntu 串行通信:读取失败然后一次全部进入

Ubuntu Serial Communication: reads failing and then coming in all at once

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

我正在使用 termios 设置串口。这是我的代码。我已经尝试在阻塞配置中设置它,但如果我这样做,代码只会在第一次读取时无限期挂起()。

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");

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

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 个字节长。相反,我一次收到一个巨大的数字,而在其他时间 none (例如,我在发送 946 个命令而没有响应后立即收到 810 个字节)。

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

如果我能提供更多信息,请告诉我。

任何帮助将不胜感激!

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

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(行尾)字符。

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() 将 return -1 和 errno(您不必费心检查)设置为 -EAGAIN。
但是当二进制数据恰好匹配一个EOL(行尾)字符时,满足规范read()的条件就满足了,缓冲数据被returned。

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

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

ICANON 在 c_lflag 成员中,而不在 c_iflag 中。
所以语句应该是

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

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


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

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

代码中的另一个错误是使用指向数组地址的指针(即地址的地址),而数组地址就足够了。

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

应该只是

bytes_read = read(fd, buf, 1024);

附录

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


附录 2

这个 c_iflagICANON 错误的起源似乎是这个 serial port tutorial from xanthium.in。作者在两年多前就收到了这个错误的通知,但一直没有修复。