Ubuntu串行通信:读取失败然后立即进入

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ubuntu串行通信:读取失败然后立即进入相关的知识,希望对你有一定的参考价值。

我正在编写一个程序,该程序在运行Ubuntu服务器14.04的MIO-3260单板计算机上运行,​​并与AMC DPRANIE C100A400驱动器通信。程序向驱动器发送一串十六进制代码,并且应该为它发送的每条消息接收响应。当我在Windows上的realTerm中尝试它时效果很好所以我不认为这是驱动器的问题。但是,当我尝试从串口读取时,read()几乎一直都会返回-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("
 ERROR: setting attributes");
else
    printf("
 Baudrate = 115200 	 Stopbits = 1 	 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	",buf[i]);
        puts("
");
}

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

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

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

任何帮助将非常感激!

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

答案

我已经尝试在阻塞配置中进行设置,但如果我这样做,代码只会在第一次读取()时无限期挂起。

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

但是,当我尝试从串口读取时,read()几乎一直都会返回-1,直到突然出现在一个看似随机的点上,我立刻得到了大量的消息。

您描述的结果类似于非阻塞规范模式(当您实际需要(阻止)原始模式时)。 当缓冲区中没有数据(即完整的行)可用时,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 bug的起源似乎是这个serial port tutorial from xanthium.in。两年前,作者被告知该错误,但尚未解决。

以上是关于Ubuntu串行通信:读取失败然后立即进入的主要内容,如果未能解决你的问题,请参考以下文章

串行通信协议

Arduino Uno Raspberry Pi 串行通信双读数

如果串行接口具有异步读取数据,则 C++ Ubuntu select()

虚拟 COM 端口 STM32 和 Qt 串行端口

我可以使用jssc与虚拟串行设备通信吗? ttyS0配置问题(Ubuntu)

Android 与 Ubuntu 的蓝牙串行通信