Самый прямой способ назначить байты 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.
@BrainTrance, 👍0
Обсуждение3 ответа
Лучший ответ:
Мне не хватило завершающего нулевого символа. Это заставило меня читать мусор со всего буфера. Добавление «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.
Все более сложные последовательные методы чтения основаны на read()
.
К счастью, в вашем случае есть завершающий символ '\n'
, так что вы можете реализовать что-то похожее на readBytesUntil
самостоятельно, если хотите.
Я полагаю, я мог бы перебрать все данные и добавить их в массив и избежать всех символов '\n', кроме последнего?, @BrainTrance
@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.
- Как точно получить значения потенциометра через USB-порт?
- Как изменить переменную при нажатии кнопки, подключенной к контакту 2
- Двоичный в десятичный с использованием побитовых операторов
- Акцептант векселей ИКТ
- Как масштабировать растровое изображение (массив uint8_t) в Arduino?
- Как я могу присвоить значение массива символов массиву uint8_t?
- Матричный дисплей с Arduino UNO (ПРОБЛЕМА)
- Обеспечиваем более быстрое и точное обнаружение MindWave Mobile
Нет такой вещи, как "все байты... в целом" - последовательный *это* только отдельные байты. Все, что больше этого, является просто оболочкой для чтения отдельных байтов., @Majenko
Что я имею в виду под «целым», это массив, @BrainTrance
@Majenko, для отправки через LoRa это важно? есть ли накладные расходы? рамка/конверт?, @Juraj
Прием сериалов часто является самой медленной частью. Все остальное, что вы делаете, в значительной степени незначительно., @Majenko