versiones serie serial que puertos puerto probar minicom habilitar com1 c linux serial-port tty

serie - que es minicom



Lectura/escritura en puerto serie Linux C (3)

Estoy tratando de enviar / recibir datos a través de un puerto USB usando FTDI , así que necesito manejar la comunicación serial usando C / C ++. Estoy trabajando en Linux (Ubuntu).

Básicamente, estoy conectado a un dispositivo que está escuchando los comandos entrantes. Necesito enviar esos comandos y leer la respuesta del dispositivo. Ambos comandos y respuesta son caracteres ASCII .

Todo funciona bien usando GtkTerm pero, cuando cambio a la programación C, encuentro problemas.

Aquí está mi código:

#include <stdio.h> // standard input / output functions #include <stdlib.h> #include <string.h> // string function definitions #include <unistd.h> // UNIX standard function definitions #include <fcntl.h> // File control definitions #include <errno.h> // Error number definitions #include <termios.h> // POSIX terminal control definitions /* Open File Descriptor */ int USB = open( "/dev/ttyUSB0", O_RDWR| O_NONBLOCK | O_NDELAY ); /* Error Handling */ if ( USB < 0 ) { cout << "Error " << errno << " opening " << "/dev/ttyUSB0" << ": " << strerror (errno) << endl; } /* *** Configure Port *** */ struct termios tty; memset (&tty, 0, sizeof tty); /* Error Handling */ if ( tcgetattr ( USB, &tty ) != 0 ) { cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << endl; } /* Set Baud Rate */ cfsetospeed (&tty, B9600); cfsetispeed (&tty, B9600); /* Setting other Port Stuff */ tty.c_cflag &= ~PARENB; // Make 8n1 tty.c_cflag &= ~CSTOPB; tty.c_cflag &= ~CSIZE; tty.c_cflag |= CS8; tty.c_cflag &= ~CRTSCTS; // no flow control tty.c_lflag = 0; // no signaling chars, no echo, no canonical processing tty.c_oflag = 0; // no remapping, no delays tty.c_cc[VMIN] = 0; // read doesn''t block tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout tty.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines tty.c_iflag &= ~(IXON | IXOFF | IXANY);// turn off s/w flow ctrl tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw tty.c_oflag &= ~OPOST; // make raw /* Flush Port, then applies attributes */ tcflush( USB, TCIFLUSH ); if ( tcsetattr ( USB, TCSANOW, &tty ) != 0) { cout << "Error " << errno << " from tcsetattr" << endl; } /* *** WRITE *** */ unsigned char cmd[] = {''I'', ''N'', ''I'', ''T'', '' '', ''/r'', ''/0''}; int n_written = write( USB, cmd, sizeof(cmd) -1 ); /* Allocate memory for read buffer */ char buf [256]; memset (&buf, ''/0'', sizeof buf); /* *** READ *** */ int n = read( USB, &buf , sizeof buf ); /* Error Handling */ if (n < 0) { cout << "Error reading: " << strerror(errno) << endl; } /* Print what I read... */ cout << "Read: " << buf << endl; close(USB);

Lo que ocurre es que read() devuelve 0 (no se leen los bytes) o bloquea hasta el tiempo de espera ( VTIME ). Supongo que esto sucede porque write() no envía nada. En ese caso, el dispositivo no recibiría el comando y no puedo recibir respuesta. De hecho, apagar el dispositivo mientras mi programa está bloqueado al leer en realidad tuvo éxito al obtener una respuesta (el dispositivo envía algo mientras se apaga).

Lo extraño es que agregar esto

cout << "I''ve written: " << n_written << "bytes" << endl;

justo después de la llamada a write() , recibo:

I''ve written 6 bytes

que es exactamente lo que espero. Solo mi programa no funciona como debería, como que mi dispositivo no puede recibir lo que estoy escribiendo en el puerto.

He probado diferentes cosas y soluciones, también con respecto a los tipos de datos (he intentado usar std :: string, como cmd = "INIT /r" o const char ) pero nada funcionó realmente.

¿Puede alguien decirme dónde me equivoco?

Gracias de antemano.

EDITAR: Anteriormente se usaba la versión de este código

unsigned char cmd[] = "INIT /n"

y también cmd[] = "INIT /r/n" . Lo cambié porque el comando sintax para mi dispositivo se informa como

<command><SPACE><CR> .

También intenté evitar la bandera O_NONBLOCK al leer, pero luego solo O_NONBLOCK hasta siempre. He intentado usar select() pero no pasa nada. Solo por intentarlo, he creado un ciclo de espera hasta que los datos estén disponibles, pero mi código nunca sale del ciclo. Por cierto, esperar o usleep() es algo que debo evitar. El reportado es solo un extracto de mi código. El código completo debe funcionar en un entorno en tiempo real (específicamente OROCOS), por lo que realmente no quiero que funcione como un sueño.


