Очищается ли содержимое буфера порта после операции Serial.read()?

Sonologist
Sonologist аватар
Offline
Зарегистрирован: 08.06.2018

Почему-то не нашел информации. Воспроc связан с будущей конфигурацией цикла While (по условию наличия или отсутствия строчки в порте).

Araris
Offline
Зарегистрирован: 09.11.2012

Поправил название темы, если Вы не против. 

Ответ - да, очищается. Почему-то не нашли информации )).

MaksVV
Offline
Зарегистрирован: 06.08.2015

функция читает один байт, соответственно этот байт и  очищается из буфера. 

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

Ничего там не очищается. Если читать весь буфер, то там всегда есть значения отличные от нуля. 

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

nik182 пишет:

Ничего там не очищается. Если читать весь буфер, то там всегда есть значения отличные от нуля. 

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

а то что в ячейках буфера остаются ненулевые значения - так это просто свойство буфера...

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

b707 пишет:

nik182 пишет:

Ничего там не очищается. Если читать весь буфер, то там всегда есть значения отличные от нуля. 

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

а то что в ячейках буфера остаются ненулевые значения - так это просто свойство буфера...

Ну так, значить, формально, буфер не очищается (не забивается нулями). :)  

Хрен знает, что имел ввиду ТС, у него на аватарке не написано

MaksVV
Offline
Зарегистрирован: 06.08.2015

nik182 пишет:

Ничего там не очищается. Если читать весь буфер, то там всегда есть значения отличные от нуля. 

а что значить очистить буфер (читай байт)? Уничтожить байт? или записать туда FF или 00? но это ведь тоже информация. Понятное дело - речь идёт про то, что программа указывает, что здесь теперь у нас пусто. 

 

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

nik182 пишет:

Ничего там не очищается. Если читать весь буфер, то там всегда есть значения отличные от нуля. 

Интересно, чем нулевые значения "чище" любых других? Сегрегацией и ксенофобией попахивает.

Гриша
Offline
Зарегистрирован: 27.04.2014

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

nik182 пишет:

Ничего там не очищается. Если читать весь буфер, то там всегда есть значения отличные от нуля. 

Интересно, чем нулевые значения "чище" любых других? Сегрегацией и ксенофобией попахивает.

в продолжение темы ...  это типа если место можно занять, значит оно свободно и попробуйте оспорить. :)))))

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Ладно, признаю, я неправ. Очищается. Пашутить уже нельзя, сразу в сегрегацыи обвиняють. :)  Ироды. 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Гриша пишет:

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

nik182 пишет:

Ничего там не очищается. Если читать весь буфер, то там всегда есть значения отличные от нуля. 

Интересно, чем нулевые значения "чище" любых других? Сегрегацией и ксенофобией попахивает.

в продолжение темы ...  это типа если место можно занять, значит оно свободно и попробуйте оспорить. :)))))

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

Гриша
Offline
Зарегистрирован: 27.04.2014

andycat пишет:

Гриша пишет:

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

nik182 пишет:

Ничего там не очищается. Если читать весь буфер, то там всегда есть значения отличные от нуля. 

Интересно, чем нулевые значения "чище" любых других? Сегрегацией и ксенофобией попахивает.

в продолжение темы ...  это типа если место можно занять, значит оно свободно и попробуйте оспорить. :)))))

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

Зачетно!!!! :)))))))))))))))) Видишь суслика? а он есть

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

Если в буфер положить строку, то содержащаяся в этой строке информация останется в буфере после считывания. Это я имел в виду что не очищается. Очистить буфер от информации - затереть чем угодно - хоть ноликами, хоть единицами хоть белым шумом. А вдруг там пароль от счета на Багамах? Сдвинуть указатель это действие только для обслуживающего буфер драйвера очистка. 

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

Ноль - это тоже данные... Надо как-то вакуумировать или хлорировать ячейки памяти для полной очистки.

anatoli_nik
Offline
Зарегистрирован: 17.01.2019

Подключить пины, допустим, порта В на + питания, затем:

void ochistka (void){
PORTB = 0;
DDRB = 0xFF;
}
void setup ()
{
}
void loop(){
ochistka();
}

Должно помочь, зуб даю!

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

nik182 пишет:

А вдруг там пароль от счета на Багамах? 

А вдруг наоборот, его там не было, а в "белом шуме" случайно сгенерится?

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

Первый вопрос, которым следовало бы задаться, а что, собственно, ТС подразумевает под "очисткой буфера".

Может, имеется в виду, что после "очистки" указанные адреса памяти становятся недоступными как для чтения, так и для записи.

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

andycat пишет:

а пожалуйста: циклический буфер - он одновременно и свободен и занят

Прямо буфер Шрёдингера :)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

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

nik182 пишет:

Ничего там не очищается. Если читать весь буфер, то там всегда есть значения отличные от нуля. 

Интересно, чем нулевые значения "чище" любых других? Сегрегацией и ксенофобией попахивает.

предлагаю внести предложение и переделать библиотеку чтобы  записывать последовательность из F6, как при форматировании

MaksVV
Offline
Зарегистрирован: 06.08.2015

я думаю b707 #4 правильно понял ТС. 

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

MaksVV пишет:

я думаю b707 #4 правильно понял ТС. 

А я думаю, что это пофиг, т.к. ТС на тему забил и уж двое суток народ сам резвится, без него :)

Sonologist
Sonologist аватар
Offline
Зарегистрирован: 08.06.2018

Простите, друзья, Интернет не вовремя отрубили... Суть вопроса чуть поподробнее. ПК выбрасывает строчку в порт 1 раз в секунду. С ПК подаю в порт некую строчку с параметрами, Ардуина ее читает, парсирует и циклически выполняет программу на основании этих параметров. Отсюда вопрос: Ардуино прочитала порт, и порт опустел? Тогда можно в начале лупа коротким циклом While просто проверять Serial.avalable () на наличие чего-то в порту, и если есть - выполнять программу с новыми параметрами, а если нет - продолжать это делать со старыми. Если в порту после чтения что-то остается, то тогда цикл While надо начинать в начале лупа. а заканчивать в конце. Вот как-то так....

Гриша
Offline
Зарегистрирован: 27.04.2014

Sonologist пишет:

 Тогда можно в начале лупа коротким циклом While просто проверять Serial.avalable () на наличие чего-то в порту, и если есть - выполнять программу с новыми параметрами, а если нет - продолжать это делать со старыми.

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

как бы все есть в примере (коротко и мало понятно)

UPD

все не читал, но вроде понятно написано - serialEvent, смутно понимаю, что именно это вы искали или я ошибся? 

Sonologist
Sonologist аватар
Offline
Зарегистрирован: 08.06.2018

Ага, спасибо. Правда, про ссылкам не то, что меня интересовало (с парсингом строки я уже разобрался), но все равно спасибо. Что касается вашего текста - все понял, буду действовать..

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

Sonologist пишет:

Простите, друзья, Интернет не вовремя отрубили... Суть вопроса чуть поподробнее. ПК выбрасывает строчку в порт 1 раз в секунду. С ПК подаю в порт некую строчку с параметрами, Ардуина ее читает, парсирует и циклически выполняет программу на основании этих параметров. Отсюда вопрос: Ардуино прочитала порт, и порт опустел? Тогда можно в начале лупа коротким циклом While просто проверять Serial.avalable () на наличие чего-то в порту, и если есть - выполнять программу с новыми параметрами, а если нет - продолжать это делать со старыми. Если в порту после чтения что-то остается, то тогда цикл While надо начинать в начале лупа. а заканчивать в конце. Вот как-то так....

1. Да, в Вашей терминологии порт после чтения становится пустым.

2. Делать что-либо в начале "лупа" или в конце - нет никакой разницы. 

3. Идея с проверкой available - плохая: контроллер работает намного быстрее собственного порта, поэтому почти наверняка проверка available произойдет тогда, когда порт еще не принял строку до конца. Правильный алгоритм - парсить не принятую строку, а входной поток посимвольно, и как только будет принят признак конца строки (а не начала, как Вы предполагаете), переключаться на новые параметры.

Sonologist
Sonologist аватар
Offline
Зарегистрирован: 08.06.2018

Благодарю, мысль понял. Но в моем случае входящая строка будет строго определенной длины, поэтому (на мой взгляд!) проще проверять именно это плюс некий значок ее начала (или окончания), а не посимвольно формировать ее из потока. Посимвольный прием, конечно, более универсален, но в конкретной задаче излишен. Нет?

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Нет, т к не факт что вся ваша строка придёт сразу а не через 0.05 секунды например, соответственно если жёстко ждать конца строки то за эту долю секунды скетч будет простаивать, что нехорошо

Sonologist
Sonologist аватар
Offline
Зарегистрирован: 08.06.2018

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

Densl
Offline
Зарегистрирован: 28.11.2018

Sonologist пишет:

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


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

astwo
Offline
Зарегистрирован: 10.07.2019

Ну например... Опрос кнопок. Если процессор будет где-то простаивать то разумеется опроса не будет. Да и простаивание где-то процессора в конкретном месте уже не красит программу и программиста написавшего этот шедевр.

Densl
Offline
Зарегистрирован: 28.11.2018

Я не совсем понял, т.е. предлагается после каждого принятого байта переключать МК на другие задачи? А эти самые регулярные переключения не скажутся в итоге на скорости обмена?

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

Densl пишет:
Да я думаю сложно найти задачу, где это простаивание оказалось критичным.

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

 

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

