Heltec WiFi LoRa 32 (V3) - кодирует/декодирует пакеты в двоичный код (сообщение становится короче)
Я использую платы Heltec WiFi LoRa32 (ESP32-S3 + SX1262).
Не могли бы вы мне помочь, как закодировать данные, например, с датчика температуры и влажности, в двоичную или шестнадцатеричную форму, чтобы сократить длину пакета LoRa? Похоже на то, что делает LoRaWAN.
Например, у меня есть два значения:
float temperature = 21.56;
float humidity = 76.21;
Я использую официальную библиотеку Heltec для радио LoRa, я передаю данные только через LoRa (не LoRaWAN), поэтому необходимо заставить ее работать с библиотечной функцией Radio.Send()
.
Radio.Send( (uint8_t *)txpacket, strlen(txpacket) ); //отправляем пакет
Я нашел этот пример и это руководство.
Я в этом запутался, поэтому был бы признателен за часть примера кода, совместимого с библиотекой Heltec, для кодирования и декодирования, совместимых с функциями библиотеки Heltec.
@iotdeveloper, 👍2
Обсуждение2 ответа
Радио.Отправить((uint8_t *)txpacket, strlen(txpacket));
Отмечено, что strlen(txpacket)
применимо только если txpacket
является строкой. Поскольку температура является значением с плавающей точкой, она должна быть sizeof(temperature)
(см. дальнейшее объяснение ниже).
Я думаю, что существует недопонимание, что это отправляет «более короткие» данные, потому что вы видели uint8_t
, но это не так. Данные с плавающей точкой одинарной точности хранятся как 4-байтовые данные в соответствии с форматом IEEE754. Функция RadioSend((uint8_t *) temperature, sizeof(temperature))
просто преобразует значение с плавающей точкой в указатель байта (т. е. uint8_t), который указывает на начало temperature
в памяти, чтобы можно было отправлять данные побайтно, sizeof(temperature)
эквивалентен sizeof(float)
, поэтому он равен 4. Данные, проходящие через радиопередачу, по-прежнему представляют собой 4-байтовое значение с плавающей точкой.
Чтобы отправить температуру и влажность, вам просто нужно отправить данные о температуре и влажности следующим образом:
float temperature = 21.56;
float humidity = 76.21;
RadioSend((uint8_t *) temperature, sizeof(temperature));
RadioSend((uint8_t *) humidity, sizeof(humidity));
Однако, как указал @jsotola, если вы хотите, есть способ сократить объем отправляемых данных с 4-байтового числа с плавающей точкой до 2-байтового int16_t
путем преобразования float
в int16_t
путем умножения значения с плавающей точкой на 100. Преобразованные данные имеют длину всего 2 байта как int16_t
без потери точности числа с плавающей точкой (точность которого составляет 2 десятичных знака).
float temperature = 21.56;
float humidity = 76.21;
int16_t temperature_in_integer = (int16_t) temperature * 100; // целое число 2156
int16_t humidity_in_integer = (int16_t) humidity * 100; // целое число 7621
// отправить по 2 байта каждый
RadioSend((uint8_t *) temperature_in_integer, sizeof(temperature_in_integer));
RadioSend((uint8_t *) humidity_in_integer, sizeof(humidity_in_integer));
На принимающей стороне полученные данные необходимо разделить на 100, чтобы получить фактическое значение температуры и влажности.
Если это вас немного сбивает с толку, я бы посоветовал вам взять книгу по C или C++ и изучить основы типов данных, приведения данных и указателей.
Рад это слышать. Если это поможет, рассмотрите возможность принять это как ответ, нажав на значок «галочка»., @hcheung
Но что делать, если я хочу отправить значения в одном пакете - как его упаковать? Особенно, когда на некоторых узлах я измеряю разные виды значений? И как быть с полученными данными на стороне получателя? Спасибо, @iotdeveloper
Вам не нужно намеренно упаковывать его, он отправляет 4+4 байта. Лично я не знаю, как RadioSend и Lora обрабатывают данные внутри, поэтому я не могу на это ответить. Для получения данные int16_t довольно просты. Для float вы можете прочитать мой ответ на [этот вопрос](https://stackoverflow.com/questions/78169013/how-to-receive-a-float-array-using-esp8266-via-i2c/78170406#78170406) о том, как прочитать float
из полученного буфера., @hcheung
Мне нужно отправить все значения в одном пакете, а затем на стороне получателя декодировать его и разделить нагрузку на отдельные значения. Это возможно?, @iotdeveloper
Если подумать, можно создать массив чисел с плавающей точкой (или структуру чисел с плавающей точкой) и отправить в него все 8 байт. Массив [0] будет значением температуры, а массив [2] — значением влажности., @hcheung
У меня также есть пример в моем [блоге](https://www.e-tinkers.com/2020/05/esp-01-range-test-with-esp-now-protocol/), который показывает температуру и влажность в структуре и отправляет по передаче. Вы можете взглянуть на это. Если у вас есть дополнительные вопросы, вы должны поднять их в отдельном вопросе, StackOverflow/StackExchange лучше подходят для одного вопроса за раз. Не добавляйте вопросы, когда на один уже ответили., @hcheung
Хорошо, а можно ли как-то гарантировать, что при измерении разных переменных можно будет определить, какая переменная находится в пакете в заданной позиции или мне просто нужно это знать? Например, если я отправлю температуру и влажность с одного устройства, а давление, напряжение и ток — с другого? Или просто указать позицию для каждой переменной в пакете, а в случае, если она не будет измеряться, оставить, например, ноль? Спасибо, @iotdeveloper
Если вы хотите отправить температуру и влажность в одном пакете,
Самый простой способ — определить пакет как struct
с двумя полями:
struct LoraData {
float temperature;
float humidity;
};
Затем вы можете отправить необработанные байты, приведя тип адреса такого
struct
в uint8_t*
. Однако это обычно не рекомендуется,
потому что это нарушает правила псевдонимов типов C++. Вы можете обойти это
проблема с определением объединения
:
union LoraPacket {
LoraData data;
uint8_t bytes[sizeof(LoraData)];
};
Это представляет собой область памяти, которую можно интерпретировать как содержащую
либо числовые данные data
, либо массив байтов. Затем можно заполнить
поле data
и отправьте необработанные байты:
void send_dummy_data()
{
LoraPacket packet = {
.data = {
.temperature = 12.56,
.humidity = 76.21
}
};
Radio.Send(packet.bytes, sizeof packet);
}
На другом конце вы делаете то же самое в обратном порядке: заполняете байты и считайте числовые данные:
void rx_done(uint8_t *payload, uint16_t size, int16_t, int8_t)
{
if (size != sizeof(LoraPacket)) { // sanity check
Serial.println("Bad packet size");
return;
}
LoraPacket packet;
memcpy(&packet.bytes, payload, size);
Serial.print("temperature: ");
Serial.println(packet.data.temperature);
Serial.print("humidity: ");
Serial.println(packet.data.humidity);
}
- Как использовать внешний кристалл 32 кГц для ESP32 S3 с Arduino IDE?
- Как передать AT-команды Лоре из UART ESP32?
- Можно ли свободно использовать UART0 при подключении ESP32 s3 через USB (D+, D-)?
- Почему Arduino IDE выдает неправильное имя платы для ESP32 S3
- ESP32 TTGO T-Call подключается к SX1276
- Ограничение подключений EthernetClient
- Сжатие изображения в оттенках серого с помощью ESP32-S3-WROOM Freenove
- esp32, platformio A fatal error occurred: Packet content transfer stopped (received 8 bytes) *** [upload] Error 2
21.56
можно представить двумя байтами как2156
, @jsotola