LinuxForum.Fans
Тема

Программирование COM-прота на Си в Linux

Автор: aalistrat 9 сообщений 4210 просмотров
#332287

Всем добрый день.
Написал небольшую тестовую программу для COM-порта.
К порту подключен трехпроводной нуль-модемный кабель, на конце которого перемычка между линиями прием-передача.

text
#include <stdio.h>        /*ввод-вывод*/
#include <string.h>       /*строковые функции*/
#include <unistd.h>       /*стандартные функции UNIX*/
#include <fcntl.h>        /*управление файлами*/
#include <termios.h>      /*управление POSIX терминалом*/
#include <stdint.h>       /*для типа переменных unit8_t*/

int open_port(void) /*функция открытия порта*/ { int fd; /*файловый дескриптор*/ fd=open("/dev/ttyS0",O_RDWR|O_NOCTTY); if (fd==-1) printf("\nошибка открытия порта\n"); else { struct termios options; /*настройка порта*/ tcgetattr(fd,&options); cfsetispeed(&options, B9600); cfsetospeed(&options, B9600); options.c_cflag |= (CLOCAL | CREAD); options.c_cflag |= PARENB; options.c_cflag |= PARODD; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; options.c_cflag &= ~CRTSCTS; options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); options.c_iflag |= (INPCK | ISTRIP); options.c_iflag &= ~(IXON | IXOFF | IXANY); options.c_oflag &= ~OPOST; options.c_cc[VTIME] = 0; options.c_cc[VMIN] = 1; tcsetattr(fd,TCSAFLUSH,&options); } return (fd); }

main (void) { int fdout; int a; int b; int fd; int n; int m; uint8_t outb[16]; uint8_t inb[16]={0xf0,0xe1,0xd2,0xc3,0xb4,0xa5,0x96,0x87,0x78,0x69,0x5a,0x4b,0x3c,0x2d,0x1e,0x0f};

printf("\n"); /*вывод на экран выходного массива, сейчас там мусор*/ for (a=0;a<16;a++) printf(" %x ",outb[a]); printf("\n\n");

fd=open_port(); /*открытие порта*/ if (fd!=-1) { fdout=open("fileout", O_WRONLY | O_CREAT | O_TRUNC); /*создание выходного файла*/ if (fdout==-1) printf("\ncreating output file error\n"); else { sleep(1); n=write(fd,inb,16); /*запись в порт*/ if (n<1) printf("\nwritting in port error\n"); else { sleep(1); n=read(fd,outb,16); /*чтение из порта*/ if (n<1) printf("\nreading from port error\n"); else { m=write(fdout,outb,n); /*запись в выходной файл*/ if (m<1) printf("\nwriting in output file error\n"); else { printf("\n"); /*вывод на экран выходного массива, сейчас там значения полученные из порта*/ for (b=0;b<16;b++) printf(" %x ",outb[b]); printf("\n\n"); } } } } } close(fdout); close(fd); return (0); }

И вот что я получаю в итоге на экране:



и в файле:

paRC4%xiZK<-

Помогите, пожалуйста, разобраться со следующими вещами:
1 Почему в массиве принятых байт, старший бит установился в 0, и как это исправить?
2 Вопрос полегче, как сделать так, чтобы в файл записывались 16-ричные значения байт, а не соответствующие им ASCII-символы?

Программу писал, руководствуясь материалом: http://www.opennet.ru/docs/RUS/serial_guide/index.html

#332405

У вас режется 8-й бит у принимаемых данных. Чтобы этого не происходило нужно заменить строку:

text

options.c_iflag |= (INPCK | ISTRIP);

на строку:

text

options.c_iflag  &=  ~(INPCK  +  ISTRIP);

Подробнее см. http://frank.harvard.edu/~coldwell/terminals/#termios%20Input%20and%20Output%20Modes

И программа начинает рабоать вот так:

text

vvk@linux-enwc:~/test> ./a.out 

