Как очистить Serial входящий буфер

Yarockiisergei
Offline
Зарегистрирован: 17.01.2015

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

я считываю 8 байт но т.к. в в буфере накопленное колличество я беру не актуальные данные.

Можно ли забать размер зранимй буффера? Или провести его очистку?

brokly
brokly аватар
Онлайн
Зарегистрирован: 08.02.2014

Serial.available() как раз и возвращает количество байт полученных данных в буфере. Для "очистки" буфера нужно его вычитать в никуда. Только ваши проблемы от неправильного подхода к работе с последовательным интерфейсом. Вы пытаетесь синхронизировать пакеты данных временными задержками. Отправили пакет-пауза-отправили-пауза.... Это самый простой и самый ненадежный способ. Отсюда и ваши непонятки.

Famouspilot
Famouspilot аватар
Offline
Зарегистрирован: 19.01.2016

brokly пишет:

Serial.available() как раз и возвращает количество байт полученных данных в буфере. Для "очистки" буфера нужно его вычитать в никуда. Только ваши проблемы от неправильного подхода к работе с последовательным интерфейсом. Вы пытаетесь синхронизировать пакеты данных временными задержками. Отправили пакет-пауза-отправили-пауза.... Это самый простой и самый ненадежный способ. Отсюда и ваши непонятки.

Прошу прощения, что опоздал на год с лишним, но как все-таки очистить буфер? Мне не очень понятно выражение "вычитать в никуда", если это не сарказм, а считывать байты до умопомрачения, используя "Serial.available()" уже не катит. 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Famouspilot пишет:

как все-таки очистить буфер? Мне не очень понятно выражение "вычитать в никуда", если это не сарказм, а считывать байты до умопомрачения, используя "Serial.available()" уже не катит. 

while (Serial.available()) Serial.read();

Famouspilot
Famouspilot аватар
Offline
Зарегистрирован: 19.01.2016

Andy пишет:

Famouspilot пишет:

как все-таки очистить буфер? Мне не очень понятно выражение "вычитать в никуда", если это не сарказм, а считывать байты до умопомрачения, используя "Serial.available()" уже не катит. 

while (Serial.available()) Serial.read();

Я об этом и говорю - нельзя ли как-то обойтись одной функцией, как когда-то это делала Serial.flush?

Клапауций 823
Клапауций 823 аватар
Offline
Зарегистрирован: 13.01.2017

Famouspilot пишет:
нельзя ли как-то обойтись одной функцией, как когда-то это делала Serial.flush?

я запретил.

Famouspilot
Famouspilot аватар
Offline
Зарегистрирован: 19.01.2016

Клапауций 823 пишет:

Famouspilot пишет:
нельзя ли как-то обойтись одной функцией, как когда-то это делала Serial.flush?

я запретил.

Ваши запреты для меня не значат ничего. Хочется все-таки по делу что-то узнать.

Клапауций 823
Клапауций 823 аватар
Offline
Зарегистрирован: 13.01.2017

Famouspilot пишет:
Ваши запреты для меня не значат ничего. Хочется все-таки по делу что-то узнать.

как же не значат, если ты не можешь очистить буфер.

Famouspilot
Famouspilot аватар
Offline
Зарегистрирован: 19.01.2016

Клапауций 823 пишет:

Famouspilot пишет:
Ваши запреты для меня не значат ничего. Хочется все-таки по делу что-то узнать.

как же не значат, если ты не можешь очистить буфер.

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

Клапауций 823
Клапауций 823 аватар
Offline
Зарегистрирован: 13.01.2017

Famouspilot пишет:
Я не могу очистить буфер не из-за того, что какой-то жирный тролль мне что-то запретил, а из-за того, что в моих знаниях устройства библиотеки Serial есть небольшие пробелы.

а, какая разница по сути?

alexpetro000
Offline
Зарегистрирован: 17.11.2013

Если хочется по-сложному, то так:

Переходим сюда:
%местокудапоставилиArduino%\Arduino\hardware\arduino\avr\cores\arduino

