Я немного запутался в чтении и записи в последовательный порт. У меня есть USB-устройство в Linux, которое использует драйвер конвертера последовательного USB-устройства FTDI. Когда я подключаю его, он создает: / dev / ttyUSB1.
Я думал, что будет просто открыть и читать / писать из него на C. Я знаю скорость передачи и информацию о четности, но похоже, что для этого нет стандарта?
Я что-то упускаю или кто-то может указать мне правильное направление?
c
linux
serial-port
гничи
источник
источник
ioctl
иfcntl
.Ответы:
Я написал это очень давно ( с 1985 по 1992 год, с тех пор было внесено всего несколько изменений ) и просто копирую и вставляю нужные биты в каждый проект.
Вы должны позвонить
cfmakeraw
поtty
полученному отtcgetattr
. Вы не можете обнулить astruct termios
, настроить его, а затем установить сtty
помощьюtcsetattr
. Если вы используете метод обнуления, то вы будете испытывать необъяснимые периодические сбои, особенно в BSD и OS X. «Необъяснимые периодические сбои» включают зависаниеread(3)
.#include <errno.h> #include <fcntl.h> #include <string.h> #include <termios.h> #include <unistd.h> int set_interface_attribs (int fd, int speed, int parity) { struct termios 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
Значения скорости являются
B115200
,B230400
,B9600
,B19200
,B38400
,B57600
,B1200
,B2400
,B4800
и т.д. Значение четности не0
(то есть без проверки четности),PARENB|PARODD
(включить четность и использовать нечетный),PARENB
(включить четность и использовать даже),PARENB|PARODD|CMSPAR
(четность знака), иPARENB|CMSPAR
( пространственный паритет).«Blocking» устанавливает,
read()
ожидает ли порт на порту прибытия указанного количества символов. Установка отсутствия блокировки означает, чтоread()
возвращается любое количество доступных символов, не дожидаясь большего, до предела буфера.Дополнение:
CMSPAR
нужен только для выбора четности меток и пробелов, что редко. Для большинства приложений его можно не указывать. Мой заголовочный файл/usr/include/bits/termios.h
позволяет определятьCMSPAR
только в том случае, если определен символ препроцессора__USE_MISC
. Это определение встречается (вfeatures.h
) с#if defined _BSD_SOURCE || defined _SVID_SOURCE #define __USE_MISC 1 #endif
Во вступительных комментариях
<features.h>
говорится:/* 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. ... */
источник
lsusb
чтобы увидеть все USB-устройства. Они могут называться по-другому, если в вашей системе есть собственныеudev
правила; см./etc/udev/rules.d/
Может быть, оттуда вы сможете выбрать порт, который ищете. Конечно, указав, а затем отключив / отключив порт, вы сможете определить разницу.Для демонстрационного кода, который соответствует стандарту POSIX, как описано в разделах «Правильная настройка режимов терминала» и « Руководство по последовательному программированию для операционных систем POSIX» , предлагается следующее.
Этот код должен правильно выполняться с использованием Linux на процессорах x86, а также на процессорах ARM (или даже CRIS).
По сути, он основан на другом ответе, но неточные и вводящие в заблуждение комментарии были исправлены.
Эта демонстрационная программа открывает и инициализирует последовательный терминал со скоростью 115200 бод для неканонического режима, который является максимально портативным.
Программа передает жестко закодированную текстовую строку на другой терминал и откладывает выполнение вывода.
Затем программа входит в бесконечный цикл для приема и отображения данных с последовательного терминала.
По умолчанию полученные данные отображаются в виде шестнадцатеричных байтовых значений.
Чтобы программа обрабатывала полученные данные как коды ASCII, скомпилируйте программу с символом DISPLAY_STRING, например
Если полученные данные представляют собой текст ASCII (а не двоичные данные), и вы хотите читать их как строки, заканчивающиеся символом новой строки, см. Этот ответ для примера программы.
#define TERMINAL "/dev/ttyUSB0" #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <termios.h> #include <unistd.h> 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 = TERMINAL; int fd; int wlen; char *xstr = "Hello!\n"; int xlen = strlen(xstr); 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, xstr, xlen); if (wlen != xlen) { 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)); } else { /* rdlen == 0 */ printf("Timeout from read\n"); } /* repeat read to get full message */ } while (1); }
источник
cfmakeraw
правильным?O_NDELAY
илиO_NONBLOCK
. В cmrr.umn.edu/~strupp/serial.html упоминается, что если вы откроете файловый дескриптор с этими флагами, тоVTIME
игнорируется. Тогда в чем разница между запуском сO_NONBLOCK
файловым дескриптором и его использованиемVTIME
?