当前位置: 首页 > 知识库问答 >
问题:

无法写入串行设备,但可以从中读取

夹谷浩宕
2023-03-14
tSerial::tSerial(const char *serialPort, bool echo)
{
    // Open the serial port. Change device path as needed (currently set to an standard FTDI USB-UART cable type device)
    m_serialPort = open(serialPort, O_RDWR);

    // Create new termios struct, we call it 'tty' for convention
    struct termios tty;

    // Read in existing settings, and handle any error
    if (tcgetattr(m_serialPort, &tty) != 0)
    {
        spdlog::error("[tSerial] error {} from tcgetattr: {}", errno, strerror(errno));
        throw std::runtime_error("Failed to get existing serial settings");
    }

    tty.c_cflag &= ~PARENB;        // Clear parity bit, disabling parity (most common)
    tty.c_cflag &= ~CSTOPB;        // Clear stop field, only one stop bit used in communication (most common)
    tty.c_cflag &= ~CSIZE;         // Clear all bits that set the data size
    tty.c_cflag |= CS8;            // 8 bits per byte (most common)
    tty.c_cflag &= ~CRTSCTS;       // Disable RTS/CTS hardware flow control (most common)
    tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1)

    // tty.c_lflag &= ~ICANON;
    tty.c_cflag |= ICANON;
    if (!echo)
    {
        tty.c_lflag &= ~ECHO; // Disable echo
    }
    else
    {
        tty.c_lflag |= ECHO; // Enable echo
    }

    // tty.c_lflag &= ~ECHOE;                                                       // Disable erasure
    // tty.c_lflag &= ~ECHONL;                                                      // Disable new-line echo
    // tty.c_lflag &= ~ISIG;                                                        // Disable interpretation of INTR, QUIT and SUSP
    tty.c_iflag &= ~(IXON | IXOFF | IXANY);                                      // Turn off s/w flow ctrl
    tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); // Disable any special handling of received bytes

    tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
    tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed

    // Set in/out baud rate to be 115200
    cfsetispeed(&tty, B115200);
    cfsetospeed(&tty, B115200);

    // Save tty settings, also checking for error
    if (tcsetattr(m_serialPort, TCSANOW, &tty) != 0)
    {
        spdlog::error("[tSerial] error {} from tcsetattr: {}", errno, strerror(errno));
        throw std::runtime_error("Failed to set new serial settings");
    }

    // Set non-blocking
    int flags;
    if ((flags = fcntl(m_serialPort, F_GETFL, 0)) == -1)
    {
        flags = 0;
    }
    fcntl(m_serialPort, F_SETFL, flags | O_NONBLOCK);
}
void tSerial::writeSerial(std::string message)
{
    int n;
    fd_set rfds;
    FD_ZERO(&rfds);
    FD_SET(m_serialPort, &rfds);
    spdlog::debug("[tSerial] writing command to serial {}", message);
    struct timeval tv;
    tv.tv_sec = 20;
    tv.tv_usec = 0;
    int retval = select(1, NULL, &rfds, NULL, &tv);
    if (retval == -1)
    {
        spdlog::error("[tSerial] select error");
    }
    else if (retval)
    {

        n = write(m_serialPort, message.c_str(), message.length());
        tcflush(m_serialPort, TCIOFLUSH);
        if (n < 0)
        {
            spdlog::error("[tSerial] error writing: {}", strerror(errno));
        }
    }
    else
    {

        spdlog::error("[tSerial] Resource unavailable after 20 seconds wait");
    }
}

共有1个答案

秦承安
2023-03-14

我正在使用select等待IO资源变得可用...但是即使等待20秒,设备仍然不可用。

由于没有正确编程select()调用,程序的行为没有达到预期:

int retval = select(1, NULL, &rfds, NULL, &tv);