Открываем файл HardwareSerial.cpp
На предпоследней строке файла дописываем:

void HardwareSerial::clear()
{
	_rx_buffer_head = _rx_buffer_tail;
}

Сохраняем файл.

Открываем файл HardwareSerial.h
после public: на следующей строке пишем

virtual void clear(void);

Сохраняем.

Далее в коде можно будет использовать функцию Serial.clear(); которая очистит входной буфер

witcher553
Offline
Зарегистрирован: 31.12.2017

Привет! Может тупой вопрос, но я  сделал как сказано  слив буфера через while и ничего не не работает.  

Если пишу в терминал 123 допустим то скетч крутится 3 раза и все цифры мне выдает. В чем проблема? Может помочь кто?


void setup(){
Serial.begin(115200);
Serial.println("REDY");
}
 
void loop(){

  while(Serial.available() == 0);
  int com = Serial.read() - '0';
  Serial.println(com);
  while(Serial.available()){
    Serial.read();
  }
  
}

Вообще мне нужно считать с буфера 1ю десятичную цифру и если есть что там еще слить. 

vk007
Offline
Зарегистрирован: 16.06.2015

В 12-й строке после Serial.read(); можно поставить небольшую задержку, например, delay(5); тогда должно вычитывать буфер нормально.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

witcher553 пишет:
Если пишу в терминал 123 допустим то скетч крутится 3 раза и все цифры мне выдает. В чем проблема? Может помочь кто?
Вы банально не понимаете как работает Serial. 123 отправляются не одним пакетом "123" , а тремя "1","2","3" (а если еще и новая строка то и "\0").  И потом это все накапливается в буфере.  То есть прилетело "1"- очистили,"2"-очистили,"3"- очистили . Но зачем вам нужна эта чистка . Вы должны собрать полный супер-пакет из "1","2","3", "\0"и потом обрабатывать.  

witcher553
Offline
Зарегистрирован: 31.12.2017

qwone пишет:

witcher553 пишет:
Если пишу в терминал 123 допустим то скетч крутится 3 раза и все цифры мне выдает. В чем проблема? Может помочь кто?
Вы банально не понимаете как работает Serial. 123 отправляются не одним пакетом "123" , а тремя "1","2","3" (а если еще и новая строка то и "\0").  И потом это все накапливается в буфере.  То есть прилетело "1"- очистили,"2"-очистили,"3"- очистили . Но зачем вам нужна эта чистка . Вы должны собрать полный супер-пакет из "1","2","3", "\0"и потом обрабатывать.  

Я в своей программе управляю меню через serial порт.  Отправил 1 перешел в подменю 1 и тд. Поэтому и решил сделать защиту от случайных нажатий путем слива буфера.

Понимаю что Serial не для этого делали. Но может есть какой-то вариант?

Спасибо что разжевали подробно программировать недавно начал.

Famouspilot
Famouspilot аватар
Offline
Зарегистрирован: 19.01.2016

Рекомендую очищать буфер через некоторое время после считывания символа, например, через 300мс. Это позволит исключить прием символов одного и того же пакета после считывания символа перехода меню. А эти 300мс либо "простоять", либо игнорировать входящие данные.

Насколько мне известно, в классе Serial до сих пор нет какого-то однозначного и конкретного метода, который бы позволил очищать буфер в один вызов. Поэтому, while(Serial.available()) Serial.read() - решение проблемы. Если режет глаза, можно дописать пару строк кода в библиотеке заголовков класса Serial (сам заголовочный класс называется как-то иначе, сейчас не вспомню), добавив методы вроде clear(). А если залезть глубже, то это можно сделать и в библиотеке Stream, даже поигравшись с указателями на начало и конец кольцевого буфера.

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

witcher553 пишет:
Я в своей программе управляю меню через serial порт.  Отправил 1 перешел в подменю 1 и тд. Поэтому и решил сделать защиту от случайных нажатий путем слива буфера.

Понимаю что Serial не для этого делали. Но может есть какой-то вариант?