1) Añadiría un / n después de init. es decir, escribir (USB, "init / n", 5);

2) Verifique la configuración del puerto serie. Las probabilidades son que algo está incorrecto allí. Solo porque no use ^ Q / ^ S o el control de flujo de hardware no significa que el otro lado no lo esté esperando.

3) Más probable: agregue un "usleep (100000); después de la escritura () . El archivo-descriptor está configurado para no bloquear o esperar, ¿verdad? ¿Cuánto tiempo lleva recuperar una respuesta antes de que pueda llamar a read? Tiene que ser recibido y almacenado por el kernel, a través de las interrupciones de hardware del sistema, antes de que pueda leerlo () . ¿Ha considerado usar select () para esperar que algo se lea () ? ¿Tal vez con un tiempo de espera?

Editado para agregar:

¿Necesitas las líneas DTR / RTS? ¿Control de flujo de hardware que le dice a la otra parte que envíe los datos de la computadora? p.ej

int tmp, serialLines; cout << "Dropping Reading DTR and RTS/n"; ioctl ( readFd, TIOCMGET, & serialLines ); serialLines &= ~TIOCM_DTR; serialLines &= ~TIOCM_RTS; ioctl ( readFd, TIOCMSET, & serialLines ); usleep(100000); ioctl ( readFd, TIOCMGET, & tmp ); cout << "Reading DTR status: " << (tmp & TIOCM_DTR) << endl; sleep (2); cout << "Setting Reading DTR and RTS/n"; serialLines |= TIOCM_DTR; serialLines |= TIOCM_RTS; ioctl ( readFd, TIOCMSET, & serialLines ); ioctl ( readFd, TIOCMGET, & tmp ); cout << "Reading DTR status: " << (tmp & TIOCM_DTR) << endl;


Algunos receptores esperan una secuencia EOL, que normalmente es de dos caracteres /r/n , así que intente reemplazar la línea con el código

unsigned char cmd[] = {''I'', ''N'', ''I'', ''T'', '' '', ''/r'', ''/0''};

con

unsigned char cmd[] = "INIT/r/n";

Por cierto, la forma anterior es probablemente más eficiente. No hay necesidad de citar a cada personaje.


He resuelto mis problemas, así que publico aquí el código correcto en caso de que alguien necesite algo similar.

Puerto abierto

int USB = open( "/dev/ttyUSB0", O_RDWR| O_NOCTTY );

Establecer parámetros

struct termios tty; struct termios tty_old; memset (&tty, 0, sizeof tty); /* Error Handling */ if ( tcgetattr ( USB, &tty ) != 0 ) { std::cout << "Error " << errno << " from tcgetattr: " << strerror(errno) << std::endl; } /* Save old tty parameters */ tty_old = tty; /* Set Baud Rate */ cfsetospeed (&tty, (speed_t)B9600); cfsetispeed (&tty, (speed_t)B9600); /* Setting other Port Stuff */ tty.c_cflag &= ~PARENB; // Make 8n1 tty.c_cflag &= ~CSTOPB; tty.c_cflag &= ~CSIZE; tty.c_cflag |= CS8; tty.c_cflag &= ~CRTSCTS; // no flow control tty.c_cc[VMIN] = 1; // read doesn''t block tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout tty.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines /* Make raw */ cfmakeraw(&tty); /* Flush Port, then applies attributes */ tcflush( USB, TCIFLUSH ); if ( tcsetattr ( USB, TCSANOW, &tty ) != 0) { std::cout << "Error " << errno << " from tcsetattr" << std::endl; }

Escribir

unsigned char cmd[] = "INIT /r"; int n_written = 0, spot = 0; do { n_written = write( USB, &cmd[spot], 1 ); spot += n_written; } while (cmd[spot-1] != ''/r'' && n_written > 0);

Definitivamente no era necesario escribir bytes por byte, también int n_written = write( USB, cmd, sizeof(cmd) -1) funcionaba bien.

Por fin, lee :

int n = 0, spot = 0; char buf = ''/0''; /* Whole response*/ char response[1024]; memset(response, ''/0'', sizeof response); do { n = read( USB, &buf, 1 ); sprintf( &response[spot], "%c", buf ); spot += n; } while( buf != ''/r'' && n > 0); if (n < 0) { std::cout << "Error reading: " << strerror(errno) << std::endl; } else if (n == 0) { std::cout << "Read nothing!" << std::endl; } else { std::cout << "Response: " << response << std::endl; }

Éste trabajó para mí. ¡Gracias a todos!