C - 串行设备未收到数据

时间:2018-04-27 05:59:40

标签: c serial-port

我正在使用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)。

1 个答案:

答案 0 :(得分:1)

嗯,我担心你没有按照正确的程序设置termios参数。首先,必须使用 tcgetattrs(3)来获取实际配置的参数(并初始化termios结构,否则在代码中未初始化为垃圾,因为您已将其声明为自动变量),然后你改变你想要的,然后你设置所需的配置。

正确的程序是:

 struct termios param;
 res = tcgetattrs(fd, &param); /* VERY IMPORTANT: first get the actual parameters */
 if (res < 0) {
      perror("tegetattrs");
      exit(EXIT_FAILURE);
 }
 cfsetispeed(&param, B38400);
 cfsetospeed(&param, B38400);
 param.c_cflag &= ~PARENB;
 /* ... all the needed configuration. */
 /* and finally. */
 res = tcsetattrs(fd, &param);
 if (res < 0) { /* error */
     perror("tcsetattrs");
     exit(EXIT_FAILURE);
 }

(另外,检查返回值res是否常见错误)

正如手册页termios(3)所述,与设置线速度有关:

  

线速度

     

波特率功能用于获取和设置值     termios结构中的输入和输出波特率。该     新值tcsetattr()成功之前不会生效     称为

     

将速度设置为B0指示调制解调器“挂断”&#34;。实际上     与B38400对应的比特率可能会随setserial(8)而改变。

     

输入和输出波特率存储在termios结构中。

(报价是我的)