Как не для этого, И для этого тоже.Вот только вы еще не научились делать.https://www.arduino.cc/en/Tutorial/SwitchCase2

5N62V
Offline
Зарегистрирован: 25.02.2016

witcher553 пишет:

Я в своей программе управляю меню через serial порт.  Отправил 1 перешел в подменю 1 и тд. Поэтому и решил сделать защиту от случайных нажатий путем слива буфера.

Понимаю что Serial не для этого делали. Но может есть какой-то вариант?

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

vk007
Offline
Зарегистрирован: 16.06.2015

qwone пишет:
Вы должны собрать полный супер-пакет из "1","2","3", "\0"и потом обрабатывать.

Э-м-м-м-м.... Нисколько не сомневаюсь в Вашей квалификации, но объясните мне пожалуйста, допустим, нужно из того, что прилетело из Serial, принять первых надцать байтов, а остальное проигнорировать. Но юзер то ли на эмоциях, то ли уснул на клавиатуре, то ли кот на ней потоптался и отправилась целая тыща байтов. Прикажете всю эту тыщу собирать в пакет и потом обрабатывать?!
Я спрашиваю без иронии. У меня в свое время была подобная задача. И да, не нашел ничего лучше, чем впихнуть delay(5) в цикл while (Serial.available()) { Serial.read(); delay(5); } и все заработало, как и хотелось - все лишнее в буфере очищалось. Да, быдлокод, но рабочий. А то, я смотрю, у кого-то от одного упоминания delay начинает бомбить.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Первое- Если у вас в serial прилетает х**ня, то этом виноват не serial, а Вы. 

А на второе Почему бы для начала делать так.

/**/
//--------------------------------
char buff[10];
byte iBuff = 0;
//---Компоновка-----------------------------
//---main-----------------------------
void setup() {
  Serial.begin(9600);
}

void loop() {
  if (Serial.available() > 0) {
    char c = Serial.read();
    if (c == '\n') { // конец пакета
      buff[iBuff] = 0;
      iBuff = 0;
      Serial.println(buff);//<--обрабатываете весь пакет
    }
    else {
      buff[iBuff++] = c;
    }
  }
}
/**/

 

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

readBytes умеет принимать надцать байт игнорируя другие.

5N62V
Offline
Зарегистрирован: 25.02.2016

А разве подразумевалось, что у него команды поступают пакетом и заканчиваются \n ? 

vk007
Offline
Зарегистрирован: 16.06.2015

Penni пишет:
readBytes умеет принимать надцать байт игнорируя другие.

Я через readBytes как-раз и принимаю данные, но эта функция не очищает оставшееся в буфере.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Выключение телевизора не прекращает работу телевизионной станции. Вы пытаетесь очищать буфер приемника (в Ардуине), но не сможите очистить буфер передатчика(в компьютере). Пока очистили буфер приемника, прилетел еще байт с компьютера. И так до бесконечности пока компьютер не передаст все.

vk007
Offline
Зарегистрирован: 16.06.2015

Ну так а я о чем? Конструкция вида while (Serial.available()) { Serial.read(); } очень быстро выполняется, по сравнению с тем, как компьютер передает данные, и очень быстро наступает Serial.available()==0, хотя не все данные еще поступили. Поэтому или нужна задержка, или для очистки надо выдумывать что-то другое.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Очистка буфера это на пустом месте надуманая проблема. Надо банально уметь принимать данные. А если данные ощибочные, то их надо принимать и ничего не делать.  На данном этапе Вы просто принимайте данные как есть. А вот на следующем Вы будете их анализировать и делать если они правильные.

//Вот идет Serial канал
'\n','1','2','3','\n','e','r','r','o','r','\n','9','8','0','\n',
//вы что не можите считать все и потом выбрать нужное
// или вам нужна "ненужная очистка буфера"
// 1 пакет
'1','2','3','\n'
// 2 пакет
'e','r','r','o','r','\n'
// 3 пакет
'9','8','0','\n'

 

