Помогите с отправкой команд по UART
- Войдите на сайт для отправки комментариев
Здравствуйте уважаемые. Надеюсь на вашу помощь ибо я дал себе правило, обращаться сюда на крайний случай. Для меня он настал. И не исключено что я просто где-то подтупливаю.
Есть 3 платы. Первая - пульт управления, передает команды второй. Вторая плата передает команды третей и отчитывается первой.
Все используют программный и аппаратный UART в следующей связке: [DEBUG_PC]-HARDWARE-><-HARDWARE-[1]-SOFTWARE-><-HARDWARE-[2]-SOFTWARE-><-SOFTWARE-[3]
Ранее использовал конкретно аппаратный uart но из-за проблем с отладкой и перекрестным подключением двух устройств, я подключил программный. Но вот кажется сам загнал себя в угол теперь думаю что делать.
Команды управления передаются в следующем виде TX0000XT где TX-XT - метки начала-конца команд. Где 0000 - команда.
Время от времени порт "хавает" первые два, а то и три символа! И я уже устал бороться с этой проблемой. Я собираю с помощью Serial.avaible и read данные из аппаратного буфера. в общую строковую переменную. Из длинной строки вырезаю 8 символов точно зная что там есть команда, а уж потом сверяю есть ли там метки. Если они есть и на месте, запускаю исполнение команды. И так пока строковая переменная - буфер не очиститься "откусыванием" по 8 смволов за каждый цикл. Этим я избавился от слипшихся команд. Но стоит потеряться хоть одному символу в начале - все! идет сдвиг и вся очередь пошла с рельс в речку.
Позже после смены кода (из-за которго поменялась скорость работы устройства) началась другая беда. Отпадали концы команд. Я понял что проверять буфер каждый цикл не есть правильно и сделал проверку в каждую секунду, надеясь что за секунду успеет дойти все что нужно. Обрадовался. Но не надолго. Через время выявил что команды все равно бьются. В основном в начале. Редко в конце.
Я не прошу вас придумывать мне код. Я хочу попросить вас подсказать мне как поступить чтобы избежать потерь на приемо-передаче. Алгоритм, на словах.
Прерывание по UART - пишу сразу не вариант.
До этого пробовал:
Поднять baud до 115200 и опустить до 2400. Установить сигнал приема-передачи чтобы программа остановилась и слушала (типа прерывание). Замедление работы программы. Делать аккумулирующие символы пробелов в начале и конце чтобы не достало до команды. Все-равно режет и еще хуже.
Ни один из способов не подошел.
И serialEvent пробовал. Терялись целые команды.
Свой код приведите, плз. Потому как я ни разу не замечал, чтобы Atmega как-то самопроизвольно чего-то там кусала или откусывала: если байт пришёл в аппаратный UART и успел отработаться в обработчике прерывания - то он не растворяется в небытие. Тем более, что искаропки в ардуино есть буфер ажно на целых 64 байта для UART. Так что если что-то куда-то пропадает - то скорее всего, что проблемы надо искать прежде всего в написанном коде, а уже потом - думать дальше.
В общем, код - в студию, пожалуйста.
Из длинной строки вырезаю 8 символов точно зная что там есть команда, а уж потом сверяю есть ли там метки. Если они есть и на месте, запускаю исполнение команды.
А если нет? Надо начинать выбирать по 1 символу в поиске стартовой метки. Плохо что она совпадает с финишной. Все уже украдено до нас, выбирайте из стандартных https://ru.wikipedia.org/wiki/Управляющие_символы
Но стоит потеряться хоть одному символу в начале - все! идет сдвиг и вся очередь пошла с рельс в речку.
Ну да. Рассинхронизация протокола.
Еще CRC штука полезная. У вас в каналах похоже весело.
Код 400 строк. Поэтому я приведу функцию которая отвечает за то самое чтение. Вызывалась ранее каждый цикл. Теперь каждую секунду с посмощью millis()
void reaqdSerialDatax () { rxCheck = ""; //пре-буфферная переменная string rxData = ""; //переменная с с которой идет выполнение. в нее копируются нормальные команды прошедшие проверку. netDatax = ""; //содержимое для команды netComm = ""; //содержимое для команды netCommdigit = 0; //содержимое для команды delay(50); while (Serial.available()) //if we have something on serial buffer { char buff = Serial.read(); //read that rxCheck += buff; //add to string } while (softSerial.available()) //if we have something on serial buffer { char buff = softSerial.read(); //read that rxCheck += buff; //add to string } if(rxCheck.startsWith("TX") == false && rxCheck.length() != 0){ //bad packet filter - фильтр плохих пакетов aSerial.level(Level::v).println("bad packet - removed").p(rxCheck); rxCheck = ""; delay(50); errorCounter++; //счетчик ошибок } bufferCommL1 += rxCheck; // копируем в общий буфер если прошло проверку. if(bufferCommL1 != "") aSerial.level(Level::vv).p("bufferCommL1 = ").p(bufferCommL1); if(bufferCommL1.length() >= 8){ //меряем длину if(bufferCommL1.endsWith("XT") == true){ bufferCommL2 = bufferCommL1.substring(0, 8); //копируем кусок команды из общего буферного потока bufferCommL1.remove(0, 8); удаляем скопированное if(bufferCommL1.length() < 8 && bufferCommL1.length() != 0){ //если остаток менее 8 и не равен 0 то там остатки которые не подлежат исполнению aSerial.level(Level::v).p(bufferCommL1.length()).pln(bufferCommL1).pln(bufferCommL1).pln("bufferCommL1 has short corrupted command"); bufferCommL1 = ""; rxCheck = ""; errorCounter++; } rxData = bufferCommL2; //присваиваем в исполнительную переменную буфер с целой командой bufferCommL2 = ""; } } compare = 70; if (rxData.startsWith("TX") == true) compare = 0; else if (rxData.startsWith("TX") == false) compare = 69; if (rxData.endsWith("XT") == true) compare = 0; else if (rxData.startsWith("XT") == false) compare = 69; if (compare == 0) //if compare success { // проверили чтометки на местах (ранее использовал substring и compareTo но отказался. Переменная compare осталась как флаг rxCheck = rxData.substring(6); //copy a ner end mark string portion to another variable compare = rxCheck.compareTo("XT"); //cpmpare to if (compare == 0) //if start and end marks are ok { //packet valid, continue... if (rxData.substring(2, 3) == "2") //Read device address { netComm = rxData.substring(3, 5); //current number or command netCommdigit = netComm.toInt(); netCommdigitconv = netCommdigit - 20; netDatax = rxData.substring(5, 6); //this is define command or req if (netCommdigit >= 20 && netCommdigit <= 40) { if (netDatax == "1" || netDatax == "0") { //this is a command SRead[netCommdigitconv] = netDatax.toInt(); if (netDatax == "1") { SwitchHandler(netCommdigitconv, 0); delay(50); SwitchHandler(netCommdigitconv, 1); DevTime[netCommdigitconv] = millis(); zeroTime[netCommdigitconv] = millis(); } if (netDatax == "0") { SwitchHandler(netCommdigitconv, 0); } // дальше идет распознание комманд и их выполнение.Да я вот уже подумал слать по ответу ОК. Тоесть если мк отправил он ждет подтверждения. Если пришло что-то непонятное или error то переслать команду до тех пор пока не прийдет OK. Это пока единственное что пришло мне в голову сегодня.
Проблема в том что если команды сильно будут биться, то канал просто загрузнет в ошибках передачи как и в случае с crc
То не проблема. То обнаружится и полечится. Проблема если команда "поворот налево" исказится и восприймется как "уничтожить цивилизацию" ;))
Ну в принципе подтверждение получения - вариант. Но CRC тоже. В общем добро пожаловать в чарующий мир протоколов )))
Спасибо. И Спасибо что уделили время.
Мысль вот вот пришла. А как вот вы представляете обмен сообщениями с вычислением crc если его тоже передавать. Тем же самым каналом. Ох...
Ну я обычно делаю типа такого: <стартовый байт> <сообщение> <crc>. Если сообщение прерменной длины то <стартовый байт> <длина> <сообщение> <crc включая длину>.
Алгоритм приема так.
1.Если не в синхронизации, например при запуске - прием по байту в ожидании стартового. Полезно изредка чегото отвечать, типа WAIT. Чтоб понимать что на том конце вобще еще шото живо.
2.После появления стартового - прием всего сообщения + crc по фиксированой длинне или прием длины а затем прием всего сообщения + crc .
3. Проверка crc. Если совпало - считаем что теперь протокол в синхронизации и отвечаем OK, иначе отвечаем ERROR_CRC и на п.1
4. Прием стартовый байт+сообщение+crc или для переменной длины стартовый байт+длинна, а затем сообщение+crc. Стартовый байт проверяем сразу, если не совпал - ответить типа ERROR_SYN и п.1
5. на п.3
Если передатчик получил в ответ: ОК - считаем что команда прошла, если ERROR_CRC- не прошла и надо отправить повторно, если ERROR_SYN - все плохо, сразу отправляем пустые команды до получения ОК.
То, что CRC идет по ненадежному каналу - естественно и приемлемо. Возможна конечно ситуация сообщение верное а ошибка в самой CRC. Ну ниче, повторно отправит.
Впринципе хороше если стартовый байт уникален (не встречается больше нигде в канале ), но не обязательно, алгоритм справляется с проблемой
Заинтриговали вы меня с контрольной суммой.
Буду пробовать на свежую голову. Посмотрим сколько коррекций будет на канале за час работы))
Еще раз Спасибо.
В аналогичной ситуации, устав бороться с протоколами обмена на RS232 я попробовал MODBUS. Сейчас перевёл на него все обмены. Даже мелкие. И на RS485. Рекомендую.
А что происходит с остатками в буфере? (Навскидку не понял )) Остатком может быть начало следующей команды, а если его просто отбросить, то эта команда будет битая. По идее надо считывать "целое" число команд, а остаток сохранять в буфере и к нему приплюсовывать следующие считанные байты.
зы. у меня засада была в том, что помехи тупо вырубали USB и обмен с компом останавливался.
Остаток - я уверен на 60% что он битый. Я сделал очистку сразу как подумал об этом методе обработке с буферизацией команд. Вот в чем дело:
Устройство [3] является управляющим, а устройство [2] командующим.
[2] Выполняет свою программу и решает что когда переключить отдавая команды в [3].
Он шлет все попакетно. Отдельно. К примеру TX3231XT (прошло 2 секунды) TX3221XT (прошло пол секунды) TX3251XT (прошло 0,8 секунды) TX3211XT (Прошло 10 секунд) TX3331XT И так далее. Устройсво [2] замеряет время на контактных датчиках и делавет вывод когда и что переключить по получению сигнала а работает все в проверке через for. Поэтому паузы между командами вальируются от 0,5 до 20 секунд.
Теоритически если в буфере осталось TX32 после извлечения из всего потока. То команда никак не дополниться. Позже я подвердил свою теорию. И начиналось нечто вроде
TX3333XTTX22TX3211XT
^^^^
Мне важно не терять пакеты даже если отгрызать символы до следующей метки. Ибо есть спец команда которая если не учтется - начнет рушить все вокруг)))
Попытался переписать алгоритм приема-передачи. После отправки команды ожидается цифра длины полученной строки. Если она не равна восьми то переслать ее заново пока не будет 8. Проблема не заставила себя ждать. Я сделал цикл ожидания ответа в функции отправки команды. И получил бесконечное количество ошибок с переполнением буфера.
Кусок отвечающий за передачу:
void writeSerialDatax(String addr, String comm, String datax) { netOutbuffer = ""; //reset data in buffer before re-assembling new params int tS2 = comm.toInt(); netOutbuffer = "TX" + addr + tS2 + datax + "XT"; //собираем команду softSerial.flush(); softSerial.print(netOutbuffer); while(netOutbuffer.length() != 0) { delay(10); while (Serial.avaible()) //if we have something on serial buffer { char buff = softSerial.read(); //read that rxCheck += buff; //add to string } aSerial.level(Level::v).p("rxCheck - ").pln(rxCheck).p("sentDatax_length - ").pln(rxCheck.length()); if(rxCheck.toInt() == netOutbuffer.length()) netOutbuffer = ""; if(rxCheck.toInt() != netOutbuffer.length()) softSerial.print(netOutbuffer); } }И то что принимает:
while (softSerial.available()) //if we have something on serial buffer { char buff = softSerial.read(); //read that rxControl += buff; //add to string } if (rxControl.length() != 0){ if(rxControl.startsWith("TX") == true && rxControl.endsWith("XT") == true){ rxCheck = rxControl; softSerial.print(rxControl.length());} //if command valid if(rxControl.startsWith("TX") == false || rxControl.endsWith("XT") == false) {softSerial.print(rxControl.length()), aSerial.level(Level::v).p("command receive - ").pln(rxControl), rxControl = "";} //if command corrupted bufferCommL1 += rxCheck;Немного "быдлокодно" но оптимизация чуть позже.
И вот как дальше, думать еще километров 10 пешком)))
Про ModBus посмотрел, почитал. Не в ник что-то. Понял что даные передаются регистрами которые как я понял и есть содержимое. Данные нужно преобразовывать. В общем для меня стало сложно и я пока отложил этот вопрос.
Вычислять crc пока не буду.
Пришла мысль что команды кусает именно while. Мол МК замялся в передаче, сделал передышку, а тот принял за конец передачи. Если бы постоянно снимать данные с uart тогда стало бы что-то ясно. Но пока не придумаю как именно постоянно опрашивать буфер uart не тормозя сильно основную программу.
Ну то есть команды передаются в виде TX0000XT, по одной команде за раз. Минимальный интервал 0.5 сек.
loop видимо крутится быстрее, чем 0.5 сек. Поэтому в loop 1 раз делается проверка буфера порта. Если в буфере что-то есть - то начинается чтение буфера до победного конца, то есть пока не будет считана целиком последовательность TX0000XT.
Поэтому условие должно быть не while (softSerial.available()) , а
if (softSerial.available()>0)
{
while (softSerial.available() < 8 байт)
{ delay 100; } // ждем пока в буфере не накопится 8 байт
Потом считываем из буфера порта 8 байт и проверяем, что последние 2 - это "XT".
}
ну как-то так. А то действительно байты в порт поступают медленнее, чем считываются и оно вываливается из while (softSerial.available()) не дождавшись конца передачи.
diakin, Благодарю за подсказку. Я чего-то не додумался дожидаться накопления команды в буфере.
Я как-то выводил значение Serial.available и там было то 1 то 2. Двойка чаще. такое ощущение что оно так кусочками и переадает. Получается байты разбирались как горячие пирожки и работало все чисто на совпадении времени.
Попробую вернуть на место что было, а то не получается нормально в голове сложить модель с корекцией ошибок. И перед тем как попробовать запихнуть чтение буфера из loop попробую снова потестировать канал чтобы понять что именно грызет пакеты. Программа или железо.
Помниться когда замедлял передатчик [2] то команды шли исправно. Когда я понял что он торопиться сделал буфер. А потом начали откусываться куски.
Т.е. приемник просто недожидался поступления всех байт команды?! Все оказалось так просто )))
Пишите в лопе сразу без циклов и ожиданий
if (softSerial.available()>=8)
{
//считываем из буфера порта 8 байт и запускаем проверки и т.д.
.....
}
// делаем остальные дела
Хрень какая-то.
Погонял тесты. Сначала в отдельной функции через интервал, потом в loop пнапрямую. Получих такое:
Пока в ступоре. Одно ясно - ОНО не успеватет или торопиться.
Попытался сделать такое: откусывать полезные команды стараясь не кусать важное.
void loop() { while (softSerial.available() >= 8) //if we have something on serial buffer { //aSerial.level(Level::vv).p("available before: ").pln(softSerial.available()); char buff = softSerial.read(); //read that rxCheck += buff; //add to string //aSerial.level(Level::vv).p("available after: ").pln(softSerial.available()); } rxData += rxCheck; aSerial.level(Level::vv).p("buffer = ").pln(rxData).p("available out while: ").pln(softSerial.available()); if(rxData.length() > 16 && rxData.endsWith("XT") == true) rxCheck = "'"; if(rxData.startsWith("TX") == true) {netDatax = rxData.substring(0, 8); rxData.remove(0, 8);} Serial.println(netDatax);А получил почемуто
Я где-то явно туплю((
А буфер действительно не успевает. Сделал разгон по времени начиная от 1 секунды и уменьшая по 5 мс.
Подцепил два шнурка на софт и на хард. После интервала менее 100мс данные льються рекой, а на входе [3] ничего нет!
Но когда 1000-600мс данные идут стройным шагом. Дальше есть подозрение что теряються полными пакетами. Добавил счетчик и как-то оно странно себя ведет.
Еще чуток погоняю, до стабильности и я стану чуточку счастливее =)
Так неправильно!
while (softSerial.available() >= 8) //if we have something on serial buffer { char buff = softSerial.read(); //read that rxCheck += buff; //add to string }В этом случае, как только в буфере останется меньше 8 байт - чтение прекращается. Правильно так (как писали выше)
if (softSerial.available()>=8) // если в буфере 8 или больше байт { for (i=0 to 7){ //считываем из буфера порта 8 байт и запускаем проверки и т.д. char buff = softSerial.read(); //read that rxCheck += buff; //add to string } }Чтение прекращается. Ну никудаже ничего не девается. По идее должно просто дописываться. Я когда мониторил софтсериал там поток был без единой ошибки.
Хотя попробую. Я понял суть.
Сегодня я попробовал сделать так:
void loop() { unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; if(softSerial.available() > 0){ while(softSerial.available() < 8){ delay(100); aSerial.level(Level::vv).println("Delayed");} while (softSerial.available() > 8) //if we have something on serial buffer { char buff = softSerial.read(); //read that rxCheck += buff; //add to string } }Интересно то что сообщение delayed - которое мне рассказало бы о том что была задержка при поступлении в буфер, не было отображено. Но все исправно приходило. Однако досконально не проверял так как пакеты однотипные отправлял. И почему-то между командами появился знак апострофа. Откуда - не знаю. Строки выглядели так: TX1234XT'TX1234XT'TX1234XT
Но меня это не смутило, просто вопрос откуда он появился? А увидел я его как добавил здержку при получении чего-то в буфер.
А вот цикл for с числом 7... просто я мониторил softSerial.available и там были (на этот раз) цифры больше 8-ми. Максимум 13. Я предположил что это управляющие символы... хотя разве они учитываются функцией при счете. Не знаю.
Спасибо diakin, попробую твой вариант. Может доведу до ума и буду вспоминать это, как страшненький сон.
По коду из 17 поста. А
rxCheckесли softSerial.available()>=8 не выполнено очищаете? Или оно к rxData добавляется при каждом проходе снова и снова? У вас слишком много буферов, что способствует путанице в логике.Там суть такая, мы считываем все что есть в "аппаратном" буфере в rxCheck а потом, теоритически там должна быть одна команда или кусок команды который потом должен прийти. Все разом они собираються в rxData. А потом проверяется если в rxData у нас собралось более двух команд, мы дополнительно смотрим есть ли метка XT (конечная метка) (вообще надо было сделать >= 16) Если метка есть, значит все целое и мы чистим rxCheck.
Позже проверяем первая команда начинается с начально метки?! Тогда отрезаем наш кусочек в netDatax и исполняем.
Вот перечитываю код, и вижу что запарился. В теории я предполагал что в rxCheck могут быть разные данные, в смысле недопереданные куски, но все собирается в rxData в надежде что там кусочки найдут друг друга и когда там целая команда, есть конечная метка и там длина больше двух команд. Рано или поздно там прийдет XT, то отчистить rxCheck от лишнего чтобы избежать склеивания не по местам как и сдвигов. А уже от теоретически целой строки вырезать целые команды и исполнять.
С буферами я разберусь. Просто сейчас чтобы мне было ясно как все работает в отладке, с создаю уровневые "мертвые переменные" которые мониторю через порт.
У меня две странности, может вы подскажите почему так.
1 - не пойму откуда в порте на приеме появляется знак одиночной кавычки.
У меня на входе такая строка выходит:
'TX1237XTTX1238XT'TX1239XTTX1240XT'TX1241XTTX1242XT'TX1243XTTX1244XT'TX1245XTTX1246XT'
А вот что в начале
Получается эта ЗАкавычка остается вконце. Зачем, почему откуда?
Я-то могу их отфильровать. Но откуда они? передача идет строго по тому что я делал (мониторил) Потерь кстати не заметно.
2 - В мониторе видно когда работает задержка на прием (50мс) но она отрабатывает 13 раз. Я ранее писал что почему-то при передачи 8-ми символьной команды в serial.available () фигурируют числа больше 8-ми. было 10-11-12и13 максимум.
Но у нас 8 символов. Почему 13 раз отрабатывает задержка на прием?!
Алгоритм приема и разбора такой:
void loop() { unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { //важно считывать ежесекундно чтобы основная программа не замедлялась. previousMillis = currentMillis; if(softSerial.available() >= 8){ while(softSerial.available() <= 8){ delay(50); aSerial.level(Level::vv).println("Delayed");} //если что-то есть в буфере, даем время быть принятым. while (softSerial.available()) // именно этот цикл работает лучше цикла for. { char buff = softSerial.read(); //read that rxCheck += buff; //add to string1 } } if(rxCheck.startsWith("'")) rxCheck.remove(0,1); //ну да, фильтр кавычки if(rxCheck.endsWith("'")) rxCheck.remove(8,1); if(rxCheck.length() >= 16 && rxCheck.endsWith("XT") == true) {rxData += rxCheck; rxCheck = "'"; aSerial.level(Level::vv).println("rxCheck - clear");} //Если в буфере больше 16-ти символов то ждем когда там появиться закрывающая метка для копирования данных. if(rxData.startsWith("TX") == true) {netDatax = rxData.substring(0, 8); rxData.remove(0, 8); aSerial.level(Level::vv).pln("rxData - cutOut");} //вырезаем полезную команду на выполнение. if(rxData.length() != 0) aSerial.level(Level::vv).p("rxData in buffer = ").pln(rxData).p("rxCheck - ").pln(rxCheck).p("netDatax - ").pln(netDatax); //конечно же отчитываемся что да как и где. //readSerialDatax(); } }закоменти это
if(currentMillis - previousMillis >= interval) {if(softSerial.available() >= 8){должно происходить максимально часто, т.е. крутиться в лупе постоянно.и это delay(50); - зачем это и кому это нужно?
//если что-то есть в буфере, даем время быть принятым. - если в буфере что-то есть, то нужно максимально быстро принять и обработать потому, что в буфере сериала уже что-то есть и ждёт обработки.
кавычка ' может быть числом 39 http://book.itep.ru/10/ascii.htm
>= 8 почему 8-мь, а не иное число?
8 потому что длина команды 8 символов и нам надо не меньше
Вот почему именно этот символ прорывается так и не ясно.
Но. Убрал посекундную проверку. По вашему совету воступил в общем убрал задержку.
И вернулся к тому с чего начал. Тестированием интервала отправки понял что от 1000 до 50 мс паузы достаточно для быстрой передачи. НО если меньше, идут страшные потери. Так что 50мс - минимальная задержка для успешной передачи.
ВОт только теперь думаю, Этот код в модуле [3] и он только принимает команды. А вот как быть с модулем [2] если он выполняет достаточно сложную программу (считыает входы с мультиплексора, контролирует время и отправляет команды управления) ему помимо этого тоже слушать надо порт от пульта управления [1] успеет ли он?!
А то получается работал над чем-то и пришел к тому с чего начинал. Да, я понял что проблема был в том что МК не успевал хватать.
Получился шум на ровном месте?!
Сейчас сделаю все на рабочий лад, и посмотрим что сейчас будет между всеми тремя платками.
ХА! Я в начале функции чтения и разбора команд вычищал все переменные в том числе и rxCheck думал от глюков избавлюсь, а получается сам себе гемор создал. Вычищать rxCheck надо когда в нем полноценная команда. Отследил монитором с выполнением основной команды:
Видно же что толко на четвертом цикле дописался конец, а когда есть конец XT мы можем очистить переменную переведя содержимое rxCheck в другую надежную строковую переменную где ничего не побито.
Так что 50мс - минимальная задержка для успешной передачи.
слушай, ну ты же тестируешь код не передачи, а приёмки - о какой неуспешной передаче ты постоянно пишешь?
ты не можешь принять, а не передать.
Ну да. С терминами запарился)
Правильнее написать: 50мс - минимальное время интервала между командами для успешного приема. (учитывая размер команды)
ок. тогда измени алгоритм приёма - собирай с сериала по одному символу в строку и по достижению условия:чего там у тебя - длина строки, метка начала нужной тебе инфы, метка конца конфы/строки, что то делай со строкой.
по сути тебе не нужно тормозить код - наоборот, скорость обработки принимаемой инфы является залогом успеха.
посмотри, как здесь сделано #76 - там digiusb, но суть сериала - когда в буфере появляется символ, с ним что-то делается - собирается в строку, а строка, затем сравнивается для выполнения нужной команды, затем строка обнуляется и начинает строиться с начала.
if(Serial.available() < 8 && Serial.available() != 0) while(Serial.available() < 8) delay(50); //Не кидаться! Это условие и не обязательно ставить. while (Serial.available()) //цикл пока что-то есть в аппаратном буфере { char buff = Serial.read(); //Читаем. А что там? rxCheck += buff; //записываем букафку за букафкой)) в rxCheck } if(rxCheck.length() >= 8 && rxCheck.startsWith("TX") == true && rxCheck.endsWith("XT") == true) {bufferCommL1 += rxCheck; rxCheck = "";} //тут должно быть понятно. Три условия. Если в буфере больше 8 символов и метки TX-XT на месте то сливаем целую строку в bufferCommL1, а затем вычищаем rxCheck. В любом случае независимо от приема и длины строки если у нас началось на TX и закончилось XT то с большей долей вероятности у нас все целое, только тогда мы переливаем целую строку в другой уровень обработки и только тогда вычищаем rxCheck while(bufferCommL1.length() != 0){ //и конечно пока не закончиться перечень команд в буфере первого уровня, мы никуда не уйдем. if(bufferCommL1.startsWith("TX") == true) {bufferCommL2 = bufferCommL1.substring(0, 8); bufferCommL1.remove(0, 8);} //Если у нас есть стартовая метка то мы вырезаем из строки одну команду в bufferCommL2 буфер второго уровня. compare = 2; //задаем флаг для определения ошибки if (bufferCommL2.startsWith("TX") == true) compare = 0; else if (bufferCommL2.startsWith("TX") == false) compare = 69; if (bufferCommL2.endsWith("XT") == true) compare = 0; else if (bufferCommL2.endsWith("XT") == false) compare = 69; if(compare != 0){ //ошибка } if (compare == 0) //если проверки пройдены { if (bufferCommL2.substring(2, 3) == "2") //Читаем адрес устройства { //дальше исполнение в подобном роде. Копируем цифры из строки сравниваем их и выполняем команду. Для этого пойдет и If и Switch case. Конечно не забываем что все они String типные, для этго есть замечательная функция stringVariable.toInt();Минимально время между приемом команд - 50мс, дальше программа тупо игнорит входящие данняе, пока не знаю почему.
Все остльные мелочи вроде страннных символов в приеме, я создал себе сам по невнимательности.
----
Благодарю всех кто отозвался и подсказал как стоит сделать.