Приём строки 300 символов
- Войдите на сайт для отправки комментариев
Доброго дня всем.
Через Блютуз мне надо принять длинную строку. Точное количество не известно. 300 символов среднее значение.
Вопросы по прочитанным мной статьям:
1) 300 символов это я так понимаю 300 байт данных + символы '\r'+'\n' получается в памяти у меня должно быть свободным 302 байта?
2) Если не добавлять +'\r'+'\n' то эти символы добавятся автоматически?
3) Буфер у Serial 64 байта, значит мне не принять их посимвольно просто так, придётся принять 64 байта, потом очистить буфер, потом дальше принимать остатки. Но это будет уже в следующем проходе loop()?
4) Вот этот код раньше работал потому что Flush() была очистка буфера. Сейчас как очистить буфер?
char buffer[100]; int i; for(i=0;i<100;i++) { buffer[i]=Serial.Read(); Serial.flush(); if(buffer[i]=='\0') break; }
5) Если увеличить буфер вместо 64 байт сделать 350 байт, в ходе работы скетча, я смогу использовать место в памяти выделенное под буфер? Или эту память никак не использовать кроме общения с устройствами?
Можно ли использовать Serial.print Serial.available без устройств? Просто для обращения к буферной памяти?
Спасибо
Может тебе базовый пример разобрать, прежде чем буферы считать? Черти что несешь
Может тебе базовый пример разобрать, прежде чем буферы считать? Черти что несешь
Как сказал Остап Бендер - "Начал неплохо, не разменивайся по мелочам. Ближе к делу"
Среднее значение никого не волнует от слова совсем. Если Вы собираетесь принимать строку целиком, а только потом обрабатывать (что безграмотно), то Вас интересует максимальное значение. Со среднего Вам толку как с диода усиления.
Не так понимаете. '\r' - один символ. '\n' - тоже.
Не получается. У Вас же 300 - среднее. А ну как 321 придёт?
Нет. Если отправитель их не добавит, то ниоткуда они сами не появятся.
Можно и так, если хотите себе головной и попной боли. Грамотно принимать по одному символу в каждом проходе loop. Это позволит здорово сэкономить на анальгетиках и анальных свечках.
flush не имеет никакого (от слова совсем) отношения к входному буферу. Он очищает выходной тем, что ждёт пока из него всё не отправится. Входной буфер чистится сам по мере вычитывания из него (read освобождает в нём прочитанный байт)
Смотря как именно Вы это сделаете. Если просто тупо увеличите, то нет - не сможете (а увеличить "остро" Вы не сумеете, судя по всему Вами написанному). Ответ - нет, не сможете.
Она всегда только так и используется. available просто возвращает количество непрочитанных байтов в буфере.
Не за что, обращайтесь.
Может тебе базовый пример разобрать, прежде чем буферы считать? Черти что несешь
Как сказал Остап Бендер - "Начал неплохо, не разменивайся по мелочам. Ближе к делу"
Для особо особых выделю жирным: РАЗБЕРИ БАЗОВЫЙ ПРИМЕР.
Ближе к делу
Вот это было предельно близко к делу
Может тебе базовый пример разобрать
Ближе быть не может.
Вы в каждой фразе несетё такой бред, что уши вянут. С таким пониманием у Вас буду возникать проблемы абсолютно на всех ровных местах. У Вас даже не будет каких-то отдельных проблем - весь код будет одной сплошной проблемой.
??
Вы в каждой фразе несетё такой бред, что уши вянут. С таким пониманием у Вас буду возникать проблемы абсолютно на всех ровных местах. У Вас даже не будет каких-то отдельных проблем - весь код будет одной сплошной проблемой.
Понимаю, заступились за товарища.
Но вот странное дело Евгений. Несмотря на то, что в каждой фразе бред, Вы дали ответ на все фразы. Причём почти всё как надо. Единственное - среднее значение я имел виду сегодня 280 завтра 320 символов. В среднем 300. Просто строка бывает разная и если не написать о количестве то можно подумать одна входит в буфер полностью.
А код - да действительно, проблем в нём много. Решаю. И всё равно решу.
Вот интересно, обратили ли на фразу
...Грамотно принимать по одному символу в каждом проходе loop. ...
А код - да действительно, проблем в нём много. Решаю. И всё равно решу.
сильно сомневаюсь. У вас подход неверный. Вместо того чтоб сначала изучить документацию, потом попробовать написать код, самому - и лишь потом спросить что не понятно - вы вместо этого сразу несетесь на фррум задавать несчетное число тупых вопросов, ответы на которые есть в любом пособии для чайников.
Подумайте об этом
Мне сдаётся, что у ТС это всё абстракция без привязки к чему либо.
А Вы не сомневайтесь.
А если не умеете считать до 100 - то поизучайте Пособие для чайников для 1-го класса. Там учат счёту.
На форуме у меня не более 100 вопросов.
Просто строка бывает разная и если не написать о количестве то можно подумать одна входит в буфер полностью.
Наоборот: если не написать о количестве, то следует считать, что строка не только не входит в буфер, но и не помещается в ОЗУ.
Наоборот: если не написать о количестве, то следует считать, что строка не только не входит в буфер, но и не помещается в ОЗУ.
Понял. Учту
А что тебе мешает увеличить буфер в библиотеке Serial (до килобайта можно увеличивать)
Отредактируй файл HardwareSerial.h
А что тебе мешает увеличить буфер в библиотеке Serial (до килобайта можно увеличивать)
Отредактируй файл HardwareSerial.h
Хуже совета сложно дать
А что тебе мешает увеличить буфер в библиотеке Serial (до килобайта можно увеличивать)
Жаль, что до гигабайта нельзя, а то ТС бы точно все проблемы решил
ТС, опишите подробней. Есть ли начало, маркеры, конец сообщения. Скорость уарт, что искать в сообщении...
ТС, опишите подробней. Есть ли начало, маркеры, конец сообщения. Скорость уарт, что искать в сообщении...
Pyotr - спасибо за ответ на вопрос, но ответы уже по теме есть. Я их все плюсанул. Что хотел узнать - всё узнал. Самый развёрнутый попунктно от Евгения. Но и другую полезную информацию узнал от других отвечающих.
Всем отвечающим спасибо.
В одном из проектов увеличивал буфер именно таким образом, работает уже 5 с лишним лет, до сих пор всё супер. Да, память отжирается, но если у автора в обработке не требуется её много, то почему бы и нет, как один из вариантов. Обработка данных налету не всегда нужна, да и асинхронная передача / приём иногда приводит к потере. И ещё, если весь пакет принят в буфер, ты его можешь забрать в любое время, когда тебе удобно, не опасаясь, потери, в момент когда контроллер занят чем то другим.
если весь пакет принят в буфер, ты его можешь забрать в любое время, когда тебе удобно.... в момент когда контроллер занят чем то другим.
интересно, как ты его заберешь из буфера "в момент, когда контроллер занят чем-то другим"? кто его тебе отдаст из буфера, если МК занят?
Идея увеличения приемного буфера -это движение во вредном и неправильном направлении. Увеличение буфера может на время замаскировать очень неприятные ошибки в коде. которые потом будет очень трудно выловить.
А правильный код должен без проблем принимать строчку в 300 символов в стандартный буфер.
Заберёшь после того, как выполнится задача и будет проверено есть ли в буфере данные через if.
А если данные в буфер «как из пулемёта летят»?
А если данные в буфер «как из пулемёта летят»?
Для Ардуино 100000 мкс - весьма внушительный интервал. За это время можно успеть не только принять данные, но еще и отобразить их на экране.
Какой бы не был интервал, данные в HardwareSerial принимаются по прерыванию наивысшего приоритета. Пока весь пакет не зайдет, они будут приниматься в буфер на стеке. Если величины буфера не хватает, они могут теряться, если вовремя их не выбрать. Я реально встретился с такой проблемой в одном из проектов, когда получал ошибки, именно во время не очистив буфер порта.
Это как же надо тормозить что бы не успеть считать буфер? Даже на 115200 интервал между символами 100 мкс. 64 байта буфер это 6.5 мс.
В AVR есть приоритет прерываний?
UPD: слазил в даташит, обновил данные в кэше памяти )) Приоритет есть, но "Vector No. 19 - USART, RX USART Rx complete". Наврядли это наивысший приоритет.
И ещё такой вариант может быть (размер буфера не важен), если есть сеть слейвов, например, сидящих на RS-485. Каждый занимается своей задачей, и проверяет буфер ну скажем раз в минуту. При этом данные в каждый контроллер валятся на стеке. Выходя из своей задачи необходимо обязательно выбрать все данные из буфера, иначе точно будете читать ошибочные данные (особенно, если пакеты будут разной длинны).
данные в HardwareSerial принимаются по прерыванию наивысшего приоритета.
...внимательно смотрю.
Пока весь пакет не зайдет, они будут приниматься в буфер на стеке.
...смотрю озадаченно ;)))
----------------------
Узнал много нового. Зря я жду следующего "Герметикона" от Вадима Панова, тут - интереснее! ;))
SAB, не хочу спорить, может в каких-то случаях вы и правы. но для этой ветки. согласен с rkit - ваш совет вредный.
ТС надо ориентироваться на обработку по одному символу, как советовал Евгений, а не надеятся что огромный буфер Сериал решит все его проблемы.
Евгений конечно авторитет, но почему грамотно именно по одному символу за цикл loop? Чем плохо считывать в цикле loop все имеющиеся в буфере символы?
Евгений конечно авторитет, но почему грамотно именно по одному символу за цикл loop? Чем плохо считывать в цикле loop все имеющиеся в буфере символы?
При правильном написании программы, имхо, у вас и не должно никогда скапливаться в буфере более одного-двух символов - иначе это означало бы, что у вас в loop() много медленных операций и программа. скорее всего, спроектирована неверно.
Но это не так и важно. За Евгения не скажу, а по мне так суть вовсе не в том, сколько символов считывать. Главный смысл - обрабатывать буфер при каждом проходе loop(), а не ждать, пока вся строка целиком залезет в буфер. Нужно читать символы по мере прихода, а по одному символу или сраху по 10 - это уже мелочи
Иногда, удобнее уходить из лупа на подпрограммы. И в некоторых задачах приоритет serial порта стоит на втором или на третьем месте. А пакеты то всё равно принимаются в буфер по прерыванию. И когда идёт возврат в луп, вот тут то и потребуется освобождения буфера, и уж потом чтения команды от мастера для конкретного контроллера. А рассудить правильно ли написана программа, может только время бесперебойной и правильной работы устройства.
SAB, с учетом того что ТС хочет научится работать с Сериал (насколько я понял :) - правильнее заставить его сделать сразу правильно, а не подсовывать ему костыль в виде увеличенного буфера
имхо
Евгений конечно авторитет, но почему грамотно именно по одному символу за цикл loop? Чем плохо считывать в цикле loop все имеющиеся в буфере символы?
грамотный код для контроллера должен содержать короткий по времени и (по возможности) всегда одинаковый по времени проход loop(). При вычитывании всего буфера, время в лупе будет зависеть от количества символов. Что составит неудобство при распределении времени кода.
Не может такого быть, чтобы МК "занимался своими делами" и проверял прием по УАРТ раз в минуту, это бред ;)).
При отсутствии вытесняющей мультизадачности, код для простого МК выглядит как набор объектов (не обязательно в стиле ООП ;)) ), у каждого из которых есть шаг, вызываемый в лупе по очереди. Тогда каждому объекту гарантированно достанется время процессора на выполнение. Все ожидания производятся уже ВНУТРИ объекта. Одинаковое время шагов - важная вещь для предсказуемости кода. Представь, что один из объектов обслуживает клавиатуру, а еще один - моргает LED лентой? Если третий объект "ЗАХВАТИТ ВЛАСТЬ", то и лента моргать перестанет и кнопку не нажать. ;))
Есть исключения - когда, по сути кода, следует ожидать ТОЧНОГО момента внешнего события. В этом случае останавливается вообще вся деятельность, в том числе и обслуживание ВСЕХ, не относящихся к ожиданию прерываний (иногда даже Таймера0).
Таким образом получаем, что прием и накопление данных в буфере УАРТ без немедленной обработки - просто безграмотность. В случае нормальной работы, без отслеживания точных моментов внешних событий (чаще всего всякие отражения, например УЗ или подобное) - нет необходимости в столь странном стиле, а в случае ожидания внешнего события - прием по УАРТ все равно будет запрещен, как мешающий.
Объяснение понятно?
Нужно добавить о возможной трате времени на вычислительные задачи, а то предвижу срач ;))). МК, способный на решение вычислительных задач (поиск, сортировка, обработка сигналов) может иметь части кода, занимающие время и неудобные для разбивки на "шаги", описанный в посте выше.
Дело в том, что такие МК - другая "лига". Они либо уже имеют ОС с вытесняющей мультизадачностью (как ESP32), или очень развитую периферию с приоритетами прерываний, как STM32. На AVR, а речь шла о них, fft считают не часто, а если и считают, то на маленьких размерах данных и укладывая вычислительную задачу в 1-2 милисекунды, что не противоречит "автоматной" схеме кода.
AVR - типично автоматный контроллер, предназначенный для разной сложности "ногодрыга" и обработки внешних событий. Объем ОЗУ и ядро без деления у него не позволяет решать вычислительные задачи. Поэтому код должен быть - автоматный, с единственным циклом - loop(), без ухода в решение затратных по времени задач, с почти постоянным временем прохода loop(). Если задача вынуждает к другому построению кода - это говорит о неправильном выборе контроллера.
Очень хорошая проверка правильности архитектуры для новичка: если ты в объекте своего кода не можешь вычленить рабочий шаг с коротким и постоянным временем исполнения, то ты неверно понимаешь задачу.
Пример: Даллас 18B20. Правильно в шаге проверять давно ли запрошено преобразование и если прошло более 750 мс, то прочитать значение температуры и выслать новый запрос на преобразование. До этого отдавать старое значение.
Пример: клавиатурная матрица. Правильно считывать не сразу всю матрицу, а по одной строке в шаге.
Пример: плавное изменение яркости чего-то. Правильно в шаге менять яркость по заранее рассчитанному графику.
Пример: задержка включения прибора после события. Правильно установить таймер и в шаге проверять истечение времени.
--- И так далее.
Да почему же вы все думаете, что уйдя из лупа в подпрограмму, нельзя в ней опрашивать клавиатуру, моргать диодиком, и т.д. К тому же может быть вложено несколько подпрограмм одна в другую. Стек нам это позволяет делать. Просто проверка возврата в луп должна быть в каждом из вложений вот и всё. Может быть такой способ в среде программистов считается моветоном, но он работает. Я ещё раз повторюсь, что есть задачи, где обработка данных с порта, является вторичной (корректирующей ) задачей. И может происходить раз в минуту. И вообще, когда мне понадобится что то поменять, я буду спрашивать у мастера (типа, что то поменялось в этом мире, пока я трудился выполняя предыдущую задачу:))) Прошу прощения за уход от темы топикстартера.
К тому же может быть вложено несколько подпрограмм одна в другую.
Ардуино - хобби, как привык, так и пиши. Просто помни, что так делать - не надо. Можно есть стейк палочками, а суши вилкой? Можно, но так делать - не надо! ;)))
Прекращаем, а то срач на пустом месте родится.
Согласен
Да почему же вы все думаете, что уйдя из лупа в подпрограмму, нельзя в ней опрашивать клавиатуру, моргать диодиком, и т.д. К тому же может быть вложено несколько подпрограмм одна в другую...
Можно конечно, но зачем? Loop уже подпрограмма, которую нам предоставили разработчики ардуино как раз для циклического вызова. Зачем уходить ещё на уровень вниз? Так никакого стека не хватит. Влад все правильно обсказал. Да и последнее - что это хобби - пиши как нравиться полностью поддерживаю. Вот только не надо свои не правильные наработки нести в массы.
Потому и говорится об одном символе - считал, тут же передал его автомату разбора. При следующем проходе опять считал и тут же передал автомату разбора. При таком походе полученные данные вообще нигде не хранятся. Правда, в классе сериал для таких вещей не хватает очень важного метода (я у себя добавил) - аналога стандартной С-шной функции ungetc. Без неё можно, но те, кто всю жизнь писал лексические разборщики на Си, к ней настолько привыкли, что без неё очень неудобно.
И что с ними делать? Сложить в ещё один буфер?
Я обрабатываю сразу весь буфер скорее потому, что в подсознании лежит "Не откладывай на завтра то, что можешь сделать сегодня".
Объяснения wdrakula мне понятны. Но из тех задач с какими я сталкивался мне проще смоделировать пример, где побайтное чтение в loop приведет к большим ограничениям к коду, чем смоделировать пример, с критичным влиянием времени обработки за счет возможно разного количества обрабатываемых символов.
Впрочем, я же Вам не запрещаю, обрабатывайте как Вам нравится.
А я в класс сериал добавил метод readLastByte() - возвращает последний байт приемного буфера, ничего не удаляя из него.
Мне удобно например ловить ответ на АТ команду, которая заканчивается в случае успеха OK\r\n
Если в буфере больше 3 байт и последний \n, значит ответ получен полностью и можно делать что-то.
Да, ладно! И не только на один уровень вниз, но и на несколько, сколько душа пожелает.) И разработчики здесь вовсе не причём. loop() - это упрощение/наглядность для домохозяек, только и всего. Вот как раз эти домохозяйки и размещают 1000 строк кода в лупе. Ужос(.
Да ладно! А кто в main loop вызывает? Папа римский? Или всё же разработчики ардуино вписали? Может и для домохозяек. Но это уже на совести пишущего.
Да ладно! А кто в main loop вызывает? Папа римский? Или всё же разработчики ардуино вписали? Может и для домохозяек. Но это уже на совести пишущего.
Не спорь, дорогой! Людям нравится исполнять "танго на граблях", кто может запретить? ;)) Это же хобби.
Без обрамления Ардуино, пишут просто бесконечный цикл в main(). Разработчики ничего нового не сочиняли.
Программисты микроконтроллеров делятся на тех кто понимает термин "автоматное программирование" и остальных.
"Мы по разному видим мир"(С).
Я даже в мелких ПИКах, где всего лишь 8-уровневый стек, по возможности использую setup() и loop().
"Мы по разному видим мир"(С).
Я даже в мелких ПИКах, где всего лишь 8-уровневый стек, по возможности использую setup() и loop().
И чем это отличается от сказанного? Именно это я и написал - setup и loop - не прихоть разработчиков ардуино, а естественная архитектура.
Ровно как и высказывание о "1000 строчках в лупе" - не архитектурная особенность, а неумение программировать. Это стиль письма, а не структура кода. Не надо писать "1000 строк", но и не надо делать функциональные подпрограммы в автоматном коде. Выдели часть строк в отдельный блок чисто "литературно", для читаемости, кто мешает?
Значит я не понял витиеватость твоих высказываний, звиняй.) Именно структурность и читаемость, а не такты и размер. Естественно, в силу обстоятельств, бывают исключения.