Famouspilot
Famouspilot аватар
Offline
Зарегистрирован: 19.01.2016

vk007 пишет:
допустим, нужно из того, что прилетело из Serial, принять первых надцать байтов, а остальное проигнорировать. Но юзер то ли на эмоциях, то ли уснул на клавиатуре, то ли кот на ней потоптался и отправилась целая тыща байтов. Прикажете всю эту тыщу собирать в пакет и потом обрабатывать?! Я спрашиваю без иронии. У меня в свое время была подобная задача. И да, не нашел ничего лучше, чем впихнуть delay(5) в цикл while (Serial.available()) { Serial.read(); delay(5); } и все заработало, как и хотелось - все лишнее в буфере очищалось. Да, быдлокод, но рабочий. А то, я смотрю, у кого-то от одного упоминания delay начинает бомбить.

Если комплексно не очищать буфер, то этот мусор будет воспринят как управляющие сигналы. Насчет delay - у всех бомбит, потому что он съедает процессорное время и без того слабенького 8-битного процессора. Программа начнет "тупить, виснуть", и взять управление будет невозможно, если на порт прилетит всякий мусор. Чтобы очищать буфер по символу с определенной периодичностью, в данном случае лучше написать обработчик прерывания, который посадить либо на вектор регистра сравнения главного счетчика, чтобы как раз срабатывал с определенной периодичностью, либо на вектор приема данных USART-a.

Если не умеете обращаться с прерываниями, то просто где-то в цикле Loop поставьте сравнение времени с milliseconds() + 300 (к примеру), и в течение этого промежутка игнорируйте входные данные, а после - очищайте буфер.

vk007
Offline
Зарегистрирован: 16.06.2015

qwone пишет:

На данном этапе Вы просто принимайте данные как есть. А вот на следующем Вы будете их анализировать и делать если они правильные.

И снова Вы о своем. Например, мне надо было принимать строку, но с ограничением длины порядка 50 символов. А это не три, как у изначально вопрошающего. Полсотни букв визуально посчитать уже сложно. Ну не делать же мне, в самом деле, буфер размером 100500 байт, на случай, если кто-то введет 60-100-150... символов, и потом выбирать нужных мне 50. Мне надо считать 50, а от остальных избавиться - т.е. считать в пустоту. Т.е. в любом случае эти данные надо считать.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Мля, какую-то херню развели с очисткой - что, куда, кому, зачем очищать? Всё прекрасно работает всю жизнь: сколько надо вычитать - вычитывается, когда надо очистить - очищается, без всяких delay и прочего онанизма вприсядку. Развели дичь тут.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
// если народ бомбит от мусора в Serial
// то вставьте хидер знак '#'
// и то что до него это и есть тот мусор
//Вот идет Serial канал
'\n','t','r','a','s','h','#','1','2','3','\n','t','r','a','s','h','#','e','r','r','o','r','\n','t','r','a','s','h','#','9','8','0','\n',
// и в результате
// 1 пакет
'1','2','3','\n'
// 2 пакет
'e','r','r','o','r','\n'
// 3 пакет
'9','8','0','\n'
// и даже так все просто

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

vk007 пишет:
И снова Вы о своем. Например, мне надо было принимать строку, но с ограничением длины порядка 50 символов. А это не три, как у изначально вопрошающего. Полсотни букв визуально посчитать уже сложно. Ну не делать же мне, в самом деле, буфер размером 100500 байт, на случай, если кто-то введет 60-100-150... символов, и потом выбирать нужных мне 50. Мне надо считать 50, а от остальных избавиться - т.е. считать в пустоту. Т.е. в любом случае эти данные надо считать.
Если у вас буффер до 50, так и читайте до 49(50 это разумеется 0) и дальше считывайте без записи до знака '\n' . Считали знак, все - пакет принят и на обработку.

vk007
Offline
Зарегистрирован: 16.06.2015

DIYMan пишет:

когда надо очистить - очищается, без всяких delay и прочего онанизма вприсядку. Развели дичь тут.

