Самый прямой способ назначить байты Serial.read() массиву?

Я пытаюсь отправить предложения NMEA 0183 через LoRa. Каждое определенное сообщение NMEA выглядит как несколько массивов символов (предложений), за которыми следует '\n'. На картинке ниже мы видим одно отчетливое сообщение NMEA:

Это сообщение поступает во входной буфер Arduino каждую 1 секунду с дифференцированными значениями (числами), и его необходимо отправить по LoRa как можно быстрее. Чтобы отправить его через LoRa, мне нужно прочитать все байты во входном буфере, назначить их массиву и отправить как массив, а не один за другим. Я знаю, что Serial.read() читает только один байт, и в этом проблема. Как я могу прочитать все байты и отправить их целиком?

Это мой код:

  if (Serial.available()) {
     c = Serial.read();
     rf95.send((char *)c, sizeof(c));
     rf95.waitPacketSent();

Я использую библиотеку RadioHead, и определение rf.95.send таково: RH_RF95::send (const uint8_t * data, uint8_t len)

c имеет тип char.

, 👍0

Обсуждение

Нет такой вещи, как "все байты... в целом" - последовательный *это* только отдельные байты. Все, что больше этого, является просто оболочкой для чтения отдельных байтов., @Majenko

Что я имею в виду под «целым», это массив, @BrainTrance

@Majenko, для отправки через LoRa это важно? есть ли накладные расходы? рамка/конверт?, @Juraj

Прием сериалов часто является самой медленной частью. Все остальное, что вы делаете, в значительной степени незначительно., @Majenko


3 ответа


Лучший ответ:

0

Мне не хватило завершающего нулевого символа. Это заставило меня читать мусор со всего буфера. Добавление «0» в конце длины буфера является обязательным. Кроме того, как заметил Дэвид Г., функция sizeof() некорректна. необходимо использовать strlen().

,

Просто используйте подсчитанную строку, а не строку с нулевым завершением. Никогда не делайте strlen(), поскольку вы уже знаете длину., @David G.

Длина не фиксирована. Предложений может быть больше или меньше в зависимости от того, какие датчики должны использоваться в каждый конкретный момент, и это может происходить во время выполнения., @BrainTrance

Длина не фиксирована, но длина ИЗВЕСТНА (после прочтения). На самом деле вам нужно знать длину, чтобы вставить ноль. Зачем вставлять нуль в известную длину, а затем использовать strlen, чтобы найти длину?, @David G.

Передающий узел не считывает длину передаваемого массива символов до тех пор, пока эта функция: rf95.send((char *)nmea.getSentence(), strlen(nmea.getSentence())); Узел-получатель знает длину после ее принятия и чтения, но там нет функции strlen()., @BrainTrance

Что ж, вызов, вероятно, должен быть rf95.send(nmea.getSentence(), nmea.getSentenceLength()); Во-первых: не приводить. Если вам кажется, что вам нужно бросить, вы сделали что-то не так. Разберитесь, что. Во-вторых: ваш класс-оболочка nmea должен знать длину данных, которые у него есть, поэтому спросите его напрямую., @David G.


0

Все более сложные последовательные методы чтения основаны на read().

К счастью, в вашем случае есть завершающий символ '\n', так что вы можете реализовать что-то похожее на readBytesUntil самостоятельно, если хотите.

,

Я полагаю, я мог бы перебрать все данные и добавить их в массив и избежать всех символов '\n', кроме последнего?, @BrainTrance


1

@DataFiddler предложил что-то вроде readBytesUntil. На самом деле вы можете просто использовать readBytesUntil. Он возвращается либо по тайм-ауту, либо по достижении указанного терминатора. Он потребляет, но не включает терминатор. Время ожидания по умолчанию равно 1000 миллисекунд и может быть изменено с помощью метода setTimeout().

Одним недостатком является то, что вы не можете различать тайм-аут, полный буфер и достигнутый терминатор. Это не должно быть проблемой, за исключением ошибок последовательной передачи. Если ваши данные поступают со скоростью 4800 бод по стандарту NMEA, вы можете разумно изменить тайм-аут на 5 миллисекунд и продолжать работать.


Одна вещь, которая может вас укусить, — это линия:

 rf95.send((char *)c, sizeof(c));

Приведение первого параметра является ошибкой. Ошибка, которую вы получили, указала, что вы должны написать:

 rf95.send(&c, sizeof(c));

Но sizeof тоже неправильный. Тип возвращаемого значения Serial::read()int, отчасти потому, что существует 257 возможных значений. Если бы вы объявили c как int, его размер был бы равен 2, а не 1.

В любом случае, если вы используете readBytesUntil, вы передаете тот же буфер, который вы передали в rf95.send(), и возвращаете значение из первого в качестве второго параметра второго.

,

Вы правы насчет "sizeof()", нужно использовать strlen(), @BrainTrance

НЕТ. strlen() НЕ подходит. Вы уже знаете количество прочитанных символов. Просто используйте это. В исходном примере был 1 символ, поэтому константа 1 верна. При использовании readBytesUntil это возвращает количество прочитанных байтов, что и следует использовать., @David G.