Можно ли грамотно выловить Serial через if а не while

alexbmd
Offline
Зарегистрирован: 15.01.2016

всем привет

	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

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Кода передатчика нет, код приёмника неполон. Что именно передавалось - неизвестно....

В общем, ответ на основной вопрос "Можно ли грамотно выловить Serial через if а не while" - можно, если вылавливать будет грамотный человек.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Женя лукавит немного... Скорее всего потому что дорогой ТС завел  нудную привычку доставать вопросами, на которые можно и нужно искать ответы самому, то есть типично учебными вопросами.

Но в честь начала пути исправления кармы ;)))) я дам, надеюсь исчерпывающий, ответ.

ИТАК:

Есть несколько способов или паттернов програмирование контроллеров. Один их них - "бесконечный цикл", который предлагается основным в парадигме Ардуино. Не сильно богатая периферия АВР контроллера преполагает т.н. "автоматный" стиль создания кода. Не вдаваясь в детали, АРХИВАЖНОЙ задачей становится сокращение времени одного прохода loop(). Например это важно для того, чтобы контроллер оперативно обработал произошедшее событие. Причем не имеет значения событие обрабатывается по прерыванию или проверкой. В парадигме Ардуино прерывание следует использовать исключительно для поднятия флага события или постановки в очередь короткого сообщения.

Таким образом не только можно, но исключительно необходимо проверять буфер приема Сериала не while, а if, и считывать не более одного символа за один проход loop(). Считав символ, следует провести проверку на адекватность ожиданию и на признак завершения ожидаемого ввода.

==================

Занудно, но, надеюсь, понятно. Да?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

wdrakula пишет:

Женя лукавит немного... 

Категорически протестую. В чём я сказал неправду? Кода нет, передаваемых данных нет. Сделать можно, если делать грамотно. Что не так? :))))

nik182
Offline
Зарегистрирован: 04.05.2015

А вот чем if с goto в конце блока от while отличается? И тут и там проверка условия. И вообще loop внутри while вызывается. Может просто loop начинать с while(1){}; и в скобках всю работу. Всё быстрее крутится будет?

sadman41
Offline
Зарегистрирован: 19.10.2016

nik182 пишет:

Может просто loop начинать с while(1){}; и в скобках всю работу. Всё быстрее крутится будет?

Быстрее будет на миллисекунду максимум. Но можно потенциальные глобалы внутрь функции занести. И вообще - луп не трогать, а прямо в setup() замутить цикл.

alexbmd
Offline
Зарегистрирован: 15.01.2016

ЕвгенийП пишет:

Кода передатчика нет, код приёмника неполон. Что именно передавалось - неизвестно.....

Передатчик - сам gsm модем. Поэтому кода нет. Что отправит то и увидим. (Да я забыл указать что в примере используется прослушка gsm. Sorry)
Приемник - в данном примере он полон. Максимально быстро выводим что пришло. (В свете _грамотной_ работы по отлову очевидно не полный. Поэтому и вопрос. )
Что передовалось известно. SM x это входящий смс. Но в свете вопроса не это важно. Пускай передается что угодно нам же надо вывести это грамотно (тобишь как минимум в том же виде что пришло*)

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

Дракула, все понятно, спасибо. Вот поэтому и вопрос про if.
Например, я думал что железный буфер тот что 1 байт, "знает" что он еще не все символы передал из .. как назвать правильно второй буфер тот что 64 байта... второго буфера. А получается из железного байт ушёл, а следующий не редко поступает медленно. Медленно имеется ввиду что успевает отработать if (! serial. Available).....
Хотя я сейчас подумал может поменять эти два if (чтения и вывода) местами , тем самым может хватит времени на заполнение железного буфера и if (! serial. Available) не будет срабатывать пока все сообщение не прочитаем... ну это так мысли вслух.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

alexbmd пишет:
if (! serial. Available())

Понимаешь.... я свое уже отпреподавал и больше точно не хочу. Поэтому подробности объяснять не стану, но такая конструкция совершенно не нужна и глупа. Проверять буфер на пустоту никогда не имеет смысла, при грамотном кодировании.

Читай образцы хорошего кода, читай ДШ и примеры. Учись сам и в тишине! Коммуникативная депривация в стиле "почемучка" прилична детям, а не взрослому мужику. Форум - не школа и ЧаВо и не справочная.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

alexbmd пишет:
Что отправит то и увидим.

Т.е. Вы отлаживаете приём не зная точно, что передаётся? Ну,успехов!

alexbmd пишет:
Приемник - в данном примере он полон.
Вы опять решили подискутировать? Не со мной, пожалуйста. Программа в которой не описаны переменные полной быть не может.

В общем, разбирайтесь сами.

alexbmd
Offline
Зарегистрирован: 15.01.2016

разобрался/пофиксил прекрасно принимает на if'ах (не зная что передаётся. но справедливости ради стоит сказать что от модема как никрути приходит только валидные символы. но учтенно на вход и не валидные тоже) и выводит. Но используя переменную флаг для конца строки

if (serial.available) {
...
   if (конец строки) flag=1
}