Ну вот и расскажите, как очистить.

while (Serial.available()) Serial.read(); у меня очищало буфер только частично.

А так толчем только воду в ступе.

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

vk007 пишет:

DIYMan пишет:

когда надо очистить - очищается, без всяких delay и прочего онанизма вприсядку. Развели дичь тут.

Ну вот и расскажите, как очистить.

while (Serial.available()) Serial.read(); у меня очищало буфер только частично.

А так толчем только воду в ступе.


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

Famouspilot
Famouspilot аватар
Offline
Зарегистрирован: 19.01.2016

Из описания данной функции:
Waits for the transmission of outgoing serial data to complete. (Prior to Arduino 1.0, this instead removed any buffered incoming serial data.)

У вас все в порядке с переводом с английского? Без обид.

vk007
Offline
Зарегистрирован: 16.06.2015

Famouspilot пишет:
Уже было сказано - вы очищаете буфер в тот момент, когда ещё передаются какие-то байты, т.е. прямо во время приема. Из-за этого происходит переход программы в какое-то ваше меню, а в это время буфер наполняется байтами, скажем так, "предыдущего" пакета, которые только-только пришли. Не может быть такого, чтобы эта конструкция очищала буфер лишь частично, если все сделано правильно.

Ну конечно во время приема, когда же еще? Ждать до завтра? Особенно, если учесть, что мне надо принять строку размером, сравнимую с размером буфера Serial.

У меня строка принимается так:

