STM32 передается через USB с ПК, проблема с порядком следования байтов

Я сейчас пытаюсь отправить поплавки через USB. На ПК есть приложение Qt, выполняющее следующий код

float x = 2.0;
memcpy(buffer.data() + 14, &x,  sizeof x);

с функцией debuglog я могу ясно видеть серию байтов, проходящих через следующий порядок

.. 00 00 00 40 ..

который согласно этому сайту

http://www.scadacore.com/field-tools/programming-calculators/online-hex-converter/

преобразуется в 1073741824 в случае слабого байта.

на моем STM32 я могу использовать следующий код, чтобы затем включить LED4

uint32_t a = buffer[14] | (buffer[15] << 8) | (buffer[16] << 16) | (buffer[17] << 24);                      
if (a == 1073741824){
    HAL_GPIO_WritePin(LED4_PORT, LED4_PIN, GPIO_PIN_RESET);
}

Проблема возникает, когда я хочу преобразовать в реальное значение с плавающей запятой 2.0.

на самом деле, если я сделаю

float b = buffer[14] | (buffer[15] << 8) | (buffer[16] << 16) | (buffer[17] << 24);
if (b == 2.0f){
    HAL_GPIO_WritePin(LED5_PORT, LED5_PIN, GPIO_PIN_RESET);
}

LED5 не включается.

Это проблема с порядком байтов? Как я могу получить значение с плавающей запятой 2.0?

С уважением,


person Luigi    schedule 04.06.2017    source источник
comment
Отправьте числа с плавающей запятой как текст ASCII и преобразуйте их обратно на другом конце. Так проще и безопаснее.   -  person ThingyWotsit    schedule 04.06.2017
comment
2.0 с завершающим символом (например, CR или NUL) имеет тот же размер, что и одиночный, и не может быть легко неверно истолкован, если обе стороны знают протокол, и тогда вы можете общаться практически с чем угодно с чем угодно. Кроме того, протокол с завершающим символом позволяет избежать проблем с потоковыми соединениями, когда вызов rx возвращает «раньше» с меньшим количеством байтов, чем необходимо для полного сообщения / числа с плавающей запятой.   -  person ThingyWotsit    schedule 04.06.2017
comment
вы можете привести пример?   -  person Luigi    schedule 04.06.2017


Ответы (1)


Для чисел с плавающей запятой IEEE 754 порядок байтов обычно не является проблемой, но проверьте, чтобы быть уверенным.

Ваша основная проблема - прочитать значение. Вы выполняете операцию ИЛИ в целочисленной арифметике и получаете целочисленное значение, которое является правильным, но затем вы конвертируете его в число с плавающей запятой. Это всегда будет давать мусор, кроме 0.

Вам нужно переосмыслить его как float. Вы можете использовать :

  • Приведение указателя: float a = *(float*)&myInt;
  • A memcpy : memcpy(&myFloat, &myInt, 4);
  • Союз: union { uint32_t i; float f; };, u.i = myInt; float f = u.f;

Также нужно быть осторожным при сравнении с плавающей запятой. Как правило, писать if( f == 2.0f ) - плохая идея, потому что 2.0f является приближением. Лучше избегать == и использовать вместо этого > >= < <=. Если вы хотите проверить конкретное значение, а не диапазон, проверьте достаточно маленький диапазон вокруг вашего значения, при этом диапазон должен соответствовать вашим требованиям к точности.

person ElderBug    schedule 04.06.2017
comment
Я попробую и сообщу об этом. В любом случае я думал, что данный uint32 может переводиться только в фиксированное число с плавающей запятой. Это не? - person Luigi; 04.06.2017
comment
@Luigi Да, каждый uint32 может представлять действительный, другой float. Хотя, преобразовав, вы можете получить только часть диапазона с плавающей запятой, а не те, которые вам нужны в вашем случае. Например, 1.0f представлен как 0x3F800000, целое число, которое не даст 1.0, если вы конвертируете его. - person ElderBug; 04.06.2017
comment
Есть ли ярлык для работы только / напрямую с элементами массива? - person Luigi; 04.06.2017
comment
@Luigi Вы, вероятно, можете использовать массив напрямую, но только если порядок байтов правильный. Это даст float f = *(float*)&buffer[14]. Вы также можете сделать это для целых чисел, опять же, только если порядок байтов верен. Если это не так, я думаю, вы не сможете сделать это без промежуточной переменной, но вы можете обернуть все в функции, чтобы иметь более удобный синтаксис. - person ElderBug; 04.06.2017
comment
Так следует ли мне fabs (myFloat - 2.0f) ‹0.01f, чтобы проверить правильность значения? - person Luigi; 04.06.2017
comment
@Luigi Да, это разумная возможность. - person ElderBug; 04.06.2017
comment
@Luigi Обратите внимание, что в случае 2.0, == будет работать нормально, потому что он точен в форме с плавающей запятой, но общая идея состоит в том, чтобы избегать == для плавающих. - person ElderBug; 04.06.2017
comment
Обратите внимание, что только решение memcpy фактически разрешено стандартными строгими правилами псевдонима. - person Matteo Italia; 04.06.2017
comment
Как мне узнать, правильный ли мой заказ? - person Luigi; 05.06.2017
comment
Вы уверены, что байты не связаны? Кажется, это зависит от stackoverflow.com/questions/2945174/floating-point-endianness @ElderBug - person Luigi; 05.06.2017
comment
@Luigi Вот почему я писал обычно. Все, что использует несколько байтов для одного значения, зависит от порядка байтов. Просто на обычной современной архитектуре (x86, AMD64, ARM, ARM64 ...) порядок байтов для чисел с плавающей запятой такой же. В качестве встречного примера это неверно для PowerPC. Чтобы узнать правильный, вам просто нужно знать порядок байтов вашей архитектуры. Если вы не знаете, возможно, самый простой способ - попробовать оба и посмотреть, какой из них работает. - person ElderBug; 05.06.2017