Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 从串行端口读取总是返回写入的内容_C_Serial Port_Usb - Fatal编程技术网

C 从串行端口读取总是返回写入的内容

C 从串行端口读取总是返回写入的内容,c,serial-port,usb,C,Serial Port,Usb,我在设备模式下使用Raspberry Pi Zero,在主机模式下使用Raspberry Pi B。我正在用USB线连接这两个。我现在的目标只是在两个Pi之间来回发送简单、任意的数据 问题是,无论哪个Pi先写入串行端口,最终都会读取它所写入的内容。我编写的程序让设备发送d\n,主机发送h\n。因此,如果设备先写入,主机将正确读取d\n,然后将h\n写入串行端口。但是设备最终读取的是d\n!如果我将其切换为主机先写入,则问题仍然存在 我曾尝试在编写程序之后但在读取之前向程序添加各种tcflush调

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

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

我曾尝试在编写程序之后但在读取之前向程序添加各种
tcflush
调用,但都不起作用。我也尝试了不同时间的睡眠。我读过每写一个字符都要等100微秒,我睡了几秒钟

我的设置要求我不能同时在两个Pi之间保持恒定连接,因为Pi Zero只有一个支持数据的usb端口。所以,为了测试,我实际上插入了一个键盘并运行程序,然后插入合适的电缆来传输数据。我可以传输数据,但不能在写入数据后传输,因为程序只是简单地读回它所写的内容

我开始觉得我掉进了一个我无法理解的陷阱。以下是我正在使用的代码:

#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;
}
#包括
#包括
#包括
#包括
#包括
/*
*gcc-o设备\u rw-d设备串行\u rw.c
*gcc-o主机\u rw串行\u rw.c
*/
#定义串行设备“/dev/ttyGS0”
#定义串行_主机“/dev/ttyACM0”
#ifdef设备
#定义串行设备
#否则
#定义\u TTY串行\u主机
#恩迪夫
int
设置接口属性(int fd,int speed)
{
结构termios tty;
如果(tcgetattr(fd和tty)<0){
printf(“来自tcgetattr的错误:%s\n”,strerror(errno));
返回-1;
}
cfsetospeed(&tty,(速度)速度);
cfsetispeed(速度)和tty(速度);
tty.c_cflag&=~PARENB;/*无奇偶校验位*/
tty.c_cflag&=~CSTOPB;/*只需要1个停止位*/
tty.c_cflag&=~CSIZE;
tty.c_cflag |=CS8;/*8位字符*/
tty.c\u cflag&=~CRTSCTS;/*无硬件流量控制*/
tty.c|u cflag |=(CLOCAL | CREAD);/*忽略调制解调器控制*/
tty.c|U iflag |=IGNPAR | IGNCR;
tty.c|u iflag&=~(IXON | IXOFF | IXANY);
tty.c|U iflag |=ICANON;
tty.c_iflag和OPOST;
如果(tcsetattr(fd、TCSANOW和tty)!=0){
printf(“来自tcsetttr的错误:%s\n”,strerror(errno));
返回-1;
}
返回0;
}
无效的
写入串行(int-fd,const-char*buf,int-len)
{
printf(“写入:%s\n”,buf);
写入(fd、buf、len);
}
无效的
只读串行(整型fd,字符*buf,整型len)
{
ssize_t nread=读取(fd、buf、len);

如果(nread>0&&nread除了不禁用ECHO属性之外(如@MarkPlotnick所评论),您有两个误用的赋值:

tty.c_iflag |= ICANON;
ICANON属于lflag成员,并且

tty.c_iflag &= ~OPOST;
OPOST属于oflag成员。
考虑到这些错误,您是否正确地应用了@MarkPlotnick的建议

有关正常工作的设置,请参阅

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到串行适配器),然后进行传输。
如果您仍然获得echo,那么它将在本地生成,由termios echo属性控制。
如果您不再收到回音,则是远程设备将其输入重复回发送方


顺便说一句,您发布的程序编译不干净。
缺少
#包含


您复制(但随后被错误修改)的termios初始化例程对返回值进行了正确的检查,但您的读写例程不会检查错误。

除了不禁用ECHO属性(如@MarkPlotnick所评论)外,您还有两个误用的赋值:

tty.c_iflag |= ICANON;
ICANON属于lflag成员,并且

tty.c_iflag &= ~OPOST;
OPOST属于oflag成员。
考虑到这些错误,您是否正确地应用了@MarkPlotnick的建议

有关正常工作的设置,请参阅

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到串行适配器),然后进行传输。
如果您仍然获得echo,那么它将在本地生成,由termios echo属性控制。
如果您不再收到回音,则是远程设备将其输入重复回发送方


顺便说一句,您发布的程序编译不干净。
缺少
#包含


您复制(但随后被错误修改)的termios初始化例程对返回值进行了正确的检查,但您的读写例程不会检查错误。

我从每个人的答案中学到了很多,并对他们表示感谢,因为我在继续这个项目时需要他们。但是,对于这种特殊情况,问题最终是权限。是的,
ttyGSO
上的文件权限


我完全预料到
打开时会出现
权限被拒绝
的错误,但从未出现过,因此我从未考虑过这种可能性。特别是因为我在
RDWR
模式下打开了文件,我可以写入串行文件,似乎我正在读取数据(尽管数据相同)我从来没有意识到我可能没有阅读权限。

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

我完全希望
权限被拒绝
错误