我正在编写一个程序,该程序在运行 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_iflag和ICANON错误的起源似乎是这个serial port tutorial from xanthium.in 。作者在两年多前就收到了有关该错误的通知,但尚未修复。
关于c - Ubuntu串行通信: reads failing and then coming in all at once,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51195829/