Serial.write печатает пустые значения

У меня есть Adafruit Bluefruit NRF52, подключенный к 9-осному датчику ориентации Adafruit BNO055, но когда я использую Serial.write для отправки данных, последовательный монитор отображает только пустые значения. Полоса прокрутки опускается, так что-то у меня определенно появляется, просто она кажется пустой.

Serial.print работает нормально, но я не могу использовать его для своего приложения, поскольку он использует слишком много памяти.

Я собираю 3 оси абсолютной ориентации плюс 3 оси ускорения (всего 6 плавающих значений) плюс трехзначное число, обозначающее калибровку каждого датчика.

Каждая строка должна выглядеть примерно так

303 68.69   4.19    -2.19   -0.12   0.14    -0.40

Мой код:

void displayCalStatus(void)
{

  uint8_t system, gyro, accel, mag;
  system = gyro = accel = mag = 0;
  bno.getCalibration(&system, &gyro, &accel, &mag);

  /* Display the individual values */
  Serial.write(gyro);
  Serial.write(accel);
  Serial.write(mag);
  Serial.write("\t");
}

void loop()
{
  imu::Vector<3> accel = bno.getVector(Adafruit_BNO055::VECTOR_LINEARACCEL);

  /* Get a new sensor event */
  sensors_event_t event;
  bno.getEvent(&event);

  displayCalStatus();

  /* Display the floating point data */
  Serial.write(event.orientation.x);
  Serial.write("\t");
  Serial.write(event.orientation.y);
  Serial.write("\t");
  Serial.write(event.orientation.z);
  Serial.write("\t");

    /* Display the floating point data for Linear Acceleration */
  Serial.write(accel.x());
  Serial.write("\t");
  Serial.write(accel.y());
  Serial.write("\t");
  Serial.write(accel.z());
  Serial.write("\n");
}

, 👍0

Обсуждение

write передает байт, вы хотите напечатать текст. замените все write на print, @Juraj

Как уже упоминалось, я не могу использовать печать, поскольку она использует слишком много памяти. Я использую Serial для отладки, но отправляю прототип Bleuart. Я записываю движение на высокой скорости и с высокой точностью, поэтому мне нужен интервал соединения минимум до 20 мс, что означает уменьшение размера передачи. Знаете ли вы, есть ли реальные альтернативы печати?, @dookie

Это нехорошее кодирование: system = gyro = Accel = mag = 0; Вместо этого явно установите для каждого из них нулевое значение., @jose can u c

но вы хотите видеть номер в виде текста или нет? если вы напишете (5), вы отправите непечатаемый байт. если вы напечатаете (5), он напечатает «5». imu::Vector занимает гораздо больше места, чем массив C, @Juraj

система = гироскоп = ускорение = маг = 0; это пример, предоставленный Adafruit, а не мой собственный. В любом случае это не решает проблему печати пустых значений., @dookie

Мне не нужен текст, только число с плавающей запятой, но подойдет и целое число., @dookie

вы печатаете вкладки и новую строку. это текст. если вы хотите увидеть номер в Serial Monitor, вы должны распечатать его как текст с помощью print, @Juraj

Хорошо, спасибо за разъяснения. Поскольку в конечном итоге я буду отправлять через bleuart, знаете ли вы, есть ли у меня альтернатива отправлять значения отдельно, без табуляции и текста новой строки?, @dookie

Значения с плавающей запятой, которые вы хотите отправить, имеют длину 4 байта. Serial.write отправляет 1 байт. Чтобы отправить необработанное значение, вы должны отправить каждый байт индивидуально, обычно путем сдвига битов. Вероятно, вам следует отправить какое-то значение «конца пакета», чтобы указать получателю, что вы уже отправили все значения (в случае, если одно из них потеряно или пропущено, получатель может сбросить настройки, чтобы ожидать первое значение и т. д.), @jose can u c

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

Если все значения имеют размер 4 байта и количество значений, отправляемых в каждом раунде, одинаково, *необходимости* в разделителях нет, хотя это может повысить надежность., @jose can u c

Я понимаю. Я не уверен, как это сделать. Можете ли вы привести пример, который я мог бы использовать?, @dookie


1 ответ


1

Проблема 1:

Вы хотите отправлять/отображать на Serial Monitor значения int и float, сгенерированные вашим датчиком, но Serial. print() использует слишком много памяти.

Решение 1:

Оптимизируйте свой эскиз, чтобы использовать меньше памяти.


Проблема 2:

Serial.write() не приводит к отображению значений на Serial Monitor, но что-то отправляется, потому что я вижу активность прокрутки.

>

Решение 2:

Serial.write() отправляет необработанные байты, тогда как Serial.print() преобразует переменную в строку (или серию байтов ASCII) и отправляет эту строку. Например, Serial.write(65) отправляет A в последовательный монитор, поскольку значение ASCII A равно 65; Serial.print(65) отправляет 65 в последовательный монитор, поскольку он преобразует числовое значение 65 в строку, содержащую символ 6 и символ 5 и отправляет эту строку в Serial Monitor.

Последовательный монитор ожидает только данные ASCII. Вы используете Serial Monitor для разработки/отладки, но ваше окончательное приложение не требует ASCII, а только для передачи чисел.

Serial.write() существует в нескольких формах. Одним из них является Serial.write(val), который отправляет один байт (с именем val, типа byte или совместимого). Другой — Serial.write(buf, len), который отправляет серию байтов len, начиная с адреса памяти, на который указывает buf. (Часто это происходит, когда buf представляет собой массив байтов, поэтому buf указывает на первый элемент массива.)

Если вы хотите отправить 4 байта float с помощью Serial.write(), вы можете вызвать:

Serial.write(&(event.orientation.x), sizeof(event.orientation.x);

В качестве альтернативы вы можете использовать битовое смещение для отправки по одному байту 4-байтового числа с плавающей запятой:

Serial.write((byte)((event.orientation.x & 0xFF000000) >> 24);
Serial.write((byte)((event.orientation.x & 0x00FF0000) >> 16);
Serial.write((byte)((event.orientation.x & 0x0000FF00) >>  8);
Serial.write((byte)((event.orientation.x & 0x000000FF)      );

На принимающей стороне вам необходимо восстановить плавающую точку, выполнив обратный процесс.

Но вам нужно отправить несколько 4-байтовых значений в быстро повторяющемся цикле, так что произойдет, если ваш приемник и передатчик рассинхронизируются? Затем вы можете указать значение «флаг», чтобы указать начало последовательности данных, и другой флаг для остановки последовательности данных. Что произойдет, если значение вашего стартового или стопового «флага» на самом деле появится как один из байтов, которые вы отправляете как часть реального байта данных? Затем вам нужно найти способ изменить «реальные» данные, чтобы их не воспринимали как флаг.

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

Я провел быстрый поиск и нашел эту библиотеку Arduino, которая упрощает последовательную связь на основе пакетов:

https://github.com/bakercp/PacketSerial

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

,