Intereting Posts
получение символа в c без нажатия «enter» Функция изменения данных массива – данные не изменяются. С Как обеспечить последовательность чередующихся streamов, чтобы показать, что код разбивается и не обеспечивает идеальную синхронизацию? Можно ли использовать функцию asm с переменной ac-string вместо строкового литерала в качестве аргумента? Разделить строку на токены в C, когда в строке 2 разделителя Вставка данных в файл в c выражение «break» при использовании фигурных скобок в корпусе переключателя Переключение двух чисел без использования дополнительного пространства не работает, если обе указывают на одно и то же место? Memcpy принимает то же время, что и memset Константы, не загруженные компилятором почему мы не можем увеличивать массив аналогичным образом как указатель в c? Как вставить нули между битами в bitmap? Ошибка «lvalue required» при попытке увеличить массив Как написать streamобезопасный и эффективный блокировочный блок распределения памяти в C? Вопрос об общей библиотеке и данных, относящихся к streamу

Проблема с RaspberryPi RS-232

Я использую линии RS-232 на своем Pi для связи с лазерным дальномером. Я проверил связь между ними, используя minicom со скоростью передачи в 19200 (потому что это скорость передачи в LRF и не может быть изменена), и она работает нормально. Несмотря на запись в LRF, любые команды (состоящие из одного символа и нажатие «enter») могут предпринять несколько попыток повлиять, общение в обоих направлениях отлично работает.

Однако, когда я начинаю программировать на C-коде для чтения и записи с помощью RS-232, он работает наполовину. Вот код, который я использую:

#include  #include  #include  #include  //SETUP UART0 int main(){ int uart0_filestream = -1; int loop; int i; int isError=1, rx_length; unsigned char rx_buffer[256]; useconds_t micro=3000; uart0_filestream = open("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NDELAY); if(uart0_filestream == -1) printf("ERROR: Unable to open UART\n\n"); else printf("UART open\n\n"); struct termios options; tcgetattr(uart0_filestream, &options); options.c_cflag = B19200 | CS8 | CLOCAL | CREAD; options.c_iflag = IGNPAR | ICRNL; options.c_oflag = 0; options.c_lflag = 0; tcflush(uart0_filestream, TCIFLUSH); tcsetattr(uart0_filestream, TCSANOW, &options); unsigned char tx_buffer[20]; unsigned char *p_tx_buffer; p_tx_buffer = &tx_buffer[0]; *p_tx_buffer++ = 'o'; *p_tx_buffer++ = '\n'; /* if(uart0_filestream != -1){ for(i = 0; i<100; i++){ int count = write(uart0_filestream, &tx_buffer[0], (p_tx_buffer - &tx_buffer[0])); if(count < 0) printf("\n\nERROR: No bytes written\n\n"); else printf("%i bytes written: %s\n", (p_tx_buffer - &tx_buffer[0]), tx_buffer); } } */ if(uart0_filestream != -1){ for(i=0; i 0){ printf("rx_lentgh = %i:\t ", rx_length); for(loop=0; loop<30; loop++){ //check for NULL and new line for easier readability if(rx_buffer[loop] == NULL) rx_buffer[loop] = '$'; if(rx_buffer[loop] == '\n') rx_buffer[loop] = '%'; printf("%c", rx_buffer[loop]); } printf("\n"); i++; } } } close(uart0_filestream); } 

Когда я пытаюсь читать с устройства, он всегда возвращает ошибку. Я начал зацикливаться, чтобы увидеть, постоянно ли читают разные результаты. Из 100 попыток, как правило, 4-5 возвращаемых данных, все остальные [i] rx_length [/ i] возвращаются -1. Возвращенные данные должны выглядеть так:

COUNTS: 0000

где число зависит от расстояния, которое измеряет LRF. Но вместо этого я получаю вывод следующим образом:

rx_lentgh = 16: jRþ $ COUNTS: 0000% $$$$$$$$$$$$
rx_lentgh = 8:% $ COUNTSTS: 0000% $$$$$$$$$$$$
rx_lentgh = 16:: 0142 %% $ СЧЕТА: 0 $$$$$$$$$$$$
rx_lentgh = 8: 000 %% $ COCOUNTS: 0 $$$$$$$$$$$$
rx_lentgh = 16: UNTS: 0142 %% $ COUN $$$$$$$$$$$$
rx_lentgh = 24: TS: 0142 %% $ COUNTS: 0000 %% $$$$$
rx_lentgh = 8: COUNTS: 0% $ COUNTS: 0000 %% $$$$$
rx_lentgh = 16: 142 %% $ COUNTS: 000: 0000 %% $$$$$
rx_lentgh = 16: 0 %% $ СЧЕТЧИКИ: 0142%: 0000 %% $$$$$
rx_lentgh = 8:% $ COUNTSTS: 0142%: 0000 %% $$$$$
rx_lentgh = 8:: 0000 %% $ TS: 0142%: 0000 %% $$$$$
rx_lentgh = 8: COUNTS: 0TS: 0142%: 0000 %% $$$$$
rx_lentgh = 24: 142 %% $ COUNTS: 0142 %% $ COUN $$$$
rx_lentgh = 8: TS: 0000% UNTS: 0142 %% $ COUN $$$$
rx_lentgh = 16:% $ COUNTS: 0000 %% $ 2 %% $ COUN $$$$
rx_lentgh = 8: COUNTS: 0: 0000 %% $ 2 %% $ COUN $$$$
rx_lentgh = 16: 142 %% $ COUNTS: 0002 %% $ COUN $$$$
rx_lentgh = 8: 0 %% $ COUNUNTS: 0002 %% $ COUN $$$$
rx_lentgh = 16: TS: 0142 %% $ COUNTS2 %% $ COUN $$$$
rx_lentgh = 8:: 0000 %% $% $ COUNTS2 %% $ COUN $$$$
rx_lentgh = 16: COUNTS: 0142 %% $ CO2 %% $ COUN $$$$
rx_lentgh = 8: UNTS: 000142 %% $ CO2 %% $ COUN $$$$
rx_lentgh = 24: 0 %% $ COUNTS: 0142 %% $ COUNTS $$$$
rx_lentgh = 16:: 0000 %% $ СЧЕТА: 0% $ COUNTS $$$$
rx_lentgh = 24: 142 %% $ COUNTS: 0142 %% $ COUN $$$$
rx_lentgh = 8: TS: 0000% UNTS: 0142 %% $ COUN $$$$
rx_lentgh = 16:% $ COUNTS: 0142 %% $ 2 %% $ COUN $$$$

 **The above is edited in my code for readability. A NULL character is replaced with '$' and a '\n' is replaced with '%' 

