Не корректно работает Serial.pfush();
$i = 2 ;
>
if ( isset ( $_POST [ ‘B3’ ] ) )
<
$cur3 = 1 ;
$i = 3 ;
>
$fp = fopen ( «/dev/ttyACM1» , «w+» ) ;
fwrite ( $fp , chr ( $i ) ) ;
echo fread ( $fp , 8192 ) ;
// sleep(3);
В винде вместо /dev/ttyACM1 просто com3 указывается.
Может сможете подсказать мне в чем проблема?
freelancer89 Нуб
Немного разобрался, надо было апачу дать права на чтение и запись портов. Но столкнулся с другой проблемой. При нажатии кнопки в на веб странице RX светодиод загорается, но управляемый светодиод нет, а если запустить монитор серийного порта, то все работает как надо.
nailxx Официальный Нерд Администратор
Тут штука вот в чём. В Linux, как только последний процесс закрывает дескриптор, ссылающийся на последовательный порт, система дёргает линию DTR, что приводит к ресету Arduino. То есть на самом всякий раз, когда вы делаете
fclose ( $fp );
вы перезагружаете плату. Когда открыт Serial Monitor, именно он остаётся последним подключенным процессом и HUP не происходит. Решения три:
1) Программное. Меняем отношение системы к порту, чтобы не делать HUP по закрытию:
$ stty -F /dev/ttyACM0 -hup
2) Программное. Открывайте порт при старте веб-приложения (fopen) и не закрывайте (fclose) никогда, либо до какого-то teardown’а вашего приложения. Извиняйте, я не спец в PHP
3) Аппаратно. Воткните конденсатор на, скажем, 10 мкф между пинами 5V и RESET. Чип в этом случае вообще не заметит, что его хотят перезагрузить.
freelancer89 Нуб
Тут штука вот в чём. В Linux, как только последний процесс закрывает дескриптор, ссылающийся на последовательный порт, система дёргает линию DTR, что приводит к ресету Arduino. То есть на самом всякий раз, когда вы делаете
вы перезагружаете плату. Когда открыт Serial Monitor, именно он остаётся последним подключенным процессом и HUP не происходит. Решения три:
1) Программное. Меняем отношение системы к порту, чтобы не делать HUP по закрытию:
$ stty -F /dev/ttyACM0 -hup
2) Программное. Открывайте порт при старте веб-приложения (fopen) и не закрывайте (fclose) никогда, либо до какого-то teardown’а вашего приложения. Извиняйте, я не спец в PHP
3) Аппаратно. Воткните конденсатор на, скажем, 10 мкф между пинами 5V и RESET. Чип в этом случае вообще не заметит, что его хотят перезагрузить.
fox7812 Нерд
Есть php_serial class для этих целей, правда пока он у меня не хочет работать под линуксом. На винде — без проблем, но чтение данных с Arduino не реализовано.
fox7812 Нерд
Та же проблема. При попытке послать данные Arduino она перегружается. php выдает:
Warning: Unable to open the device in /opt/lampp/htdocs/ard/php_serial.class.php on line 157
Warning: Device must be opened in /opt/lampp/htdocs/ard/php_serial.class.php on line 541
Программные решение не помогли, конденсатор остановил перезагрузку, теперь просто мигает tx и php выдает те же ошибки. В винде тоже проблем не было.
Источник
Монитор порта, отладка
Как мы с вами знаем из урока “О платформе“, на платах Ардуино стоит USB-TTL конвертер, позволяющий микроконтроллеру в текстовом режиме “консоли” общаться с компьютером по последовательному интерфейсу, Serial. На компьютере создаётся виртуальный COM порт, к которому можно подключиться при помощи программ-терминалов порта, и принимать-отправлять текстовые данные. Через этот же порт загружается прошивка, т.к. поддержка Serial является встроенной в микроконтроллер на “железном” уровне, и USB-TTL преобразователь подключен именно к этим выводам микроконтроллера. На плате Arduino Nano это кстати пины D0 и D1.
К этим же пинам можно подключаться при помощи отдельных плат “программаторов”, например на чипах CP2102 или том же CH340 с целью загрузки прошивки или просто общения с платой. В самой Arduino IDE тоже есть встроенная “консоль” – монитор порта, кнопка с иконкой лупы в правом верхнем углу программы. Нажав на эту кнопку мы откроем сам монитор порта, в котором будут настройки:
Если с отправкой, автопрокруткой, отметками времени и кнопкой “очистить вывод” всё понятно, то конец строки и скорость мы рассмотрим подробнее:
- Конец строки: тут есть несколько вариантов на выбор, чуть позже вы поймёте, на что они влияют. Лучше поставить нет конца строки, так как это позволит избежать непонятных ошибок на первых этапах знакомства с Ардуино.
- Нет конца строки – никаких дополнительных символов в конце введённых символов после нажатия на кнопку отправка/Enter
- NL – символ переноса строки в конце отправленных данных
- CR – символ возврата каретки в конце отправленных данных
- NL+CR – и то и то
- Скорость – тут на выбор нам даётся целый список скоростей, т.к. общение по Serial может осуществляться на разных скоростях, измеряемых в бод (baud), и если скорости приёма и отправки не совпадают – данные будут получены некорректно. По умолчанию скорость стоит 9600, её и оставим.
- Очистить вывод – тут всё понятно, очищает вывод
Объект Serial
Начнём знакомство с одной из самых полезных штук Arduino-разработчика – Serial . Serial это объект класса Stream, позволяющий как просто принимать/отправлять данные через последовательный порт, так и наследует из класса Stream кучу интересных возможностей и фишек, давайте сразу их все рассмотрим, а потом перейдём к конкретным примерам.
Запустить связь по Serial на скорости speed (baud rate, бит в секунду). Скорость можно поставить любую, но есть несколько “стандартных”. Список скоростей для монитора порта Arduino IDE:
- 300
- 1200
- 2400
- 4800
- 9600 чаще всего используется, можно назвать стандартной для большинства устройств с связью через TTL
- 19200
- 38400
- 57600
- 115200 тоже часто встречается
- 230400
- 250000
- 500000
- 1000000
- 2000000
Отправляет в порт значение val – число или строку. В отличие от write выводит именно символы, т.е. отправив 88 вы получите 88: Serial.print(88); выведет 88. Также метод print/println имеет несколько настроек для разных данных, что делает его очень удобным инструментом отладки:
format позволяет настраивать вывод данных: BIN, OCT, DEC, HEX выведут число в соответствующей системе исчисления, а цифра после вывода float позволяет настраивать выводимое количество знаков после точки
Читает данные из буфера и ищет набор символов target (тип char), опционально можно указать длину length. Возвращает true, если находит указанные символы. Ожидает передачу по таймауту
Плоттер
Помимо монитора последовательного порта, в Arduino IDE есть плоттер – построитель графиков в реальном времени по данным из последовательного порта. Достаточно отправить значение при помощи команды Serial.println(значение) и открыть плоттер по последовательному соединению, например построим график значения с аналогового пина A0:
Плоттер поддерживает несколько линий графиков одновременно, для их отображения нужно соблюдать следующий протокол отправки данных: значение1 пробел_или_запятая значение2 пробел_или_запятая значение3 пробел_или_запятая значениеN перенос_строки, то есть значения выводятся в одну строку, одно за другим по порядку, разделяются пробелом или запятой, и в конце обязательно перенос строки. Давайте выведем несколько случайных величин:
Вывод значений происходит каждые 10 миллисекунд, а каждые 300 миллисекунд значения обновляются. Получаем вот такой график: В Arduino IDE с версии 1.8.10 добавили возможность подписать графики, для этого перед выводом нужно отправить названия в виде название 1, название 2, название n с переносом строки, и дальше просто выводить данные:
Использование пинов
Как я писал выше, аппаратный Serial имеет выводы на ноги микроконтроллера, для Nano/Uno/Mini это выводы D0 и D1. Можно ли работать с этими пинами, как с обычными цифровыми пинами? При отключенном Serial – можно, при включенном – нет. После вызова Serial.begin() ноги перестают функционировать как цифровые пины в ручном режиме, но после вызова Serial.end() можно снова ими пользоваться!
Отправка и парсинг
Рассмотрим самый классический пример для всех языков программирования: Hello World! Отправка данных в порт не должна вызывать трудностей и вопросов, потому что всё понятно/очевидно, да и чуть выше в описании метода print мы рассмотрели все варианты вывода. Отправка в порт позволяет узнать значение переменной в нужном месте программы, этот процесс называется отладка. Когда код работает не так, как нужно, начинаем смотреть, где какие переменные какие значения принимают. Или выводим текст из разных мест программы, чтобы наблюдать за правильностью (порядком) её работы. Давайте вспомним урок циклы и массивы и выведем в порт массив:
Вывод: 0 50 68 85 15 214 63 254 – элементы массива, разделённые пробелами! Проблемы возникают при попытке принять данные в порт. Дело в том, что метод read() читает один символ, даже если вы отправите длинное число – программа получит его по одной цифре, и составлять число из цифр придётся вручную. Проблема усугубляется тем, что read() читает именно символ, то есть код символа в таблице ASCII. Посмотрим вот такой пример, в котором в порт отправляются принятые в него данные (так называемое эхо):
Так как же принять именно цифру? Есть хитрость – вычитать из полученного кода символа код цифры 0, либо сам 0 в виде символа: ‘0’
Также для принятия одиночных чисел у нас есть готовый метод – parseInt() / parseFloat() – для целочисленных и рациональных чисел соответственно. Процесс приёма и расшифровки данных называется парсинг (parsing). Давайте примем в порт число 1234, используя готовый метод парсинга.
Итак, мы используем конструкцию if (Serial.available()) <> чтобы опрашивать порт только в том случае, если в него что-то пришло. Отправив в порт число 1234 мы получим ответ ОК, отправив любое другое – error. Также вы заметите, что после отправки проходит секунда, прежде чем плата ответит. Эта секунда спрятана внутри метода parseInt, программа ждёт секунду после принятия данных, чтобы все данные успели прийти. Секунда это очень много, достаточно было ждать, скажем, 50 миллисекунд. Это можно сделать при помощи метода setTimeout() .
Теперь после отправки цифры программа будет ждать всего 50 мс, и сразу же вам ответит. Остальные алгоритмы отправки и парсинга, в том числе обмена разнотипными данными между Ардуинами и другими платами смотри в уроке общение по Serial.
Управляющие символы
Существуют так называемые управляющие символы, позволяющие форматировать вывод. Их около десятка, но вот самые полезные из них
- \n – новая строка
- \r – возврат каретки
- \v – вертикальная табуляция
- \t – горизонтальная табуляция
Также если для вывода вы захотите использовать одинарные ‘ или двойные кавычки, “ или обратный слэш \ – нужно выводить их при помощи соответствующего спецсимвола, иначе ваш вывод “поломается”, я думаю, не нужно объяснять, почему:
- \» – двойные кавычки
- \’ – апостроф
- \\ – обратный слэш
- \0 – нулевой символ
- \? – знак вопроса
Как использовать? Просто писать в вывод. Например комбинация \r\n переведёт строку и вернёт курсор в левое положение:
Именно так кстати и работает функция println() , она просто добавляет вывод \r\n после print() =) Символы табуляции позволят удобно отправлять данные для последующей вставки в excel или другие таблицы. Например выведем несколько степеней двойки в виде таблицы, используя символ табуляции \t :
Результат скопируем и вставим в excel Удобно!
Видео
Источник
Arduino.ru
Очистка буфера
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
С одного устройсва на плату по Serial1 отправляется значения, на плате выполняется код, и потом отпраляются обратно другие значения на другой Serial порт. Но дело в том,что val принимает только самое первое значение из буфера, получается,что программа работает с запозданием. И выполняет расчеты со всеми значениями из буфера.
Как сделать так,чтобы val посредством parseInt принимал только последнее поступившее значение в буфер?
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Интересно а где вы присвоили val новое значение которое он должен передать, например
Идея такова что между приемом и отправкой должна стоять Ваша функция обработки принятой информации. иначе получается что отправляется то что принято. для реализации вашей идеи только путем сравнения. Создаете case или if с перечислением сообщений на которые должна быть реакция.
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Во время работы функции обработки принятой информации, на микроконтроллер поступают ещё значения. И даже если в serial порт перестают поступать данные, функция продолжает работу, пока все значения из буфера не обработает.
Пс забыл упомянуть, что мой код — пример, там показана лишь основная часть.
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Всё логично с точки зрения встроенных классов: пока буфер приёма не переполнился, и пока в буфере есть что-то, похожее на число — он его вам и будет возвращать. В исходниках Stream parseInt юзает peek, который в HardwareSerial возвращает символ из текущей позиции, никуда позицию чтения не сдвигая, в отличие от вызова read, в котором позиция чтения сдвигается.
Вывод: либо переделывать, либо — после parseInt вычитывать весь буфер вызовами read, пока есть available().
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Скачал старую версию IDE, вставил Flush() в код, но все равно функция работает с запозданием. Еще пытался поменять parseint на peek — опять та же история. Уже не знаю, что и делать.
Пробовал завершать прием данных с помощью Serial.end(), опять не помогло:
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Или я ни чего не понимаю или суть такова, parsentInt обрабатывает по 2 байта int = byte * 2; следовательно вы считываете только первую посылку. Посмотрел примеры людей в интернете, там это выглядит так:
Следовательно сколько элементов вы передаете, столко раз надо прочитать поток, а значит должно быть столько переменных val n, val n+1. Сколько аргументов вы передаете. Последним будет val end, вот его то и выведя в UART увидите в мониторе последнее принятое значение.
Здесь мы принимаем аргумент за аргументом и при выполнении условия окончания приема выходим с сохранением последнего принятого аргумента, может надо будет попробовать !Flush() для условия while, но это уже ньюансы.
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Скачал старую версию IDE, вставил Flush() в код, но все равно функция работает с запозданием. Еще пытался поменять parseint на peek — опять та же история. Уже не знаю, что и делать.
Пробовал завершать прием данных с помощью Serial.end(), опять не помогло:
Вы хотя бы осознаёте, что пытаетесь делать? Читаете документацию — хотя бы? peek — оставляет буфер нетронутым, никак не меняя позицию чтения. Serial.end — вообще из другой оперы.
Я же говорю — для того, чтобы вычитать два числа из Serial вызовами parseInt — надо понимать, как этот самый parseInt устроен. Я писал выше, как. Он не меняет позицию чтения из буфера, пока там есть что-то похожее на число. Поэтому с вашей стороны надо предпринять какие-то действия, чтобы дать понять Serial, что нужное вам число вы прочитали. Выше — я писал вариант.
Для танкистов, ещё раз: в буфер упал символ ‘1’. Его можно преобразовать в число? Можно. Вызов parseInt вернёт вам единичку в виде уже числа, а не символа, оставив эту единичку в буфере. Далее — в буфер падает символ ‘2’, вы вызываете parseInt и — получаете, как и ожидалось, число 12, потому что и ‘1’, и ‘2’ — можно преобразовать в числа 1 и 2, и их вместе — в число 12.
В каком месте моих объяснений я пишу на китайском?
З.Ы. Строго говоря, внутри parseInt есть вызов read, но — тут возникают проблемы, когда в буфере ещё не всё число. Но про это — не будем, да?
Источник