char str[52];
if (Serial.available())
{
  delay(20);
  str[Serial.readBytes(str, sizeof(str) - 1)] = 0;
  delay(20);
  while (Serial.available())
  {
    Serial.read();
    delay(5);
  }
// дальше парсим принятую строку

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

Вообще не понимаю, нахрен я влез сюда, работает годами, как мне надо, ну и хрен с ним. Нет, блин, захотелось выяснить, как правильно.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Serial.flush()

void HardwareSerial::flush()
{
  // If we have never written a byte, no need to flush. This special
  // case is needed since there is no way to force the TXC (transmit
  // complete) bit to 1 during initialization
  if (!_written)
    return;

  while (bit_is_set(*_ucsrb, UDRIE0) || bit_is_clear(*_ucsra, TXC0)) {
    if (bit_is_clear(SREG, SREG_I) && bit_is_set(*_ucsrb, UDRIE0))
	// Interrupts are globally disabled, but the DR empty
	// interrupt should be enabled, so poll the DR empty flag to
	// prevent deadlock
	if (bit_is_set(*_ucsra, UDRE0))
	  _tx_udr_empty_irq();
  }
  // If we get here, nothing is queued anymore (DRIE is disabled) and
  // the hardware finished tranmission (TXC is set).
}

Останавливает передачу и очищает буфер передачи. Но не приема! А тема о какой очистке буфера в Serial здесь идет? Передачи или приема?

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

ну дак я уже чучуть плюшевый же.  Прошу простить. 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

vk007 пишет:
Вообще не понимаю, нахрен я влез сюда, работает годами, как мне надо, ну и хрен с ним. Нет, блин, захотелось выяснить, как правильно.
Вот ваши delay и делают задержку для приема следующего байта. Не совсем эффективно, но работает. Можно и сейчас воду из колодца вручную набирать и ведрами носить. Но в местности, где есть электричество предпочитают уже насосами это дело проворачивать.

vk007
Offline
Зарегистрирован: 16.06.2015

qwone пишет:

Вот ваши delay и делают задержку для приема следующего байта.

Ну вот, а иначе не получалось. В который раз повторюсь, while (Serial.available()) Serial.read(); без задержки слишком быстро вычитывала из буфера и слишком быстро Serial.available() становилось 0. Хотя данные комп еще передавал.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Но мне этот подход не подходит. Tем более я стороник короткого loop(), на котором висит многое. Когда данные еще не получены, лучше сделать что-то другое.

vk007
Offline
Зарегистрирован: 16.06.2015

Короткий loop это замечательно. Но делать его коротким, только ради того, чтобы он был коротким?... В данном случае надо именно ждать, ждать и ничего не делать. Ждать, пока пользователь наберет и отправит строку. Принять максимум полсотни символов из этой строки, а если пользователь отправил строку длиннее, то остальное проигнорировать чтобы не висело в буфере и не мешало в дальнейшем.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

vk007 пишет:
Ждать, пока пользователь наберет и отправит строку. Принять максимум полсотни символов из этой строки, а если пользователь отправил строку длиннее, то остальное проигнорировать чтобы не висело в буфере и не мешало в дальнейшем.
Что-то вы не то сказали. Вот возмем Монитор среды. Пользователь набирает строку,в порт не отправляется еще, и нажимает кнопку ОПРАВИТЬ и вся набраная строка идет отправку с заданой скоростью. Но передача идет не мгновенно, а байт по байту. Надо принять всю строку, а потом делать . Теперь вопрос . Зачем останавливать работу всего устройства, что бы ждать окончания пакета.

А если пользователь будет постоянно слать в Serial пакеты.И это начнет блокировать работу всего устройства.  

vk007
Offline
Зарегистрирован: 16.06.2015

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

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

Жесть!

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

vk007 пишет:

DIYMan пишет:

когда надо очистить - очищается, без всяких delay и прочего онанизма вприсядку. Развели дичь тут.

Ну вот и расскажите, как очистить.

while (Serial.available()) Serial.read(); у меня очищало буфер только частично.

А так толчем только воду в ступе.

Шось? Кто-то болеет, по-моему. Приведённый выше код очистить ВСЁ, что есть на МОМЕНТ ВЫЗОВА КОДА в приёмном буфере класса HardwareSerial, за пруфами - в исходники. А вот если МЕЖДУ вызовами этого кода в буфер что-то упадёт - то будет КАЗАТЬСЯ, что очищено лишь частично.

Не несите бред, короче.

vk007
Offline
Зарегистрирован: 16.06.2015

DIYMan пишет:

Приведённый выше код очистить ВСЁ, что есть на МОМЕНТ ВЫЗОВА КОДА в приёмном буфере класса HardwareSerial, за пруфами - в исходники. А вот если МЕЖДУ вызовами этого кода в буфер что-то упадёт - то будет КАЗАТЬСЯ, что очищено лишь частично.

Не несите бред, короче.

Ну и? К чему все это? Я согласен с каждым вашим словом. Но это не отменяет того, что, если отправить длинную строку из компа, то она СРАЗУ ВСЯ "дойдет" до ардуины и я смогу ее всю сразу и целиком вычитать. К сожалению, приняв необходимые 50 байтов, мне приходится ЖДАТЬ, пока комп мне не отдаст всю оставшуюся часть строки, чтобы слить ее в никуда и буфер был чист.

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

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

Завязывайте срач, праздник сегодня. Накатите вон лучше за диодную развязку и мир сразу станет комфортнее.

Famouspilot
Famouspilot аватар
Offline
Зарегистрирован: 19.01.2016

vk007 пишет:

DIYMan пишет:

Приведённый выше код очистить ВСЁ, что есть на МОМЕНТ ВЫЗОВА КОДА в приёмном буфере класса HardwareSerial, за пруфами - в исходники. А вот если МЕЖДУ вызовами этого кода в буфер что-то упадёт - то будет КАЗАТЬСЯ, что очищено лишь частично.

Не несите бред, короче.

Ну и? К чему все это? Я согласен с каждым вашим словом. Но это не отменяет того, что, если отправить длинную строку из компа, то она СРАЗУ ВСЯ "дойдет" до ардуины и я смогу ее всю сразу и целиком вычитать. К сожалению, приняв необходимые 50 байтов, мне приходится ЖДАТЬ, пока комп мне не отдаст всю оставшуюся часть строки, чтобы слить ее в никуда и буфер был чист.

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

Строка не доходит мгновенно. Можно считать последовательность символов , которая заканчивается где-то на середине той строки, которая шлётся в порт. Если поставить в программе ограничение на считывание лишь нуль-терминированной или ей подобной строки, то можно избежать необходимости сепарировать "мусор" от ништяков. И тогда можно быть уверенным, что все, что пришло после символа окончания строки - не мусор с большой долей вероятности.

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

vk007
Offline
Зарегистрирован: 16.06.2015

Вот именно, что строка не доходит мгновенно. Кстати, я опечатался в своем предыдущем сообщении "она СРАЗУ ВСЯ "дойдет" до ардуины и я смогу ее всю сразу и целиком вычитать". Имелось в виду как раз "не дойдет", следующее предложение это, надеюсь, проясняет (редактировал из нескольких фраз и не прочитал итог). Буфер Serial, если не ошибаюсь, 64 байта. И при длинной входящей строке, даже если я подожду и сделаю его очистку, то придут следующие 64 байта строки и снова надо буфер чистить, пока эта строка полностью не передастся.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

vk007 пишет:

 

Ну и? К чему все это? Я согласен с каждым вашим словом. Но это не отменяет того, что, если отправить длинную строку из компа, то она СРАЗУ ВСЯ "дойдет" до ардуины и я смогу ее всю сразу и целиком вычитать. К сожалению, приняв необходимые 50 байтов, мне приходится ЖДАТЬ, пока комп мне не отдаст всю оставшуюся часть строки, чтобы слить ее в никуда и буфер был чист.

К тому, что ваше замечание о том, что код while(Serial.available())Serial.read(); не очищает весь буфер. Я написал, что это бред, и налицо непонимание лично вами основ алгоритмического анализа конкретно вашей задачи, вследствие чего вы начали пенять на зеркало и впихивать delay куда не надо, вместо того, чтобы попытаться разобраться в том, почему ваш алгоритм не работает как надо, вот и всё. 

Вы описали, что вам надо принять 50 байт, остальное - в топку, правильно? Даже в этой постановке задачи существует неполнота, ибо: 1) вам один раз принять 50 байт - и амба? 2) если принять не один раз, то как понимать, что можно принимать снова? Есть ли какой-то стоп-символ, после которого мы понимаем, что можно принимать опять?

