Linux串口正确的初始化顺序

6

我写了一个应用程序,必须在Linux上使用串口,特别是ttyUSB。读写操作使用标准的select()/read()循环和write()函数执行,它们可能没有问题,但初始化代码(或某些部分缺失)会破坏tty子系统中的某些内容。以下是代码:


  vuxboot(string filename, unsigned baud = B115200) : _debug(false) {
    _fd = open(filename.c_str(), O_RDWR | O_NOCTTY);
    if(_fd < 0) throw new io_error("cannot open port");

    // Serial initialization was written with FTDI USB-to-serial converters
    // in mind. Anyway, who wants to use non-8n1 protocol?

    tcgetattr(_fd, &_termios);

    termios tio = {0};
    tio.c_iflag = IGNPAR;
    tio.c_oflag = 0;
    tio.c_cflag = baud | CLOCAL | CREAD | CS8;
    tio.c_lflag = 0;

    tcflush(_fd, TCIFLUSH);
    tcsetattr(_fd, TCSANOW, &tio);
  }

在析构函数中有另一个tcsetattr(_fd, TCSANOW, &_termios),但它是无关紧要的。

无论是否进行了termios初始化,在应用程序退出后,系统中都会发生奇怪的事情。有时候,普通的cat(或hd)会立即退出,打印出来的东西都一样,有时候它会等待并且不显示肯定发送到端口上的任何数据;而close()read()也是如此,但不是每次)会向dmesg发出奇怪的WARNING,参见usb-serial.c

我检查了硬件和固件很多次(甚至在不同的机器上),我确定它正在按预期工作;此外,我将固件剥离到只是反复打印相同的消息。

如何在不破坏任何内容的情况下使用串行端口? 谢谢。

5个回答

2

遇到WARN_ON行可能意味着你遇到了内核错误。我知道最近一直在改进USB串口驱动程序方面进行了很多工作;建议尝试使用更新的内核版本,或者在linux-usb@vger.kernel.org邮件列表上提问。


这个问题经常被使用Beagle Boards的人们遇到,因为几乎所有连接都是通过USB连接的。我也相当确定他遇到了该子系统中可能存在的几个错误之一。 - Tim Post
1
稳定内核的历史记录表明,自2009年10月左右以来没有进行任何更改。此外,当我使用minicom或类似工具时,“错误”不会出现。 - whitequark

1

我不确定你的代码片段有什么问题,但是如果你还没有看过它,这可能会很有用:POSIX操作系统串行编程指南

最近我不得不进行一些串口接口编程,这个库运行良好,也许可以作为另一个例子。


我刚刚从那个指南中复制了大部分代码。它只是“不太好”,或者我错过了什么吗?我会检查一下那个库,但它是GPL许可的,而我的应用程序使用Expat(又名MIT);而且它的界面也不太好。例如,我想将ttyUSB指定为字符串:在不同的udev配置或有时候它可能会有不同的名称。 - whitequark
是的,我必须承认那篇指南中有一些令人困惑的部分,但那仍然是我能找到的最全面的资源。关于这个库:也许你可以将其用作“健全性检查”,只是为了看看它是否也会破坏你的系统? - Hamza
是的,我已经检查过了,并且可以确认在那个库和我的代码中初始化代码是相同的,除了 O_NDELAY(=O_NONBLOCK)之外。过去我设置了这个选项,结果变得更加奇怪:完全无意义的内容被发送到设备并从设备接收,read()返回错误,syslog 中出现了更多的警告。 - whitequark
不确定这是否与您的问题相关,但我记得几个月前我曾经费了很大的劲才让一个基于PL-2303芯片组的设备工作,并且它曾经在系统中引起各种随机行为。所有其他设备(包括我使用提到的库的那个设备)都是基于FT232芯片的设备。 - Hamza
我的设备是基于FT232RL的。 - whitequark

0

你可以尝试以下方法:

  vuxboot(string filename, unsigned baud = B115200) : _debug(false) {
    _fd = open(filename.c_str(), O_RDWR | O_NOCTTY);
    if(_fd < 0) throw new io_error("cannot open port");

    // Serial initialization was written with FTDI USB-to-serial converters
    // in mind. Anyway, who wants to use non-8n1 protocol?

    tcgetattr(_fd, &_termios);

-   termios tio;
+   termios tio;
+   memcpy(&tio, &_termios, sizeof(struct termios)); 

    tio.c_iflag = IGNPAR;
    tio.c_oflag = 0;
    tio.c_cflag = baud | CLOCAL | CREAD | CS8;
    tio.c_lflag = 0;

    tcflush(_fd, TCIFLUSH);
    tcsetattr(_fd, TCSANOW, &tio);
}

这样做可以使您的系统上任何意外字段的termios获得相当合理的值。


0

仅作为旁注,您在open上的错误检查并不完全正确 - 错误条件是通过返回值-1来表示的。(0是一个完全有效的fd,通常连接到stdin。)


0

好的。这可能不是一个完美的解决方案...它绝对不是。我刚才扔掉了FT232转换器(实际上是烧坏了),并使用了基于CP2102的转换器。现在它可以正常工作了(而且价格也便宜了6倍)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接