cómo abrir, leer y escribir desde el puerto serie en C

Estoy un poco confundido acerca de leer y escribir en un puerto serie. Tengo un dispositivo USB en Linux que usa el controlador de convertidor de dispositivo en serie FTDI USB. Cuando lo enchufo, crea: / dev / ttyUSB1.

Pensé que sería fácil abrir y leer / escribir en C. Conozco la velocidad en baudios y la información de paridad, pero parece que no hay un estándar para esto.

¿Me estoy perdiendo algo, o alguien puede señalarme en la dirección correcta?

Escribí esto hace mucho tiempo, y simplemente copié y pegué los bits necesarios en cada proyecto.

 #include  #include  #include  #include  #include  int set_interface_attribs (int fd, int speed, int parity) { struct termios tty; memset (&tty, 0, sizeof tty); if (tcgetattr (fd, &tty) != 0) { error_message ("error %d from tcgetattr", errno); return -1; } cfsetospeed (&tty, speed); cfsetispeed (&tty, speed); tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars // disable IGNBRK for mismatched speed tests; otherwise receive break // as \000 chars tty.c_iflag &= ~IGNBRK; // disable break processing 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_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls, // enable reading tty.c_cflag &= ~(PARENB | PARODD); // shut off parity tty.c_cflag |= parity; tty.c_cflag &= ~CSTOPB; tty.c_cflag &= ~CRTSCTS; if (tcsetattr (fd, TCSANOW, &tty) != 0) { error_message ("error %d from tcsetattr", errno); return -1; } return 0; } void set_blocking (int fd, int should_block) { struct termios tty; memset (&tty, 0, sizeof tty); if (tcgetattr (fd, &tty) != 0) { error_message ("error %d from tggetattr", errno); return; } tty.c_cc[VMIN] = should_block ? 1 : 0; tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout if (tcsetattr (fd, TCSANOW, &tty) != 0) error_message ("error %d setting term attributes", errno); } ... char *portname = "/dev/ttyUSB1" ... int fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC); if (fd < 0) { error_message ("error %d opening %s: %s", errno, portname, strerror (errno)); return; } set_interface_attribs (fd, B115200, 0); // set speed to 115,200 bps, 8n1 (no parity) set_blocking (fd, 0); // set no blocking write (fd, "hello!\n", 7); // send 7 character greeting usleep ((7 + 25) * 100); // sleep enough to transmit the 7 plus // receive 25: approx 100 uS per char transmit char buf [100]; int n = read (fd, buf, sizeof buf); // read up to 100 characters if ready to read 

Los valores de velocidad son B115200 , B230400 , B9600 , B19200 , B38400 , B57600 , B1200 , B2400 , B4800 , etc. Los valores para la paridad son 0 (lo que significa que no hay paridad), PARENB|PARODD (habilitar paridad y uso impar), PARENB ( habilitar paridad y usar incluso), PARENB|PARODD|CMSPAR (paridad de marca) y PARENB|CMSPAR (paridad de espacio).

"Bloquear" establece si una read() en el puerto espera a que llegue el número especificado de caracteres. El hecho de no bloquear significa que read() devuelve cuantos caracteres estén disponibles sin esperar más, hasta el límite del buffer.


Apéndice:

CMSPAR solo se necesita para elegir la paridad de marca y espacio, lo cual no es común. Para la mayoría de las aplicaciones, se puede omitir. Mi archivo de cabecera /usr/include/bits/termios.h permite la definición de CMSPAR solo si se define el símbolo del preprocesador __USE_MISC . Esa definición ocurre (en features.h ) con

 #if defined _BSD_SOURCE || defined _SVID_SOURCE #define __USE_MISC 1 #endif 

Los comentarios introductorios de dicen:

 /* These are defined by the user (or the compiler) to specify the desired environment: ... _BSD_SOURCE ISO C, POSIX, and 4.3BSD things. _SVID_SOURCE ISO C, POSIX, and SVID things. ... */ 

Para el código de demostración que cumple con el estándar POSIX como se describe en Configuración correcta de los modos de los terminales y la Guía de progtwigción en serie para los sistemas operativos POSIX , se ofrece lo siguiente.
Se deriva esencialmente de la otra respuesta, pero se corrigieron comentarios inexactos y engañosos.

 #include  #include  #include  #include  #include  #include  #include  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 |= (CLOCAL | CREAD); /* ignore modem controls */ 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 */ /* setup for non-canonical mode */ tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); tty.c_oflag &= ~OPOST; /* fetch bytes as they become available */ tty.c_cc[VMIN] = 1; tty.c_cc[VTIME] = 1; if (tcsetattr(fd, TCSANOW, &tty) != 0) { printf("Error from tcsetattr: %s\n", strerror(errno)); return -1; } return 0; } void set_mincount(int fd, int mcount) { struct termios tty; if (tcgetattr(fd, &tty) < 0) { printf("Error tcgetattr: %s\n", strerror(errno)); return; } tty.c_cc[VMIN] = mcount ? 1 : 0; tty.c_cc[VTIME] = 5; /* half second timer */ if (tcsetattr(fd, TCSANOW, &tty) < 0) printf("Error tcsetattr: %s\n", strerror(errno)); } int main() { char *portname = "/dev/ttyUSB0"; int fd; int wlen; fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); if (fd < 0) { printf("Error opening %s: %s\n", portname, strerror(errno)); return -1; } /*baudrate 115200, 8 bits, no parity, 1 stop bit */ set_interface_attribs(fd, B115200); //set_mincount(fd, 0); /* set to pure timed read */ /* simple output */ wlen = write(fd, "Hello!\n", 7); if (wlen != 7) { printf("Error from write: %d, %d\n", wlen, errno); } tcdrain(fd); /* delay for output */ /* simple noncanonical input */ do { unsigned char buf[80]; int rdlen; rdlen = read(fd, buf, sizeof(buf) - 1); if (rdlen > 0) { #ifdef DISPLAY_STRING buf[rdlen] = 0; printf("Read %d: \"%s\"\n", rdlen, buf); #else /* display hex */ unsigned char *p; printf("Read %d:", rdlen); for (p = buf; rdlen-- > 0; p++) printf(" 0x%x", *p); printf("\n"); #endif } else if (rdlen < 0) { printf("Error from read: %d: %s\n", rdlen, strerror(errno)); } /* repeat read to get full message */ } while (1); } 

Para que el progtwig trate los datos recibidos como códigos ASCII, compile el progtwig con el símbolo DISPLAY_STRING, por ej.

  cc -DDISPLAY_STRING demo.c