我在设备模式下使用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;
}
答案 0 :(得分:4)
除了不禁用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 <string.h>
您复制的 termios 初始化例程(但随后被错误地修改)会正确检查返回值,但您的读写例程不会检查错误。
答案 1 :(得分:0)
我从每个人的答案中学到了很多东西,并对他们表示感谢,因为随着这个项目的继续,我将需要他们。但是,对于此特定情况,问题最终成为权限。是的,ttyGSO
上的文件权限。
我完全期望来自permission denied
的{{1}}错误而且永远不会有错误,所以我从未考虑过这种可能性。特别是自从我以open
模式打开文件后,我可以写入串行文件,出现我正在读取数据(虽然是相同的数据)我从来没有意识到我也许没有读权限。