Проблемы с read () последовательного порта (USB-RS232) с использованием языка C - PullRequest
0 голосов
/ 08 ноября 2018

Доброго всем дня,

Я только начинаю программировать для своего исследования, в котором необходимо использовать механизм перемещения (похожий на манипулятор робота, который может двигаться только по 3 осям XYZ), подключенный через последовательный порт (USB к RS232, используя / dev / ttyUSB0) для компьютер. Операционная система компьютера - Linux 14.04, и по причинам ядра я не могу использовать более продвинутую версию, также я использую язык C в программе для этой траверсы.

Этот код, который я использовал, был разработан с 2000 года, но в последние годы эта программа не использовалась. С тех пор, как я начал этот проект, у меня возникло несколько проблем, но в конце я всегда терпел крах с одной и той же стеной, это вечный цикл, вызванный внутри программы, потому что функция read () в C не может правильно выполнить чтение данные поступают из последовательного порта.

/* For 232cOUT() and 232cIN() */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include "traverse.h"

rs232cIN(mojiin,status)
unsigned char *mojiin;
unsigned char *status;{
     int fdi,c,res,j,w;
     struct termios oldtio,newtio;
     struct termios oldscr;
     printf("ok0i\n");
     fdi = open(MODEMDEVICE, O_RDWR | O_NOCTTY ); 
     if (fdi <0) {perror(MODEMDEVICE); exit(-1); }

    tcgetattr(fdi,&oldtio); /* save current port settings --> For tty device */
    tcgetattr(1,&oldscr);  /* save current port settings --> For display device */
    printf("fdi=%d\n",fdi);
    printf("ok1i\n");
    bzero(&newtio, sizeof(newtio));
    newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD | CSTOPB;
    newtio.c_iflag = IGNPAR | ICRNL;  
    newtio.c_oflag = 0;
    printf("ok2i\n");
    /* set input mode (non-canonical, no echo,...) */
    newtio.c_lflag = 0;

    newtio.c_cc[VTIME]    = 5;   /* inter-character timer unused */
    newtio.c_cc[VMIN]     = 0;   /* blocking read until 5 chars received */

    tcflush(fdi, TCIFLUSH);
    tcsetattr(fdi,TCSANOW,&newtio);
    tcsetattr(1,TCSANOW,&newtio); /* stdout settings like modem settings */

    printf("ok3i\n");
    res = read(fdi,mojiin,256);   /* return after 5 chars have been input */        
    printf("res=%d\n",res);
     printf("ok4i\n");
    mojiin[res]=0;              /* so we can printf... */
    #if 1
         printf("Data import Good!!\n\r");
         printf("Imported-MOJIRETSU:%c\n\r",mojiin[0]);   
         printf("Imported-MOJISU:%d\n\r", res);   
     #endif
     status[0]=mojiin[0];       
     //sleep(1);       /*  this command is very important */
     usleep(SLEEPUSEC2);
     tcsetattr(fdi,TCSANOW,&oldtio);
     tcsetattr(1,TCSANOW,&oldscr);

     close(fdi); 
     }

Может быть, этот код похож на другие, которые я нашел в Интернете, Open Port также похож на этот, но вместо read () используется функция write ().

Проблема заключается здесь в функции чтения, где, используя текущий код, я не могу прочитать любое значение, поступающее с RS232. Компьютер может отправить код ASCII на RS232, но когда ему нужно получить, возвращаемое значение не возвращается, так как пример запуска программы - этот код. Программа запускает несколько циклов, но программа застревает в loopin1.

Результаты чтения: res, MOJIRETSU и MOJISU. Если вы проверите fdi = 3, что означает, что он читает что-то из порта RS232, но когда он получает разрешение res, значение равно 0, а MOJIRETSU не показывает никакого значения, а MOJISU равно 0. Из MOJISU он создает Состояние, которое в дальнейшем генерирует флаг «Ошибка».

==========  [Y_AXIS] Traversing START!! ========== 
Delta(Traverse) -->0.000000 
loopin1ok0o 
ok1o 
ok2o 
MOJISU=4 
ok3o 
     ZR 

