我正在使用C打开串行设备并向其发送/接收数据。接收工作没有问题,但我发送的任何数据都没有到达设备。我打开这样的设备:
int open_tty() {
int fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_CLOEXEC);
struct termios config;
cfsetispeed(&config, B38400);
cfsetospeed(&config, B38400);
config.c_cflag &= ~PARENB;
config.c_cflag &= ~CSTOPB;
config.c_cflag &= ~CSIZE;
config.c_cflag |= CS8;
tcsetattr(fd, TCSANOW, &config);
return fd;
}
...
write(fd, data, length)
...
根据strace,一切正常:
openat(AT_FDCWD, "/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_CLOEXEC) = 3
ioctl(3, TCGETS, {B38400 -opost isig icanon echo ...}) = 0
ioctl(3, SNDCTL_TMR_START or TCSETS, {B38400 -opost isig icanon echo ...}) = 0
ioctl(3, TCGETS, {B38400 -opost isig icanon echo ...}) = 0
write(3, "some data.......", 16) = 16
但是,设备不接收任何数据(它应该发送ACK数据包)。如果我在python中做同样的事情,一切都运行正常:
s=serial.Serial('/dev/ttyUSB0', baudrate=9600*4)
s.write('some data.......')
strace的:
openat(AT_FDCWD, "/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_NONBLOCK|O_CLOEXEC) = 3
ioctl(3, TCGETS, {B38400 -opost isig icanon echo ...}) = 0
ioctl(3, TCGETS, {B38400 -opost isig icanon echo ...}) = 0
ioctl(3, TCGETS, {B38400 -opost isig icanon echo ...}) = 0
ioctl(3, SNDCTL_TMR_START or TCSETS, {B38400 -opost -isig -icanon -echo ...}) = 0
ioctl(3, TCGETS, {B38400 -opost -isig -icanon -echo ...}) = 0
ioctl(3, TIOCMBIS, [TIOCM_DTR]) = 0
ioctl(3, TIOCMBIS, [TIOCM_RTS]) = 0
ioctl(3, TCFLSH, TCIFLUSH) = 0
write(3, "some data.......", 16) = 16
非常感谢任何帮助。
编辑: 正如@abarnert建议的那样,我设置DTR和RTS位并刷新缓冲区:
char rts = TIOCM_RTS;
char dtr = TIOCM_DTR;
ioctl(fd, TIOCMBIS, &dtr);
ioctl(fd, TIOCMBIS, &rts);
tcflush(fd, TCIFLUSH);
这导致在write
调用之前直接调度以下附加系统调用:
ioctl(3, TIOCMBIS, [TIOCM_DTR|TIOCM_DSR|0x200]) = 0
ioctl(3, TIOCMBIS, [[TIOCM_RTS|0x30200}) = 0
ioctl(3, TCFLSH, TCIFLUSH) = 0
但是,我仍然没有收到任何来自设备的ACK数据包。
该设备是使用USB转串口转换器连接的VirtualRobotix GPS uBlox 8(http://www.virtualrobotix.it/index.php/en/shop/gps/3dr-gps-ublox-8-542015-11-30-13-35-34_-detail)。
答案 0 :(得分:1)
嗯,我担心你没有按照正确的程序设置termios
参数。首先,必须使用 tcgetattrs(3)
来获取实际配置的参数(并初始化termios
结构,否则在代码中未初始化为垃圾,因为您已将其声明为自动变量),然后你改变你想要的,然后你设置所需的配置。
正确的程序是:
struct termios param;
res = tcgetattrs(fd, ¶m); /* VERY IMPORTANT: first get the actual parameters */
if (res < 0) {
perror("tegetattrs");
exit(EXIT_FAILURE);
}
cfsetispeed(¶m, B38400);
cfsetospeed(¶m, B38400);
param.c_cflag &= ~PARENB;
/* ... all the needed configuration. */
/* and finally. */
res = tcsetattrs(fd, ¶m);
if (res < 0) { /* error */
perror("tcsetattrs");
exit(EXIT_FAILURE);
}
(另外,检查返回值res
是否常见错误)
正如手册页termios(3)
所述,与设置线速度有关:
线速度
波特率功能用于获取和设置值
termios
结构中的输入和输出波特率。该 新值在tcsetattr()
成功之前不会生效 称为强>将速度设置为
B0
指示调制解调器“挂断”&#34;。实际上 与B38400
对应的比特率可能会随setserial(8)
而改变。输入和输出波特率存储在
termios
结构中。
(报价是我的)