Поймите, входящие данные по UART - это ПОТОК. В потоке нет понятия "вот от сих до сих - наши данные" или "вот до сюда - принимаем, потом - поворачиваемся жопой и надуваем щёки". Это просто банальный поток данных, набор байт, если угодно. Как им манипулировать - дело конкретной задачи. 

Ок, даже по вашим некорректным вводным (почему некорректные - описал выше) можно предложить два варианта решения, оба - без delay. Первый вариант - это когда принимаем 50 байт 1 раз, и всё - баиньки:

int readed = 0;

void setup()
{
	Serial.begin(9600);
}

void loop()
{
	while(readed <= 50 && Serial.available())
	{
		char ch = Serial.read();
		readed++;
	}
}

Вычитает 50 байт - и дальше хоть потоп. Второй вариант - вычитываем 50 байт, остальные байты, пока не придёт стоп-символ (юзаем для этого символ перевода строки '\n') - пускаем в небытие:

int readed = 0;

void setup()
{
	Serial.begin(9600);
}

void loop()
{
	while(Serial.available())
	{
		char ch = Serial.read();
		
		if(readed <= 50)
		{
			// тут что-то делаем с символом, например, помещаем во внутренний буфер
			readed++;
		}
		else
		{
			// уже вычитали 50 символов, ждём стоп-символ, как только его встретим - сможем читать в буфер
			if(ch =='\n')
			{
				readed = 0; // всё, говорим, что опять можно читать в буфер
			}
		}
		
	}
}

Всё, ни одного delay, неважно, какими окольными путями данные придут в буфер Serial - вычитаем 50 байт, потом - до стоп-символа будем игнорировать байты, после стоп-символа - опять сможем читать очередные 50 байт.

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