【问题标题】:reading from serial port always returns what was written从串口读取总是返回写入的内容
【发布时间】:2016-12-28 19:06:36
【问题描述】:

我在设备模式下使用 Raspberry Pi Zero,在主机模式下使用 Raspberry Pi B。我用 USB 数据线将两者连接起来。我现在的目标只是在两个 Pi 之间来回发送简单的任意数据。

问题是,无论 Pi 先写入串行端口,最终都会读取它写入的内容。我编写的程序让设备发送d\n,主机发送h\n。因此,如果设备先写入,则主机正确读取d\n,然后将h\n 写入串行端口。但设备最终读取d\n!如果我切换它以便主机先写入,问题仍然存在。

我尝试在写入之后但在读取之前向程序添加各种tcflush 调用,但它不起作用。我也试过睡不同的时间。我已经阅读了为每个写入的字符等待 100 微秒,并且我已经睡了几秒钟。

由于 Pi Zero 的单个支持数据的 USB 端口,我的设置要求我不能同时在两个 Pi 之间建立持续连接。所以,为了测试,我实际上是插入键盘并运行程序,然后插入正确的电缆来传输数据。我可以传输数据,但不能在写入后传输,因为程序只是读回它写入的内容。

我开始认为我掉进了一个我无法理解的菜鸟陷阱。这是我正在使用的代码:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>    
#include <termios.h>
#include <errno.h>

/*
 * gcc -o device_rw -DDEVICE serial_rw.c
 * gcc -o host_rw serial_rw.c
 */

#define SERIAL_DEVICE "/dev/ttyGS0"
#define SERIAL_HOST   "/dev/ttyACM0"

#ifdef DEVICE
#define _TTY SERIAL_DEVICE
#else
#define _TTY SERIAL_HOST
#endif

int
set_interface_attribs(int fd, int speed)
{
    struct termios tty;

    if (tcgetattr(fd, &tty) < 0) {
        printf("Error from tcgetattr: %s\n", strerror(errno));
        return -1;
    }

    cfsetospeed(&tty, (speed_t)speed);
    cfsetispeed(&tty, (speed_t)speed);

    tty.c_cflag &= ~PARENB;     /* no parity bit */
    tty.c_cflag &= ~CSTOPB;     /* only need 1 stop bit */
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;         /* 8-bit characters */

    tty.c_cflag &= ~CRTSCTS;    /* no hardware flowcontrol */
    tty.c_cflag |= (CLOCAL | CREAD);    /* ignore modem controls */

    tty.c_iflag |= IGNPAR | IGNCR;
    tty.c_iflag &= ~(IXON | IXOFF | IXANY);
    tty.c_iflag |= ICANON;
    tty.c_iflag &= ~OPOST;

    if (tcsetattr(fd, TCSANOW, &tty) != 0) {
        printf("Error from tcsetattr: %s\n", strerror(errno));
        return -1;
    }

    return 0;
}

void
write_serial (int fd, const char *buf, int len)
{
    printf("WRITE: %s\n", buf);
    write(fd, buf, len);
}

void
read_serial (int fd, char *buf, int len)
{
    ssize_t nread = read(fd, buf, len);
    if (nread > 0 && nread <= len) {
      buf[nread] = 0;
      printf(" READ: %s\n", buf);
    }
}

int 
main (int argc, char **argv)
{
    char buf[80];
    int fd = open(_TTY, O_RDWR | O_NOCTTY);

    if (fd < 0) {
      fprintf(stderr, "Can't open %s: %s\n", _TTY, strerror(errno));
      goto exit;
    }

    if (set_interface_attribs(fd, B115200) < 0) {
      goto exit;
    }

#ifdef DEVICE
    printf("device: %s\n", _TTY);
    write_serial(fd, "d\n", 2);
    usleep((2 + 25) * 100);
    read_serial(fd, buf, 2);
#else
    printf("host: %s\n", _TTY);
    read_serial(fd, buf, 2);
    //usleep((2 + 25) * 100);
    write_serial(fd, "h\n", 2);
#endif

    close(fd);
exit:
    return 0;
}

【问题讨论】:

  • 你把#define DEVICE放在哪里以满足#ifdef DEVICE控制的编译版本?
  • 我用-DDEVICE编译来触发它。
  • 哦,我明白了,如代码中所述。但我不喜欢它——会导致手指麻烦。我建议必须定义一个特定值,否则编译将失败。
  • 尝试添加tty.c_lflag &amp;= ~ECHO;
  • @MarkPlotnick 没有成功。仍在读取写入的数据。

标签: c serial-port usb


【解决方案1】:

除了不禁用 ECHO 属性(正如@MarkPlotnick 评论的那样),您还有两个误用的分配:

tty.c_iflag |= ICANON;

ICANON 属于 lflag 成员,并且

tty.c_iflag &= ~OPOST;

OPOST 属于 oflag 成员。
考虑到这些错误,您是否正确应用了@MarkPlotnick 的建议?

请参阅 Working with linux serial port in C, Not able to get full data 了解有效的规范设置。

cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);

tty.c_cflag |= CLOCAL | CREAD;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;         /* 8-bit characters */
tty.c_cflag &= ~PARENB;     /* no parity bit */
tty.c_cflag &= ~CSTOPB;     /* only need 1 stop bit */
tty.c_cflag &= ~CRTSCTS;    /* no hardware flowcontrol */

tty.c_lflag |= ICANON | ISIG;  /* canonical input */
tty.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN);

tty.c_iflag &= ~INPCK;
tty.c_iflag |= IGNCR;
tty.c_iflag &= ~(INLCR | ICRNL | IUCLC | IMAXBEL);
tty.c_iflag &= ~(IXON | IXOFF | IXANY);   /* no SW flowcontrol */

tty.c_oflag &= ~OPOST;

请注意,也可以在远端启用回声。
要确定回声是在本地生成还是从远端生成,只需断开远程设备(假设您使用的是 UART 和/或 USB 转串口适配器),然后进行传输。
如果您仍然得到回声,那么它是在本地生成的,由 termios ECHO 属性控制。
如果您不再收到回声,那么就是远程单元将其输入重复回发送者。


顺便说一句,您发布的程序编译不干净。
它不见了#include &lt;string.h&gt;
您复制的 termios 初始化例程(但随后被错误修改)对返回值进行了适当的检查,但您的读取和写入例程不检查错误。

【讨论】:

    【解决方案2】:

    我从每个人的回答中学到了很多东西,我很感激他们,因为在我继续这个项目的过程中我会需要他们。然而,对于 this 特殊情况,问题最终是权限。是的,ttyGSO 的文件权限。

    我完全预料到 open 会出现 permission denied 错误,但从未遇到过,所以我从未考虑过这种可能性。特别是因为我以RDWR 模式打开文件,我可以写入串行文件,它出现我正在读取数据(虽然是相同的数据),但我从未意识到也许我没有没有读取权限。

    【讨论】:

      猜你喜欢
      • 2018-01-03
      • 2019-04-25
      • 1970-01-01
      • 2015-12-01
      • 1970-01-01
      • 2021-07-28
      • 2010-11-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多