e8 33 98 16 ff 7f 0 0 0 0 0 0 0 0 0 0

f0 e1 d2 c3 b4 a5 96 87 78 69 5a 4b 3c 2d 1e f

vvk@linux-enwc:~/test> cat fileout ����xiZK<- vvk@linux-enwc:~/test> hexdump -C fileout 00000000 f0 e1 d2 c3 b4 a5 96 87 78 69 5a 4b 3c 2d 1e 0f |........xiZK<-..| 00000010 vvk@linux-enwc:~/test>

#332433

Чтобы в файл записывались 16-ричные числа в виде текста использовать fprintf

#332476

Спасибо!!!

#348716

Еще такой вопрос.
Ситуация та же:
К порту подключен трехпроводной нуль-модемный кабель, на конце которого перемычка между линиями прием-передача.

Программа на отправку-чтение массива из 1000000 байт, а читаются только 4095, почему и как это исправить?

#351892

Доброго дня!
По работе в «наследство» досталась тестовая прога для модуля с интерфейсом RS-232. Режим работы порта 8N1, без контроля четности, скорость 115200.
В процедуре записи в порт после вызова write идёт следующая конструкция:

text
    write ( fd, buf, len );
    do      
    {
        usleep(1);
        ioctl ( fd, TIOCSERGETLSR, &status );
    } while (!(status & TIOCSER_TEMT));

status |= TIOCM_RTS; ioctl ( fd, TIOCMBIC, &status ); return 0;

Так как тест запускается на персоналке, то usleep (1) на поверку выливается в паузу 20 мс (судя по всему, минимальный тик таймера), что является слишком долгим интервалом при работе с модулем. Попробовал закомментить usleep, в результате RTS выставляется ранее, чем успевают передаться данные, и последний байт данных теряется.
Попробовал вместо do-while использовать tcdrain(fd) – та же история с потерей последнего байта. Совместное использование tcdrain и затем do-while выливается в задержки переменной длины 5…13 мс, что тоже слишком долго.
Вот пытаюсь понять, что же сделать, чтобы RTS сбрасывался вовремя, а не слишком рано или чрезмерно поздно =)

#354049
"aalistrat" написал:
Программа на отправку-чтение массива из 1000000 байт, а читаются только 4095, почему и как это исправить?

Размер буфера СОМ-порта - 4096 байт. Буфер полон и чтение останавливается.Чтобы очистить буфер надо его прочитать.
Для передачи 1000000 байт надо примерно так:
int count = write(port,tx_buffer,1000);/*пишем 1000 байт*/
usleep(timeout);/*ждем пока данные уйдут в эфир*/
count = read(port,rx_buffer,1000);/*читаем буфер СОМ-порта*/
и так 1000000/1000 = 1000 раз

#354056
"Путник" написал:
Вот пытаюсь понять, что же сделать, чтобы RTS сбрасывался вовремя, а не слишком рано или чрезмерно поздно =)

СОМ порт в секунду передает BAUDRATE/10 байт (8 бит информация + 2 синхро).
Например В115200/10 = 11520 байт/сек.
Можно посчитать время и сбросить RTS, хотя костыльно.
У меня порты работают по приходу данных, RTS давно не применял.

#373128

Всем привет!
Собственно, задачка с прежними условиями (ком-порт 8N1, без контроля четности, 115200 бод). Железка обменивается данными с ПК. Смотрим картинку обмена на логическом анализаторе. Данные выдаю кодограммами из 12 байт ( write (fd, buf,12) ).
Иногда возникает ситуация, что при выдаче от ПК кодограмма из нескольких байт разрывается на части, интервалы между частями кодограммы варьируются от 100 мкс до 1,5 мс (на картинке эти разрывы показаны красными стрелками). Сигнал RTS при этом живет своей жизнью и сбрасывается значительно раньше (сброс RTS показан синей стрелкой).
C чем такое может быть связано? Или такие разрывы правомерны в работе порта?

Войдите или зарегистрируйтесь, чтобы ответить.