Официальный сайт компании Arduino по адресу arduino.cc
Можно ли грамотно выловить Serial через if а не while
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Чт, 30/05/2019 - 19:12
всем привет
uint32_t t = millis(); uint8_t i = 0; while (1){ if (millis() - t > 1000UL){ PC.println("led13 action"); PORTC ^= PIN_LED; t = millis(); } if (Serial.available()){ PC.println("read byte"); serial_byte[i++] = Serial1.read(); if (i > CHR_BUF-2) --i; } if (!Serial.available() && i != 0){ PC.print("1 = "); PC.println(serial_byte); i = 0; } }
что выводит этот код , смотрите ниже. анализирую вывод имею несколько вопросов
Как грамотно прослушивать Serial используя if а не while ? ...можно поставить еще одну переменную флаг, который взовлиться при чтении байта возврат коретки. но можно ли сделать не объявляя дополнительных переменных?
Почему такие большие паузы при поступлении байтов , что программа успевает словить if (!Serial.available() ) и вывести один байт, хотя байты на самом деле еще не закончились ?
Принимая SM 5, откуда взялся ОК 3 раза ?
Почему выводя SM 6, для букв C,M,T приплюсовалось SM 5
Откуда перед плюсом пару пустых байтов пришло?
read byte 1 = C OK read byte 1 = M OK read byte 1 = T OK read byte read byte read byte read byte read byte read byte read byte read byte read byte read byte read byte 1 = I: "SM",5 led13 action led13 action led13 action led13 action read byte 1 = : "SM",5 read byte 1 = : "SM",5 read byte 1 = +: "SM",5 read byte 1 = C: "SM",5 read byte 1 = M: "SM",5 read byte read byte read byte read byte read byte read byte read byte read byte read byte read byte read byte read byte 1 = TI: "SM",6 led13 action led13 action
led13 action read byte 1 = read byte 1 = read byte 1 = + read byte 1 = C read byte 1 = M read byte 1 = T read byte 1 = I read byte 1 = : read byte 1 = read byte 1 = " read byte 1 = S read byte read byte read byte read byte read byte read byte 1 = M",7 led13 action led13 action led13 action led13 action read byte 1 = ",7 read byte 1 = ",7 read byte 1 = +",7 read byte 1 = C",7 read byte 1 = M",7 read byte 1 = T",7 read byte 1 = I",7 read byte 1 = :",7 read byte 1 = ",7 read byte read byte read byte read byte read byte read byte read byte read byte 1 = "SM",8 led13 action
Кода передатчика нет, код приёмника неполон. Что именно передавалось - неизвестно....
В общем, ответ на основной вопрос "Можно ли грамотно выловить Serial через if а не while" - можно, если вылавливать будет грамотный человек.
Женя лукавит немного... Скорее всего потому что дорогой ТС завел нудную привычку доставать вопросами, на которые можно и нужно искать ответы самому, то есть типично учебными вопросами.
Но в честь начала пути исправления кармы ;)))) я дам, надеюсь исчерпывающий, ответ.
ИТАК:
Есть несколько способов или паттернов програмирование контроллеров. Один их них - "бесконечный цикл", который предлагается основным в парадигме Ардуино. Не сильно богатая периферия АВР контроллера преполагает т.н. "автоматный" стиль создания кода. Не вдаваясь в детали, АРХИВАЖНОЙ задачей становится сокращение времени одного прохода loop(). Например это важно для того, чтобы контроллер оперативно обработал произошедшее событие. Причем не имеет значения событие обрабатывается по прерыванию или проверкой. В парадигме Ардуино прерывание следует использовать исключительно для поднятия флага события или постановки в очередь короткого сообщения.
Таким образом не только можно, но исключительно необходимо проверять буфер приема Сериала не while, а if, и считывать не более одного символа за один проход loop(). Считав символ, следует провести проверку на адекватность ожиданию и на признак завершения ожидаемого ввода.
==================
Занудно, но, надеюсь, понятно. Да?
Женя лукавит немного...
Категорически протестую. В чём я сказал неправду? Кода нет, передаваемых данных нет. Сделать можно, если делать грамотно. Что не так? :))))
А вот чем if с goto в конце блока от while отличается? И тут и там проверка условия. И вообще loop внутри while вызывается. Может просто loop начинать с while(1){}; и в скобках всю работу. Всё быстрее крутится будет?
Может просто loop начинать с while(1){}; и в скобках всю работу. Всё быстрее крутится будет?
Быстрее будет на миллисекунду максимум. Но можно потенциальные глобалы внутрь функции занести. И вообще - луп не трогать, а прямо в setup() замутить цикл.
Кода передатчика нет, код приёмника неполон. Что именно передавалось - неизвестно.....
Передатчик - сам gsm модем. Поэтому кода нет. Что отправит то и увидим. (Да я забыл указать что в примере используется прослушка gsm. Sorry)
Приемник - в данном примере он полон. Максимально быстро выводим что пришло. (В свете _грамотной_ работы по отлову очевидно не полный. Поэтому и вопрос. )
Что передовалось известно. SM x это входящий смс. Но в свете вопроса не это важно. Пускай передается что угодно нам же надо вывести это грамотно (тобишь как минимум в том же виде что пришло*)
* но конечно же через переменую. Т.к. это скелет так скажем, просто вывод. В который в последствии конечно же нужно добавить анализ поступающих данных в переменую.
Дракула, все понятно, спасибо. Вот поэтому и вопрос про if.
Например, я думал что железный буфер тот что 1 байт, "знает" что он еще не все символы передал из .. как назвать правильно второй буфер тот что 64 байта... второго буфера. А получается из железного байт ушёл, а следующий не редко поступает медленно. Медленно имеется ввиду что успевает отработать if (! serial. Available).....
Хотя я сейчас подумал может поменять эти два if (чтения и вывода) местами , тем самым может хватит времени на заполнение железного буфера и if (! serial. Available) не будет срабатывать пока все сообщение не прочитаем... ну это так мысли вслух.
Понимаешь.... я свое уже отпреподавал и больше точно не хочу. Поэтому подробности объяснять не стану, но такая конструкция совершенно не нужна и глупа. Проверять буфер на пустоту никогда не имеет смысла, при грамотном кодировании.
Читай образцы хорошего кода, читай ДШ и примеры. Учись сам и в тишине! Коммуникативная депривация в стиле "почемучка" прилична детям, а не взрослому мужику. Форум - не школа и ЧаВо и не справочная.
Т.е. Вы отлаживаете приём не зная точно, что передаётся? Ну,успехов!
В общем, разбирайтесь сами.
разобрался/пофиксил прекрасно принимает на if'ах (не зная что передаётся. но справедливости ради стоит сказать что от модема как никрути приходит только валидные символы. но учтенно на вход и не валидные тоже) и выводит. Но используя переменную флаг для конца строки
остался только один основной вопрос: "А можно ли тоже самое сделать не используя дополнительную переменную для конца строки?"
разобрался/пофиксил прекрасно принимает на if'ах (не зная что передаётся. но справедливости ради стоит сказать что от модема как никрути приходит только валидные символы. но учтенно на вход и не валидные тоже) и выводит. Но используя переменную флаг для конца строки
остался только один основной вопрос: "А можно ли тоже самое сделать не используя дополнительную переменную для конца строки?"
Ответ на Ваш вопрос существенно зависит от того, что именно Вы подразумеваете под словами "то же самое" (взял на себя смелость поправить авторское написание).
под словами "то же самое" я подразумевал,
1. получить всю строку из serial но не опредляя конец строки по пришедшему чару, закинуть в наш буфер
2. вывести буфер
вот я пытался по available() определять но получилась ерунда. других методов я не знаю. спросил более знающих.
Какие у вас варианты ? По маркерам начала/конца, зная размер строки, по тайм-ауту. Первое самое надежное.
Это никак не отменяет контроля по символу конца строки и т.п. Ну т.е. если в буфере и есть какой то символ - он может быть полной ерундой, так бывает.
1. получить всю строку из serial но не опредляя конец строки по пришедшему чару
Единственный метод НАДЕЖНО определить конец строки неизвестной длины - только "по пришедшему чару". Других методов НЕ СУЩЕСТВУЕТ. А как этот конец строки ловить - по if или по while - роли не играет.
да уже про if while никто не спрашивает.
Morroc , точно по размеру может мне пригодиться . спасибо.
точно по размеру может мне пригодиться . спасибо.
при быстром обмене метод по размеру перестает быть надежным.
хотя вам это скорее всего не пригодится
без последней фразу никак
при быстром обмене метод по размеру перестает быть надежным.
почему ?
Потому что всегда есть вероятность получить вместо нужного байта ерунду (или получить ерунду вдобавок к нужному байту или не получить какой нибудь байт вообще). В каком то случае можно на это забить, в каком то нет.
при быстром обмене метод по размеру перестает быть надежным.
почему ?
потому что для контроля получения сообщения по размеру нужно четко понимать, где начало сообщения. А если у вас сообщения идут сплошным потоком, откуда вы начало будете отсчитывать?
Классический пример - что тут написано "мать-мать-мать" или "тьма-тьма-тьма" ?
Согласен да. Но в каких то узких задачах вполне применимо. Размер это же дополнительное условие .
Если настроим например на поиск тьма то мы его нашли и нас это устраивает. Если изначально избегать ситуации при проектировании чтоб два слова были ключевыми и тьма и мать
Можно пропустить байт из первой последовательности и хватануть вместо него из следующей - все, капец, в буфере фигня. Если канал прям супернадежный... ну тогда может быть, я бы на это не расчитывал. ~тьма~тьма~тьма~тьма~тьма и уже путаницы нет
А если вы заранее не знаете, что будет передаваться?
поверьте, в разы проще определить начало и конец пакета в виде уникальных символов(или последовательности )
Помню как то давно анализировал файлы логов с мини-АТС - на небольшой скорости пуляла в комп по rs-232 (9600 или 19200), шнурок правда не особо короткий был, метров 5-7 - вполне проскакивали кракозябры иногда.
Никто не спорит что так удобней. Просто работая по размеру мы же чего то да ждем. Если прошли кзябры и они нас не устроили "извините сударь команда не распознана" и пусть наладчик с отладчиком развивают тему до приемлемого результата моли идут другим путем.
Ну то есть варианты есть и это хорошо!
Спасибо
Горбатого могила исправит.
тогда это будет продакшн баг :)
"но лучше сразу заложить " не зря грамотные архитекторы на вес золота