Вы можете видеть, что каждый раз, когда он получает данные, он по крайней мере получает часть хорошего чтения, а иногда и всего. Но там много мусора. Вы можете увидеть в моем коде, что я отфильтровал все прочитанные, которые были возвращены в ошибке. Вероятно, это займет более 1000 просмотров, чтобы получить много «хороших» чтений. Я действительно думаю, что это связано с хронометражем, но даже если бы это было время, я бы не стал получать данные [i] некоторых [/ i] данных?

Письмо имеет ту же проблему. Единственная запись ничего не делает. Зацикливание кода записи 100 раз может привести к тому, что код будет переведен в LRF, но LRF почти не работает после запуска этого кода, и я не должен отключать его, чтобы заставить его работать и просматривать данные в миникомпьюте снова.

LRF может отправлять пакеты с частотой 200 или 10 Гц в зависимости от режима. Все данные, полученные выше, были выполнены с передачей LRF пакетов на частоте 200 Гц.

Любая помощь вообще будет очень признательна! Я работаю над этим несколько недель между моими другими занятиями и работой.

В коде есть несколько проблем.


 uart0_filestream = open("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NDELAY); 

Вы установили порт для неблокирующего ввода-вывода.
Это, вероятно, не то, что вы хотите. После проверки кода возврата добавьте следующее:

 fcntl(uart0_filestream, F_SETFL, 0); 

для настройки блокировки ввода-вывода.


 if(uart0_filestream == -1) printf("ERROR: Unable to open UART\n\n"); 

Когда возникает фатальная ошибка, программа должна выйти, а не продолжить.
Вам также нужно проверить значение errno, когда syscall возвращает -1.


 tcgetattr(uart0_filestream, &options); ... tcsetattr(uart0_filestream, TCSANOW, &options); 

Коды возврата из системных вызовов всегда должны быть проверены.


 options.c_cflag = B19200 | CS8 | CLOCAL | CREAD; options.c_iflag = IGNPAR | ICRNL; options.c_oflag = 0; options.c_lflag = 0; 

Это неправильная модификация членов termios .
Должны быть выполнены только правильные macros и побитовые операции. См. Руководство по последовательному программированию Posix .
Вы отключили каноническую обработку ввода, что, вероятно, не то, что вы хотите сделать.
Ввод, который вы пытаетесь прочитать, – это текст ASCII с завершением строки, поэтому используйте канонический режим, чтобы система анализировала конец каждой строки.
Теперь у вас настроен порт для режима raw, который предназначен для двоичных данных или для игнорирования символов управления ASCII.

Для примера кода для настройки канонического режима см. Этот ответ .


  rx_length = read(uart0_filestream, (void*)rx_buffer, 255); 

Опять же, вам нужно проверить значение errno, когда syscall возвращает -1.
Когда read() возвращает -1 для вашего кода, errno , вероятно, EAGAIN, чтобы указать, что данных не было.


Если задан блокирующий ввод-вывод и канонический ввод-вывод вместо необработанного ввода-вывода, то каждый read() будет возвращаться с полной строкой ввода.

Предложить OP неправильно интерпретировать данные – он выглядит довольно хорошо.

Рекомендовать переписать внутренний цикл

 // for(loop=0; loop<30; loop++) for(loop=0; loop 

После этого результат должен выглядеть намного лучше. Хитрость заключается в том, что образец read() происходит асинхронно с поступающими данными, так что считывается только часть сообщения. read() не знает, когда пакет закончился. Он возвращается, когда его полная, ошибка или когда в этот момент нет более доступных данных. Синхронизация между read() и приходом конца пакета отсутствует. Требуется повторная интеграция сообщения.

Синхронизация псевдокода

 i = 0; length = 0; forever() { do { i += length; length = read(&buffer[i]) if (length means bad read) handle error; search buffer from i to (i+length) for End-of-packet } while (end-of-packet not found and buffer not too full) Use buffer from start to end-of-packet. length = i+length-end-of-packet-index memmove(&buffer[0], &buffer[end-of-packet-index+1], length); i = 0; } 

Вы можете проверить другие функции read() которые читаются до таймаута. (Может быть, другой вариант open() тоже?

Другие незначительные моменты

  1. Дополнительные комментарии в options.c_cflag для объяснения вариантов.

  2. «rx_length» против «rx_lentgh».

  3. rx_buffer[loop] == NULL - плохая форма. rx_buffer[loop] - char . NULL - это указатель. Используйте rx_buffer[loop] == '\0' .

  4. Для целей отладки рассмотрите

,

 // printf("%c", rx_buffer[loop]); if (isprint(rx_buffer[loop])) { printf("%c", rx_buffer[loop]); } else { printf("(%02hhX)", rx_buffer[loop]); }