c - Ubuntu串行通信: reads failing and then coming in all at once

标签 c serial-port ubuntu-14.04 termios

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

我正在使用 termios 设置串行端口。这是我的代码。我尝试过将其设置为阻塞配置,但如果我这样做,代码就会在第一次 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");

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

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 个字节)。

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

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

任何帮助将不胜感激!

更新: 我也将我的笔记本电脑连接到串行端口,这样我就可以使用 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()将返回-1和errno(您可以这样做懒得检查)设置为-EAGAIN。
但是,当二进制数据恰好匹配 EOL(行尾)字符时,满足规范 read() 的条件就满足,并且返回缓冲的数据。

串行终端实际上​​没有配置为非规范模式的原因是因为 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 。作者在两年多前就收到了有关该错误的通知,但尚未修复。

关于c - Ubuntu串行通信: reads failing and then coming in all at once,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51195829/

相关文章:

c++ - 为什么当内存中的类对象已经是二进制 (C/C++) 时进行序列化?

c - C 中矩阵与 vector 相乘

c - BST 节点删除函数在递归调用时失败

响应 AT 调制解调器,缓冲区数组中的检查值为 0 且不为 NULL?

PHP 启动 : Unable to load dynamic library `curl.so` Ubuntu

c - 当我的 fgets 输入超过指定的缓冲区大小时,我的(非常简单的)程序似乎表现出奇怪的行为

java - 重写serialEvent两次

Android 与 USB 到串行设备的通信和 controlTransfers

docker - 运行“docker-compose up时出错

android - zipalign : error while loading shared libraries: libc++. 所以:无法打开共享对象文件:没有这样的文件或目录