Как преобразовать двойной в гекс / байт

Мне нужно отправить данные в The Things Network, и данные должны быть в байтах

Для отправки данных туда и обратно через сеть вещей вам нужно использовать байты

Некоторые функции возвращают число с плавающей запятой с 2

23,56 или 4,32

У меня есть большие трудности, чтобы преобразовать мой float и сохранить его в надежных uint8_t моих данных. Я должен найти, как конвертировать мою переменную с плавающей точкой

У меня есть такой цикл:

/*
NOTE:
uinit8_t mydata[64];
byte nbMaxCapteurs = 10;
mesMesures[i][mesCapteur[i].idDuCapteur].valeur => this is a float
*/

memset(mydata, 0xFF, 64);
uint8_t * ptr = mydata;
for (byte i = 0; i < nbMaxCapteurs; i++) {
  if (mesCapteur[i].actif) {
    *ptr = mesMesures[i][mesCapteur[i].idDuCapteur].valeur;
    ptr += 15; // How to know the number of step to move the pointer
    if (i < nbCapteurActif + 1) {
      *ptr = 0x2C; // virgule
      ptr += sizeof(char);
    }
  } else {
    *ptr = 0x2C; // virgule pour les capteurs inactifs
    ptr += sizeof(char);
  }
}
*ptr = '00'; // Close \0
ptr += sizeof(char);
printData();

Я очень новичок в таких преобразованиях. Настоящая проблема здесь:

*ptr = mesMesures[i][mesCapteur[i].idDuCapteur].valeur;

printData печатает это:

04 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2C CB FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2F A8 F8 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2C

Но это должно напечатать по крайней мере это:

34 2E 33 32 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2C CB FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2C A8 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 2C

Так как 34 2e 33 32 равно 4,32.

Я не понимаю и не знаю, как я могу "объединить" и преобразовать значение с плавающей запятой. И тогда вы могли бы помочь мне переместить указатель в соответствии с размером поплавка?

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

2 ответа

  • Если вы хотите округлить до нуля после двух десятичных знаков, вы можете использовать следующее:

    double lum = ((int)(luminosity * 100))/100.0;
    
  • Если вы хотите округлить до ближайшего (округлить половину от нуля) после двух десятичных знаков, вы можете использовать следующее:

    #include <math.h>
    double lum = round(luminosity * 100)/100.0;
    

  • Если, с другой стороны, вы хотите максимально эффективно сохранить яркость в 8 битах, вы можете использовать следующий алгоритм.

    uint8_t packed_luminosity;
    if (luminosity >= MAX_LUMINOSITY)       // Just in case
       packed_luminosity = 255;
    else if (luminosity <= MIN_LUMINOSITY)  // Just in case
       packed_luminosity = 0;
    else
       packed_luminosity = (uint8_t)(
           ( luminosity - MIN_LUMINOSITY ) / ( MAX_LUMINOSITY - MIN_LUMINOSITY + 1 ) * 256 );
    

    Вы можете выполнять сравнения и определенные операции над светимостью в этом формате.

  • Другой способ упаковать десятичное число в целое число - это число с фиксированной запятой. Это работает, выбирая масштабирование для всех ваших яркостей, когда вы пишете свою программу. Вот диапазоны, поддерживаемые некоторыми масштабами:

    uint8_t
    =======
    Scaling  Supported range (binary)         Supported range (decimal)
    -------  -------------------------------  -----------------------------------------
    ...
    B8       [00000000.    .. 111111110.   ]  [0 .. 512)  No odd numbers
    B7       [ 0000000.    ..  11111111.   ]  [0 .. 256)  No decimals
    B6       [  000000.0   ..   1111111.1  ]  [0 .. 128)  .0, .5
    B5       [   00000.00  ..    111111.11 ]  [0 ..  64)  .0, .25, .5, .75
    B4       [    0000.000 ..     11111.111]  [0 ..  32)  Almost one full decimal place
    ...
    
    int8_t
    ======
    Scaling  Supported range (binary)        Supported range (decimal)
    -------  ------------------------------  --------------------------------------------
    ...
    B8       [10000000.   .. 011111110.   ]  [-256 .. 256)  No odd numbers
    B7       [ 1000000.   ..  01111111.   ]  [-128 .. 128)  No decimals
    B6       [  100000.0  ..   0111111.1  ]  [ -64 ..  64)  .0, .5
    B5       [   10000.00 ..    011111.11 ]  [ -32 ..  32)  .0, .25, .5, .75
    B4       [    1000.000 ..    01111.111]  [ -16 ..  16)  Almost one full decimal place
    ...
    

    Как вы можете видеть, использование только 8 битов очень ограничивает, и вы не получаете такую ​​же гибкость выбора диапазонов, как предыдущий метод. Преимущество чисел с фиксированной точкой состоит в том, что вы можете выполнять арифметические функции (сложение, вычитание, умножение и деление) на их пары.

(Я ничего не знаю об Arduino)

Минимальное изменение, которое приблизит вас к вашим целям:

double luminosity;
uint32_t lum;
lum = (uint32_t)(luminosity * 100);

Теперь lum будет содержать ваше значение, умноженное на сотню, округленное в меньшую сторону.

Вместо 23,45 вы получите 2345. Использование uint8_t ограничит вас слишком сильно, так как диапазон слишком мал (0-255). Имеются ли у вас в наличии uint16_t и uint32_t, я не знаю.

Эта техника называется арифметикой с фиксированной точкой.

Другие вопросы по тегам