if (flag) {
вывод
}

остался только один основной вопрос: "А можно ли тоже самое сделать не используя дополнительную переменную для конца строки?"

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

alexbmd пишет:

разобрался/пофиксил прекрасно принимает на if'ах (не зная что передаётся. но справедливости ради стоит сказать что от модема как никрути приходит только валидные символы. но учтенно на вход и не валидные тоже) и выводит. Но используя переменную флаг для конца строки

if (serial.available) {
...
   if (конец строки) flag=1
}

if (flag) {
вывод
}

остался только один основной вопрос: "А можно ли тоже самое сделать не используя дополнительную переменную для конца строки?"

Ответ на Ваш вопрос существенно зависит от того, что именно Вы подразумеваете под словами "то же самое" (взял на себя смелость поправить авторское написание).

alexbmd
Offline
Зарегистрирован: 15.01.2016

под словами "то же самое" я подразумевал, 

1. получить всю строку из serial но не опредляя конец строки по пришедшему чару, закинуть в наш буфер

2. вывести буфер

вот я пытался по available() определять но получилась ерунда.  других методов я не знаю. спросил более знающих.

 

Morroc
Offline
Зарегистрирован: 24.10.2016

alexbmd пишет:
1. получить всю строку из serial но не опредляя конец строки по пришедшему чару, закинуть в наш буфер

Какие у вас варианты ? По маркерам начала/конца, зная размер строки, по тайм-ауту. Первое самое надежное.

alexbmd пишет:
ailable() определять но получилась ерунда.  других методов я не знаю. спросил более знающих

Это никак не отменяет контроля по символу конца строки и т.п. Ну т.е. если в буфере и есть какой то символ - он может быть полной ерундой, так бывает.

b707
Offline
Зарегистрирован: 26.05.2017

alexbmd пишет:

1. получить всю строку из serial но не опредляя конец строки по пришедшему чару

Единственный метод НАДЕЖНО определить конец строки неизвестной длины - только "по пришедшему чару". Других методов НЕ СУЩЕСТВУЕТ. А как этот конец строки ловить - по if или по while - роли не играет.

alexbmd
Offline
Зарегистрирован: 15.01.2016

да уже про if while никто не спрашивает.

Morroc , точно по размеру может мне пригодиться . спасибо.

b707
Offline
Зарегистрирован: 26.05.2017

alexbmd пишет:

точно по размеру может мне пригодиться . спасибо.

при быстром обмене метод по размеру перестает быть надежным.

хотя вам это скорее всего не пригодится

alexbmd
Offline
Зарегистрирован: 15.01.2016

без последней фразу никак 

b707 пишет:

при быстром обмене метод по размеру перестает быть надежным.

почему ?

Morroc
Offline
Зарегистрирован: 24.10.2016

Потому что всегда есть вероятность получить вместо нужного байта ерунду (или получить ерунду вдобавок к нужному байту или не получить какой нибудь байт вообще). В каком то случае можно на это забить, в каком то нет.

b707
Offline
Зарегистрирован: 26.05.2017

alexbmd пишет:

b707 пишет:

при быстром обмене метод по размеру перестает быть надежным.

почему ?

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

Классический пример - что тут написано "мать-мать-мать" или "тьма-тьма-тьма" ?

alexbmd
Offline
Зарегистрирован: 15.01.2016

Согласен да. Но в каких то узких задачах вполне применимо. Размер это же дополнительное условие .
Если настроим например на поиск тьма то мы его нашли и нас это устраивает. Если изначально избегать ситуации при проектировании чтоб два слова были ключевыми и тьма и мать

Morroc
Offline
Зарегистрирован: 24.10.2016

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

b707
Offline
Зарегистрирован: 26.05.2017

alexbmd пишет:
Согласен да. Но в каких то узких задачах вполне применимо. Размер это же дополнительное условие . Если настроим например на поиск тьма то мы его нашли и нас это устраивает. Если изначально избегать ситуации при проектировании чтоб два слова были ключевыми и тьма и мать

А если вы заранее не знаете, что будет передаваться?

поверьте, в разы проще определить начало и конец пакета в виде уникальных символов(или последовательности )

Morroc
Offline
Зарегистрирован: 24.10.2016

Помню как то давно анализировал файлы логов с мини-АТС - на небольшой скорости пуляла в комп по rs-232 (9600 или 19200), шнурок правда не особо короткий был, метров 5-7 - вполне проскакивали кракозябры иногда.

alexbmd
Offline
Зарегистрирован: 15.01.2016

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

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Горбатого могила исправит.

Morroc
Offline
Зарегистрирован: 24.10.2016

alexbmd пишет:
Если прошли кзябры и они нас не устроили "извините сударь команда не распознана"
А если распознана, но не так или вместо "повернуть на 10 градусов" получилось "на 100 градусов" ? :) Варианты есть, но лучше сразу заложить все вместе - оно же не особо сложно.

alexbmd
Offline
Зарегистрирован: 15.01.2016

тогда это будет продакшн баг :)

"но лучше сразу заложить " не зря грамотные архитекторы на вес золота