Densl пишет:
Я не совсем понял, т.е. предлагается после каждого принятого байта переключать МК на другие задачи? А эти самые регулярные переключения не скажутся в итоге на скорости обмена?

не после каждого байта, а после выборки всех байт из буфера Сериал. На скорости Сериал обычно это не сказывается - последовательный интерфейс один из самых медленных в контроллере, как правило это он все тормозит. а не наоборот

 

Densl
Offline
Зарегистрирован: 28.11.2018

b707 пишет:

Densl пишет:
Да я думаю сложно найти задачу, где это простаивание оказалось критичным.

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

 


А там какие задержки? Serial.print(...) разве с задержкой работает?

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Densl пишет:
Я не совсем понял, т.е. предлагается после каждого принятого байта переключать МК на другие задачи?

да

http://arduino.ru/forum/apparatnye-voprosy/vse-o-sim800l-i-vse-chto-s-nim-svyazano?page=1#comment-439631

Update: Хотя нет, там цикл пока весь UART не вычитается, но все равно обработка идет каждого байта.

 

rkit
Offline
Зарегистрирован: 23.11.2016

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

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

Цитата:
А там какие задержки? Serial.print(...) разве с задержкой работает?

Вы не путайте print() и read().

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

А второй может вычитать из буфера только то, что там уже успело накопиться. По available() мы узнаем о приходе 1-го байта, т.е. либо мы считываем только первый байт посылки, либо ждем, пока не накопятся остальные. А накапливаются они очень медленно.

 

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

Densl
Offline
Зарегистрирован: 28.11.2018

andriano пишет:

Цитата:
А там какие задержки? Serial.print(...) разве с задержкой работает?

Вы не путайте print() и read().

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

А второй может вычитать из буфера только то, что там уже успело накопиться. По available() мы узнаем о приходе 1-го байта, т.е. либо мы считываем только первый байт посылки, либо ждем, пока не накопятся остальные. А накапливаются они очень медленно.

 

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


Я не путаю. B707 высказался что на передающей стороне могут быть задержки.
Serial.Available() в моем случае не имеет альтернативы, т.к. у меня там есть блокирующие функции в которые приходится внедрять такие конструкции, чтобы выйти из них.
Я посмотрел код функции available, в ней нет ничего, что могло бы замедлять работу МК, т.к. чтение в ней происходит не каких-либо регистров, а непосредственно глобальных переменных, что совсем не плохо.

MaksVV
Offline
Зарегистрирован: 06.08.2015

Densl пишет:
Я не совсем понял, т.е. предлагается после каждого принятого байта переключать МК на другие задачи? А эти самые регулярные переключения не скажутся в итоге на скорости обмена?

имхо, по-нормальному нужно, чтобы в пакете, кроме данных содержались также маркер начала, длина пакета и контрольная сумма, тогда собирать на приёмной стороне такой пакет легко и надёжность выше. И читаем по байту за проход лупа (если конечно этот байт уже в буфере появился, если нет - проходим мимо) и никаких задержек. 

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

Нет, ну по идее, чтобы без задержек, да при фиксированной длине пакета - получается два варианта:

1. На каждом проходе loop() Опрашиваем по available() [!=0], и складываем в буфер или сразу посимвольно парсим пока не придет все сообщение. (универсальный способ, допустим при неизвестной заранее длине пакета)

2. Крутя цикл loop(), дожидаемся, пока станет available() == N, где N - длина пакета, и тогда читаем целиком.

 

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

Densl
Offline
Зарегистрирован: 28.11.2018

MaksVV пишет:

Densl пишет:
Я не совсем понял, т.е. предлагается после каждого принятого байта переключать МК на другие задачи? А эти самые регулярные переключения не скажутся в итоге на скорости обмена?

имхо, по-нормальному нужно, чтобы в пакете, кроме данных содержались также маркер начала, длина пакета и контрольная сумма, тогда собирать на приёмной стороне такой пакет легко и надёжность выше. И читаем по байту за проход лупа (если конечно этот байт уже в буфере появился, если нет - проходим мимо) и никаких задержек. 


Ещё нужно число передавать не символьным знаком типа *char.

А я помню стандарт RsS232 предусматривал два дополнительных провода. Один для выставления логического уровня когда отправляются данные, другой читают когда принимаются. Можно нечто подобное и тут сделать для ускорения работы, но похоже тут в большинстве случаев это лишнее.

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

andriano пишет:

Нет, ну по идее, чтобы без задержек, да при фиксированной длине пакета - получается два варианта:

1. На каждом проходе loop() Опрашиваем по available() [!=0], и складываем в буфер или сразу посимвольно парсим пока не придет все сообщение. (универсальный способ, допустим при неизвестной заранее длине пакета)