在手册页中,第一个参数“应该设置为三个集合中编号最高的文件描述符,外加1。”
由于传递的值1,所以select()可以检查的唯一文件描述符是stdin(它是只读的,永远不会准备好输出),并且永远不会(文件描述符)打开的串行终端。
相反,系统调用需要是

select(m_serialPort + 1, ...);

您的代码还有其他问题。

(1)使用非阻塞模式是有问题的。
似乎您更喜欢在程序中添加额外的代码以等待,而不是让操作系统为您做这件事。如果您的程序没有有效地利用它的时间片,那么您最好让操作系统管理系统资源。

(2)在write()之后使用tcflush()是荒谬和错误的!
您可能打算使用tcdrain()。
研究手册页。

fd_set rfds;  
...
int retval = select(..., NULL, &rfds, NULL, &tv);

您的程序应该使用类似于wfds的内容作为第三个参数,而不是rfds

...试图直接写入它会出现错误资源暂时不可用

使用select()时的问题很容易解释。
对于上述问题,您需要提供一个最小的、可复制的示例,即一个完整的程序。

 类似资料:
  • 我正在尝试使用Android Studio作为IDE和Java作为编程语言与温度计BLE设备进行交互。使用智能手机上的应用程序,我发现了该设备在运行过程中暴露的服务:有很多通用服务/特性和一个自定义服务。 首先,我试着阅读 健康温度计服务(UUID=00001809-0000-1000-8000-00805F9B34FB) 从服务列表中恢复特征并访问其描述符: 在这种情况下,我可以看到测量的结果在

  • 我正在尝试从Java应用程序的Google Sheets API。我已经访问了教程中提到的文件,但我无法访问我自己创建的任何文件。 这是我使用的代码: 我在Drive中手动创建了一个电子表格,用字符串填充A1: B,并从URL中复制了id,看起来像“1IeoY5jY3Su86x1uvgc1yJqEU-6dd6FdUKo8Yf5J73k”(不是实际的ID)。 这将生成错误400无法解析范围:类数据!

  • 问题内容: 我将Arduino连接到运行循环的计算机,每100毫秒通过串行端口将值发送回计算机。 我想制作一个Python脚本,该脚本仅每隔几秒钟从串行端口读取一次,因此我希望它仅查看Arduino发送的最新消息。 您如何在Pyserial中做到这一点? 这是我尝试的无效代码。它顺序读取行。 问题答案: 也许我误会了您的问题,但是由于它是一条串行线路,因此您必须按顺序读取Arduino发送的所有内

  • 问题内容: 我对读取和写入串行端口有些困惑。我在Linux中有一个使用FTDI USB串行设备转换器驱动程序的USB设备。当我插入它时,它将创建:/ dev / ttyUSB1。 我认为用C打开和读取它很简单。我知道波特率和奇偶校验信息,但是似乎没有标准吗? 我是否缺少某些东西,或者有人可以指出正确的方向? 问题答案: 您必须调用一个从获得。你不能零了,配置它,然后将用。如果使用归零方法,则会遇到

  • 我正在尝试将数据写入我的Arduino Uno,并从中接收日期。 我在Windows 8.1上使用NetBeans,为了做到这一点,库“RXTXcomm.jar”。 我的代码是这样的,我的Arduino在COM3上,它在第25行和第80行抛出一个错误: 错误 java.lang.UnsatisfiedLinkError:java.library中没有rxtxSerial。加载gnu.io时抛出的路

  • 我拥有一个极地H10胸带,它以蓝牙低能量运行,并提供心率和心率变化。 我想用Android应用程序读取这些值。由于官方BLE教程中的帮助,我能够连接到设备。现在的问题是从设备中读取心率和心率变异性值。每次设备上有新值可用时,我都要读取该值(并且至少每秒都有新值)。 我找到了以下代码: 假设我与设备有连接,我如何使用它来提取心率和r-r间隔(节拍到节拍间隔)?如果有人能举个简短的例子,我会很高兴。此