MOJIOUT=ZR 
Sending OK 

ok4o 
ok0i 
fdi=3 
ok1i 
ok2i 
ok3i 
    res=0 
         ok4i 
             Data import Good!! 
Imported-MOJIRETSU: 
Imported-MOJISU:0 
status=0 
STATUS ERROR 0x0 !!!! 
STATUS FLAG=-4 
ok0o 
ok1o 
ok2o 
MOJISU=4 
ok3o 
     ZR 

MOJIOUT=ZR 
Sending OK 

ok4o 
ok0i 
fdi=3 
ok1i 
ok2i 
ok3i 
    res=0 
         ok4i 
             Data import Good!! 
Imported-MOJIRETSU: 
Imported-MOJISU:0 
status=0 
STATUS ERROR 0x0 !!!! 
STATUS FLAG=-4 
^C 

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

Тогда вы можете спросить, работайте без цикла, но проблема в том, что сообщения об ошибках - это флаги, которые указывают, достигает ли механизм перемещения предела на рельсе, который он стоит, и если у него нет предупреждения Я мог бы сломать механизм траверс! Так что определенно мне нужен этот цикл обратной связи для его работы.

Система работает неканоническим способом, и я настроил VTIME на несколько значений и не меняет статус исходящего события. Если я поменяю VMIN, программа застрянет, и я смогу остановить его, только если закрою терминал.

Действительно странно, что при отправке ошибки даже без цикла работает механизм перемещения. Поэтому очень нужен совет, если кто-то знает, как работать с функцией read (), чтобы я мог получить значения res, MOJIRETSU и MOJISU и, таким образом, управлять механизмом перемещения, не удаляя этот цикл обратной связи.

1 Ответ

0 голосов
/ 10 ноября 2018

Ваша инициализация последовательного терминала использует плохие методы кодирования. Обнуление структуры termios не соответствует POSIX.

что вы имеете в виду при обнулении структуры termios?

Просто найдите «ноль» в своем коде, и вы найдете оскорбительное утверждение:

    bzero(&newtio, sizeof(newtio));

См. Правильная настройка режимов работы терминала и Руководство по последовательному программированию для операционных систем POSIX для правильных методов инициализации последовательного терминала.

Также код использовался для работы несколько лет назад, потому что механизм перемещения использовался в предыдущих исследованиях, в последнее время он не мог перемещаться с этим кодом.

В этом проблема плохо написанного кода. Он не переносимый и может не работать в другой системе или в другой день.


Проблема заключается здесь в функции чтения, где, используя текущий код, я не могу прочитать любое значение, поступающее с RS232.

Анализ несколько затруднен кодом, который не соответствует комментариям или текстовым описаниям.
Но три проблемы с вашим кодом очевидны.

Как уже упоминалось, инициализация последовательного терминала не соответствует POSIX.

Журнал указывает, что вы переключаетесь между какой-то загадочной подпрограммой (-ами) вывода и подпрограммой ввода, которую вы опубликовали для проверки.
Каждое выполнение входной подпрограммы выполняет последовательность open () , инициализацию и close () на последовательном терминале. Предположительно, процедура вывода (которая не была опубликована) выполняет аналогичную последовательность open () , инициализация и close () на последовательном терминале.

Эта повторяющаяся последовательность открывания, инициализации и закрытия последовательного терминала ужасно неэффективна и совершенно ненужна при правильной разработке программы.
Это вторая проблема.

Третья проблема является прямым следствием предыдущей проблемы.
В рамках инициализации чтения вы выполняете явное удаление любых данных, которые могут находиться в приемных буферах:

    tcflush(fdi, TCIFLUSH);

Ваши последующие read () (независимо от того, как вы конфигурируете VMIN и VTIME) могут возвращать только данные, полученные после операции сброса.
В вашей программе потеряны все данные, полученные, когда последовательный терминал не открыт и / или до операции сброса.

Если ваша программа только один раз открыла и инициализировала последовательный терминал для чтения и записи, эта третья проблема исчезла бы.

...