177 votes

comment ouvrir, lire et écrire à partir du port série en C

Je suis un peu confus à propos de la lecture et de l'écriture sur un port série. J'ai un périphérique USB sous Linux qui utilise le pilote de convertisseur de périphérique série FTDI USB. Lorsque je le branche, il crée: / dev / ttyUSB1.

Je pensais qu'il serait simple d'ouvrir et de lire / écrire en C. Je connais le débit en bauds et les informations de parité, mais il semble qu'il n'y ait pas de standard pour cela?

Est-ce que je manque quelque chose, ou quelqu'un peut-il me diriger dans la bonne direction?

282voto

wallyk Points 33150

J'ai écrit cela il y a longtemps, et il suffit de copier et coller les bits nécessaires à chaque projet.

#include <errno.h>
#include <termios.h>
#include <unistd.h>

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

Les valeurs de vitesse sont B115200, B230400, B9600, B19200, B38400, B57600, B1200, B2400, B4800, etc. Les valeurs de parité sont 0 (ce qui signifie pas de parité), PARENB|PARODD (permettre à la parité et à l'utilisation impair), PARENB (permettre à la parité et à l'utilisation même), PARENB|PARODD|CMSPAR (marque de la parité), et PARENB|CMSPAR (de l'espace de parité).

"Blocage" permet de définir si un read() sur le port attend pour le nombre spécifié de caractères à arriver. Paramètre aucun blocage signifie que l' read() renvoie cependant, de nombreux personnages sont disponibles, sans attendre plus, jusqu'à la limite de tampon.


Addendum:

CMSPAR n'est nécessaire que pour le choix de la marque et de l'espace de parité, ce qui est rare. Pour la plupart des applications, il peut être omis. Mon fichier d'en-tête /usr/include/bits/termios.h permet de définir des CMSPAR seulement si le symbole de préprocesseur __USE_MISC est défini. Cette définition se produit (en features.h) avec

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

Les commentaires d'introduction de l' <features.h> dit:

/* 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.
...
 */

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X