Делаю шагающего робота на пульте управления. На роботе mega mini. В пульте pro micro с oled экраном, двумя аналоговыми стиками и энкодером. Связь через hc-12 на стандартных 9200 бод. Планирую отправку пакетов делать раз 100 в секунду (может пореже, не мозговал пока).
Привожу код того, что сейчас работает
pro micro в пульте формирует пакет с состоянием осей аналогового стика, кнопки и подобием crc
struct tCommunicationData {
uint16_t x;
uint16_t y;
bool b;
uint16_t crc;
};
tCommunicationData txData;
void setup () {
Serial.begin(9600);
Serial1.begin(9600);
pinMode(15, INPUT_PULLUP);
}
void loop () {
uint16_t x = constrain(analogRead(A1), 0, 1000);
if (abs(x - 500) < 50) x = 500;
uint16_t y = constrain(analogRead(A0), 0, 1000);
if (abs(y - 500) < 50) y = 500;
bool b = !digitalRead(15);
Serial.println("Joy: x = " + String(x) + "; y = " + String(y) + "; b = " + String(b) + ";");
txData.x = x;
txData.y = y;
txData.b = b;
txData.crc = txData.b ? ~(txData.x ^ txData.y) : (txData.x ^ txData.y);
Serial1.write((byte*)&txData, sizeof(txData));
delay(100); // ясно дело ограничение количества отправок будет не с помощью delay()...
}
mega mini в роботе принимает пакеты, проверяет crc, выводит в usb-serial полученные данные
Так вот, мне не хватает уверенности, что этот код будет исправно работать, не произойдет переполнения данными или зависания какого-то из контроллеров по неведанным мне причинам.
Важное дополнение: в дальнейшем робот также будет передавать в пульт несколько строк текста для вывода на экран - реализация меню, чтобы не прописывать логику и коды в пульте, т.е. не править прошивки каждый раз при изменениях в обоих устройствах. То есть связь будет двусторонней.
если ты хотел обратить внимание на опечатку “9200” вместо “9600” то следовало процитировать именно само число. Но в целом это на тему обсуждения никак существенно не влияет, да?
Вопрос в коде. Скорость передачи 9600, передаваемый с пульта пакет будет в 2.5 раза жирнее, чем сейчас. В обратку пульту полетят строчки, вернее скорее всего одна строка не более 80 символов, чтобы разбить по разделителю на 3-4 строчки и вывести на экран пульта. Может ли при использовании кода из топика случиться какой-либо неизлечимый рассинхрон, из-за которого продолжение получения корректных данных будет невозможно до перезагрузки устройств? Например из-за попытки чтения да завершения процесса получения пакета, или из-за переполнения очереди, т.к. плата в роботе будет занята тригонометрией и генерацией 18-ти PWM?
То есть продолжаем получать из serial, пока не получим кусок между двумя стартовыми байтами, и только тогда забираем данные между ними и парсим. Верно понял ваше предложение? Прием/передачу в таком случае лучше побайтно делать?
А с какой стати ему чего-то дожидаться?
Понимаете, МК делает ровно то, что ему сказал делать программист, и ничего от себя не придумывает.
Ну а способ стандартный: МК должен понять, когда заканчивается пакет.
Не из хрустального шара, а из структуры самого пакета.
Ключевое слово “протокол”.
Я не увидел замечания в #6, в чем именно оно заключается? Последняя цитата относится к Serial0 (посмотреть результат на экране компа, в релизе этого не будет), а передача в прохе по Serial1, прием в меге по Serial2. Этот код вчера пару часов гонялся на столе, сбоев не вызвал, оси и кнопка передавались. Но мега разгружена, т.к. до тех пор пока я не реализую управление, чтобы в нем сделать калибровку крайних точек серво, я не буду проверять позиционирование конечностей, движение по параметрическим кривым 4й степени (хотя в openscad работает, там та же математика), и не смогу приступить к сочинению алгоритма совершения шагов… ну не суть.
Касаемо чтения побайтно, я думал раз размерность sizeof(rxData) передаю в write (пульт) и в readBytes (приемник) то это значение где-то используется во внутренней реализации Serial
Нет. UART физически работает с потоком байтов, ничем и ни как не связаных. Ловит каждый байт. А задача программы из этого потока взять нужные данные.
Про пост #6: 9600 бод это 1200 байт/с “сырых” битов. Если выкинуть старт-стоп биты, то останется меньше 1000 байт/с. Это несколько спорное решение, учитывая желаемые “100 пакетов в секунду”. В теории возможно, но как всегда “никогда не было, и вот опять!”
Мысль понял, в целом там пакет-то будет 8 бит на ось х4шт + 8 бит на все кнопки и направление вращения энкодера сразу + какая-нибудь контрольная сумма.
Вот в обратку строка… есть сомнения. Но в целом я 100 раз в секунду пальцами шевелить не могу, для незаметного в разрезе задачи импутлага думаю и 20 раз / сек достаточно.
Почему именно 9600? Почему бы выще не поставить? Не забывай, МК может “проспать” момент первого байта, и будет тупо ждать когда “весь поезд” проедет, чтобы начать смотреть сначала новый “поезд”.
Поэтому запас “на всякий” должен быть всегда. Тем более в коде до кучи “типа crc”, весьма “тяжёлую” по вычислениям. Я бы от неё отказался. UART и так на борту имеет проверку чётности.
Не знаю, как hc-12 переварит повышение скорости, его разработчики же чем-то руководствовались, выбрав именно такое умолчание. И если честно лень в его настройках ковыряться))) но мысль понял.
P.s. спасибо за беседу по существу
Может быть каким либо древним стандартом? Множество устройств типа электрощётчиков и прочих по умолчанию имеют 9600. Ардуина в примерах тоже всегда 9600, хотя отлично работает на 115200 .