2. Крутя цикл loop(), дожидаемся, пока станет available() == N, где N - длина пакета, и тогда читаем целиком.

я всегда работаю только по первому варианту - при каждом обороте ЛУП читаю available() и выбираю из буфера все имеющиеся символы. Если сообщение не пришло целиком - без ожидания перехожу к другим ветвям программы

 

 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Если пришла какая нибудь html страница по gprs, она в принципе не влезет в память МК, так что парсить online единственный универсальный способ.

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

b707 пишет:

я всегда работаю только по первому варианту...

Для неизвестной заранее длины пакета - это вообще единственный вариант.

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

b707 пишет:
при каждом обороте ЛУП читаю available() и выбираю из буфера все имеющиеся символы.

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

Logik
Offline
Зарегистрирован: 05.08.2014

andriano пишет:

b707 пишет:

я всегда работаю только по первому варианту...

Для неизвестной заранее длины пакета - это вообще единственный вариант.

Токо по первому. С поправкой на "складываем в буфер или сразу посимвольно парсим"  - там как правило и то и другое делается. Ну распарсили очередной символ и пришли к выводу что это не все символы идентификатора или значения и что делать? Только сохранять уже принятое  в буфере пока следующий символ не приехал. Живой пример здесь http://arduino.ru/forum/apparatnye-voprosy/gsm-modem-a6-v-rezhime-tcp , строки 714-717.

Одна беда. Парсинг "на лету" - самый сложный из других подходов.

ПС. При неизвестной заранее длине пакета таки бывают варианты. Эту неизвестную заранее длину передают (явно или неявно) гдето в начале пакета чем сводят дальнейшую работу к случаю известной длинны.

Logik
Offline
Зарегистрирован: 05.08.2014

По теме топика. Определимся что имеет ввиду ТС как буффер. Если просто массив  - read() не меняет его содержимое. Правильней считать буфером не только сам массив, но и набор переменных связанных с ним для организации буфера. В таком случае вызов read() при наличии  принятых данных загрязняет буфер, т.к. уменьшает на 1 байт кол-во данных в нем и увеличивает на 1 байт количество временно не использованных ячеек - т.е. мусора.

astwo
Offline
Зарегистрирован: 10.07.2019

Скорее ТС включил валенок. Но есть канальный уровень а есть транспортный. И там и там цель передача и получение данных. Но если канальный ЭТОSPI I2C ONEWIRE, то транспортный это Serial. Что понятнее, канальный это такси сел и едешь. То транспортный это пришёл на почту и отправил посылку, или получил если дошла. Канальный это дорогой и надо выделять время, то почта дешевле и можно в удобное время отправить-получить. Теперь вопрос. Можно очистить почту. Можно но до следующего привоз. А привоз он следует своей логике и от воли клиентов не зависит.

Sonologist
Sonologist аватар
Offline
Зарегистрирован: 08.06.2018

Даже и не думал, что простой с первого взгляда вопрос вызовет столь широкую дискуссию :)

Тогда так. В порт от ПК один раз в секунду приходит 27-символьная строка с параметрами. Ардуино ее читает, анализирует (парсинг) и рассовывает параметры по переменным. После чего начинает выполнять очередной луп согласно изменившимся или не изменившимся переменным. Только и всего. Отсюда вопрос и возник. Если порт очищается - то его достаточно прочесть в начале лупа, выявить, соответствует ли длина строки 27 символам, если да, то закрыть цикл While и работать с новыми параметрами, если нет - то игнорировать и делать все как раньше. 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Ага, а на 13 символе прилетит помеха и/или delay, или прерывание на вывод параметров в serial сработает, параметр прочитается криво, железка угробит что нибудь более серьёзное.

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

Sonologist пишет:

Если порт очищается - то его достаточно прочесть в начале лупа, выявить, соответствует ли длина строки 27 символам, если да, то закрыть цикл While и работать с новыми параметрами, если нет - то игнорировать и делать все как раньше. 

Вы сами-то поняли, что тут написано? Я нет. Потому и срач на неделю, что все пытаются угадать что же Вам надо и спорят между собой.

Sonologist пишет:

если да, то закрыть цикл While и работать

Какой ещё цикл while?

Sonologist пишет:

если нет - то игнорировать и делать все как раньше. 

Что "всё как раньше"?

Т.е. Вам надо примерно так:

Входите в луп, смотрите сколько символов пришло. Допустим прийти успело 26 (один ещё не успел). Поскольку их не 27, Вы выбрасываете их и "делаете всё как раньше". При следующем лупе приходит не успевший в прошлый раз 27-ой символ. Поскольку символов опять не 27, а один, Вы и его выбрасываете и "делаете всё как раньше".

Правильно, Вам так надо? Если так, то проще забить и вообще эти символы не получать.