C 从串行端口读取总是返回写入的内容
我在设备模式下使用Raspberry Pi Zero,在主机模式下使用Raspberry Pi B。我正在用USB线连接这两个。我现在的目标只是在两个Pi之间来回发送简单、任意的数据 问题是,无论哪个Pi先写入串行端口,最终都会读取它所写入的内容。我编写的程序让设备发送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调
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
上的文件权限
我完全希望权限被拒绝
错误