Помогите в очередной раз разобрать строку
- Войдите на сайт для отправки комментариев
Ср, 15/02/2017 - 17:04
Прошу подсказать как разобрать строоку. Тем по этой теме на форуме много, разобратся не могу.
Две ардуины подключены по сериал. Одна собирает сигналы с датчиков и отправляет их на вторую. Вторая должна принять и обновить переменные на те что пришли.
Вот что отправляет первая ардуина с датчиками
$&a29.72&b20.44&c748.35&d26.20# // $ символ начала передачи //# символ окончания передачи //& символ для распознавания идентификатора // a b c d идентификаторы // цифры значения с датчиков
Вообще строка передачи может быть любого другого формата.
Нужно условие проверки начала и конца пакета по символам $ и #
Если они есть то разбираем строку.
Если после '&' символ 'a' то цифры которые идут после нее до следующего '&' это значение.
Значение из строки перевести в float и присвоить переменной a.
Сделал через субстринг, но это ненадежно т.к длины значений могут быть разные.
Ну, покажите, как сделал-то?
И поподробнее. Количество переменных всегда одинаковое? Или может быть разным? Имена всегд одни и тже и в том же порядке? Поподробнее, в общем.
Переменных количество разное.
Имена произвольные из одной буквы. a b c d e f g.... +- около 10шт, без повторения.
найти символы и их адрес можно по strstr. разложить по разделителю strtok.
Нет, ну на фиксированную длиину забиваться нельзя, я правильно понял?
Как делать зависит от задачи опять же (подробности Вы от нас скрываете).
Например, строка приходит целиком и её нужно обрабатывать только после того, как придёт заключительный символ #? Или сразу по поступлении $ нужно обрабатывать числа по мере поступления, не дожидаясь конца строки?
Если первое, то можно просто разбить строку на лексемы (например, функцией strtok) (можно и String задействовать, если память девать некуда, конечно). На лексемы разбивать по символу &. Ну. а каждую лексему уже легко обработать, т.к. про неё известно, что там односимвольный код и число.
Кстати. а что с этими названиями и числами делать-то надо?
Фиксированной длины не получится.
Не знаю как еще подробней расписать.
Все равно по сути как будет лишь бы было надежно))
Для надежносости хотелось бы ввести начало и конец пакета$#
Пакет может выглядеть как угодно с любыми разделителями и т.п
Надо сначало получить потом разобрать т.е после#
Вообще смысл в чем. Делаю контроллер типа для управления климатом, приходится разбросать все на два контроллера, в одном датчики, во втором алгоритм и управление. Надо чтоб во втором были актуальные значения датчиков из первого контроллера.
Пакет может выглядеть как угодно с любыми разделителями и т.п
Не понял, что значит "с любыми разделителями"? Вы же говорили, что разделитель всегда &. Если там "любой разделитель", то как Вы его выделять собираетесь.
Думаю, тут Вы погорячились и разделитель не любой вовсе.
Надо сначало получить потом разобрать т.е после#
Получать умеете? Если умееете, получайте, а дальше разбирайте strtok'ом. Пример есть по той ссылке, что я давал.
В чём именно у Вас проблема?
Про разделитель - он может быть любой в том плане что какой поставим тот и будет.
strtok разобьет строку на части получится что то вроде
&a29.72
&b20.44
&c748.35
&d26.20
как дальше это разбить не понимаю
Да в моем примере идет присваивание значения переменной BME_T Это работает.
Но в случае с субстрингом длина должна быть фиксирована.
Надо функцию которая способна находить по критерию т.е ищем в строке символ нужный все что до следующего символа это значение переменной(цифры в формате строки) после их перевожу в float и ставлю как значение.
мне такой вариант не подходит т.к тут жесткая привязка к позициям данных в строке.
Так а дальше бить не надо. Каждая из этих частей имеет фиксированный формат, а именно
str + 0 - символ &
str + 1 - имя переменной
str + 2 - начало числа.
Поэтому, так и делаете. Допустим, такой кусочек у Вас сидит в переменной str (тип у неё char *, разумеется). Тогда, Вы тупо пишете
И всё.
Как получить эту str типа char * при помощи strtok там в примере показано.
Если остались вопросы - не стесняйтесь.
спасибо, попробую переварить.
чет запутался окончательно)
пример начинается с обьвления строки с извесным содержимым
у меня то его нет.
делаю так) но компилятор говорит что что то тут не так)
Так я ж Вас спрашивал, "Вы умеете получать строку из сериала?". Её прочитать сначала надо.
Ну, я могу помочь, но хоть скажите ограничение на её длину. Только не надо, что "может быть любой" - у Вас же не любое количество датчиков. Итак, какова максимальная длина строки, которая будет приходить из Сериала?
на данный момент максимально 69 символов
$&a31.52&b19.85&c753.45&d27.40&e19.50&f22.10&g22.31&h1671.62&i32.50#
судя по всему нужно разбить на две части т.е по 35 символов максимум.
Хорошо, я завтра вечером (после работы) напишу для Вас пример (не бойтесь - не полный, Вам оставлю что-нибудь вкусное для самостоятельной работы -:))) сейчас не могу, простите. Потерпит до завтра, я надеюсь?
Конечно))) ни кто не умрет) Спасибо.
Максимальная длина сообщения которая может придти в контроллер 62 символа, дальше обрезает начало сообщения. Наверное если буфер увеличить то и больше зайдет, но мне не это не надо, два раза отправит, где то это даже лучше.
Если Вы можете и на слейве и на мастере менять протокол, то в данном случае Вы страдаете херней. Вам ASCII ваще тут нахрен не надо, нахера передавать число с пл. запятой в виде аски?
наверное для удобства, много выиграю от передачи в ином формате?
какого нафиг удобства? вы с датчиков принимаете в бинарном виде? да. так вот в том виде и передавайте дальше, а уже на мастере переводите в удобочитаемый вид. У Вас вот эта хрень &a27.72 занимает 7 байт. в семь байт можно уложить информацию минимум с трех датчиков. Зачем между машинами обмениваться человеческой информацией, если нет такой потребности?
Вроде понял о чем имете ввиду. Сейчас разберусь с тем что более менее понятно.
Коллега прав.
Вам нужен пример разбора строки?
Да прав... я чемпион по обновлению этой страницы сегодня))
Так пример со строкой больше не актуален? Мне-то написать нетрудно, но если не нужно, так зачем? Ответьте.
Не правильно выразился. Мне очень нужен ваш пример и я его целый день жду)
Совет коллеги принял и уверен что так было бы правильно, но если с "человеческим языком" пока справится не могу, то в цифрах точно потону) По этому, пока мне надо сделать, именно так как я планировал и понять как это делается.
Ага, ну сейчас покурю и займусь.
Ну вот как-то так, если нигде ничего не ляпнул.
Любые символы между пакетами она игнорирует. Попробуйте, например,
qwerty$&a123.32&b0.12&c3.14#lalalalalal$&a0.1&b0.2&c999#zxcv
В этой строке два пакета, а перед ними, после них и между ними - грязь. Вроде нормально она выделяет пакеты и распаковывает.
Отправляю и получаю. Супер.
Разбираюсь дальше.
бывает так
теряет символы почему то
Ну, задания контролировать формат не было, предполагалось, что строки программа формирует. тут просто ошибка в формате строки. Смотрите, предпоследний слот: d27.4e19.10 Это разве допустимо?
теряет символы почему то
Ничего не теряет. Это Вы потеряли имя переменной в третьем слоте справа. Он у Вас выглядит: &.50 И где тут имя переменной?
Если надо контролировать формат и отлавливать такие ошибки, так надо говорить об этом при постановке задачи.
Или Вы случайно ошиблись при вводе?
Т.е. при правильных строках она работает правильно.
так точно если все правильно то все разбирает отлично
щас надо посидеть потлавливать почему не доходит.
привык что обычно если не влазит теряется начало.
сейчас видно что если убрать дну переменную то все приходит целое.
Все нормально, наблюдаю.
Подключил вторую отправку. Тоже все норм, есть небольшие потери, но у меня не космический корабль.
Надо конечно глянуть от куда они идут, или не доходят или не успевают улетать в буфер.
Большое человеческое спасибо.
С вами можно будет как то связаться по мимо форума? Если не сложно черканите мне на почту mmc1@bk.ru
Оставлю на пару дней чтоб логи записать.
Проект будет интересный 24 контролера STM32, 12 шт ESP12, одна малина пи3 и просто целая гора датчиков.
Дописал присваивание вот так.
Если нужно контролировать пришедшие пакеты, это тоже делается, просто Вы не просили. Можно доделать. Другими способами не надо, в реале меня нет (в смысле - в реале живёт другой человек, а такой, какой я здесь, толь здесь и существует) просто при случае апните тему, она у меня и вылезет в списке отслеживания.
Понял.
Наверное целостность можно будет проверять когда будет точно известен состав пакетов?
Ну, должны быть чёткие правила. Типа в том месте обязательно буква, а в этом цифра или десятичная точка. Тогда можно это проверять и при любом отклонении, выдавать кокое-нибудь сообщение и пупо игнорировать всё до начала следующего пакета.
Кстати, Вы уверены, что разбор надо начинать, когда всё пришло? Если разбирать по мере прихода, то можно отказаться от того 64-байтного буфера - он тогда не нужен.
Если нужно контролировать пришедшие пакеты, это тоже делается, просто Вы не просили. Можно доделать. Другими способами не надо, в реале меня нет (в смысле - в реале живёт другой человек, а такой, какой я здесь, толь здесь и существует) просто при случае апните тему, она у меня и вылезет в списке отслеживания.
" ...не скажу, что я идеальный, я живой, я просто реальный..."
Давайте попробуем без буфера. Если не затруднит.
Ну, давайте сначала определимся с окончательным форматом и с необходимостью его проверки. Кстати, тогда и признаки начала/конконца пакета тоже не нужны - они терют информативность. Сичтать, что одно переданное значение и есть пакет и разбирать их по мере прибытия.
Только, сдаётся мне, что фигнёй маемся. Если __Alexander прав и Вы на одной ардуине получаете числа, а на другой они Вам нужны, то преобразование их в символьный вид, а потом обратно сродни мастурбации.
Я правильно понимаю что нужно перейти в этом случае на Serial.write ? Не совсем понимаю... Serial.write не передаст float, надо множить на 100 потом делить то что придет. Верно?
Serial.write передаст всё, что угодно. Просто передайте ему адрес начала Вашего float и количество байтов.
Вот и все дела. Передаст за милую душу.
Принимать также
ух ты..
Вот это можно более подробно
(
byte
*) & value,
Можно. По шагам:
value - кусок памяти в котором лежит Ваше плавающее число
& value - адрес этого куска памяти (т.е. номер байта с которого начинается Ваше число).
Собственно по сути это всё, но формально функция readBytes ожидает не адреса плавающего числа, а адреса массива байтов. Технически это одно и тоже - адрес он и есть адрес - это просто номер байта в памяти, считая с нуля, но синтаксис требует, чтобы мы передавали readBytes именно адрес массива байтов. Для этого мы используем операция преобразования типа для адреса
(byte *) & value
эта операция не делает вообще ничего с адресом - никак его не изменяет, просто говорит компилятору, чтобы он счиал &value не адресом плавающего числа, а адресом массива байтов (повторяю, это важно - никаких физических манипуляций с адресом не делается - от остаётся точно таким же).
Т.е. обобщая. Выражение (byte *) & value означает "адрес в памяти начального байта плавающего числа value").
Значит, когда мы пишем
Serial
.write((
byte
*) & value,
sizeof
(value));
мы передаём write адрес начала и длину в байтах того, что мы хотим, чтобы она передала.
Понадобится идентификатор передачи, его отправляем отдельно, перед сообщением или все одной командой можно? или тут не нужен ни какой идентификатор?
Или можно одновременно передать пакет переменных не вызывая каждый раз
Serial
.write()
Не знаю, Вам же всё равно нужно имя переменной передавать, так что думаю, лучше сделать. Признак начала, имя, число. Если не делать признака начала, то за имя можно приянять всё, что угодно, что там может прилететь.
Поэтому и пишут протоколы обмена с железяками, а они в текстовом виде посылают, от чего уходили к тому и пришли или формировать дамп переменных, к примеру 60 бит, по структуре и загоняем в одну переменную, берем адрес по первому в блоке и по нашей структуре данных вытаскиваем в переменные
удобная штука мультипроцессорный режим. выставил адрес и всё, пока не свой адрес - всё игнорится, когда пришел свой адрес - сдедующие байты полезная информация.
удобная штука мультипроцессорный режим. выставил адрес и всё, пока не свой адрес - всё игнорится, когда пришел свой адрес - сдедующие байты полезная информация.
Это как?
ну в разделе про уарт можно почитать.
или вот
http://we.easyelectronics.ru/AVR/vremya-govorit-s-kamnyami-ili-usart-mul...
Работает на камнях, где есть полноценный USART (это меги)
Не заморачиваться, да свой протокол написать, заготовку Евгений уже дал
а на ардуино не мега?
и чем заморачиваться? пяьтю строчками кода? зато протокола не надо.
яб в принципе модбас бы использовал, контроллеры уже подключены по RS485
но я не смог найти библиотеку модбас под stm32duino, а своих мозгов нет.
Евгений привет.
Давай попробуем продолжить.
Предстоит отправлять в таком формате:
Признак начала, имя переменной, число.
Признак начала и имя переменной это символы, пусть будет так же.
Признак начала & и имена переменных анг алфавит по одной букве.
Разбирать надо будет сразу.
Отправка получается типа того
верно?
Ну, можно и так.
Ну, а приём тоже проще некуда. Вы бы могли и сами по образцу, что был.
Первым делом надо понимать, что любой разборщик - конечный автомат. Вот и давайте выделять его состояния. Читайте внимательно и Вы всё поймёте.
1. Ждёт символа '&' при этом игнорирует все остальные символы. Получив символ '&' переходит в состояние 2
2. Ждёт имени переменной, получив байт проверяется яляется ли он латинской буквой. Если да, переходит в состояние 3, иначе в состояние 1
3. Ждёт начала числа, получив что-то, пытается прочитать как число и после этого выдаёт результат (имя - число) и переходит в состояние 1.
Изначально автомат находится в состоянии 1.
Вот и всё, осталось это написать. Но тут всё просто - пишем буквально как есть, прямо по этим пунктам.
Сравните текст с написанными выше правилами - всё переписано 1 к 1. Текст коротенький - комментариев больше.
Возможно, я в чём-то ошибся, проверить сейчас не на чем. Но идейно всё правильно, а если будут мелкие ошибки - пишите, посмотрим, поправим.