Преобразование 32-битного шестнадцатеричного значения со знаком в десятичное

Использование CAN-щита Seed Studio для чтения и преобразования данных CAN в десятичное значение.

Пример ожидаемого результата:

Полное сообщение CAN равно 70 3B F1 FF 00 00 00 00 , с использованием первых 4 байтов с прямым порядком байтов получается: FFF13B70 , что должно быть равно преобразованному десятичному значению -0,967824 (с использованием коэффициента 0,000001).

Вот код для извлечения текстового значения, которое я использую.

CAN.readMsgBuf(&len, buf);
unsigned char len = 0;
unsigned char buf[8];
    {
           String reg0 = String (buf[0], HEX);
           String reg1 = String (buf[1], HEX);
           String reg2 = String (buf[2], HEX);   
           String reg3 = String (buf[3], HEX);
           Serial.print(reg3);
           Serial.print("\t");
           Serial.print(reg2);
           Serial.print("\t");
           Serial.print(reg1);
           Serial.print("\t");
           Serial.print(reg0);
           Serial.print("\t");
           String regsumm = (reg3 + reg2 + reg1 + reg0);

           Serial.println(regsumm);
        }

В результате я получил только текстовую строку, которую невозможно преобразовать в dec. Есть еще способы как это сделать?

, 👍0


2 ответа


1

Вы выбрали совершенно неверный путь. Вы не хотите конвертировать данные в текст, а затем снова конвертировать их в данные — это уже данные.

Вы можете объединить первые четыре байта буфера в одно 32-битное целое число со знаком всего лишь:

int32_t val = ((int32_t)buf[3] << 24) | ((int32_t)buf[2] << 16) | 
              ((int32_t)buf[1] << 8) | (int32_t)buf[0];

Это дает вам значение -967824, которое равно 0xFFF13B70 в шестнадцатеричном формате или 11111111 11110001 00111011 0111000 в двоичном формате. Все они одно и то же и представляют собой просто числа.

Затем вы можете умножить этот результат на свой «коэффициент» в переменную с плавающей запятой:

float dec = val * 0.000001;

Скорее всего, он не даст вам -0,967824 из-за природы значений с плавающей запятой, поэтому вам лучше оставить его как -967824 и работать в «микроединицах», а не в «единицах».

>
,

Комментарии не предназначены для расширенного обсуждения; этот разговор был [перенесен в чат](https://chat.stackexchange.com/rooms/87212/discussion-on-answer-by-majko-converting-of-32-bit-signed-hex-value-to- декабрь)., @Majenko


1

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

union {
    uint8_t bytes[8];
    int32_t numbers[2];
} buffer;
unsigned char len = 0;

CAN.readMsgBuf(&len, buffer.bytes);
Serial.println(buffer.numbers[0] * 1e-6, 6);

Это выведет -0.967824 на последовательный порт.

Обратите внимание, что этот код не будет работать должным образом на платформе с прямым порядком байтов. Если вам нужно что-то портативное, обычное решение — создать результат с использованием битовых сдвигов, как в ответе Маженко.

,