Как объединить целочисленные двоичные значения в массиве в C? - PullRequest
0 голосов
/ 18 мая 2018

Я пишу встроенную системную программу, которая получает 24-битные данные от внешнего АЦП через SPI и сохраняет данные в целочисленном массиве.Эта часть работает.Чтобы данные были полезны, мне нужно объединить каждый байт в двоичном или шестнадцатеричном виде и разделить на 0x7FFFFFF.Здесь я сталкиваюсь с неприятностями.Например, я могу получить массив данных через SPI, который выглядит следующим образом:

data_buffer = { 24 , 17 , 140 };

aka

data_buffer = { 0b00011000 , 0b00010001 , 0b10001100 };

aka

data_buffer = { 0x18 , 0x11 , 0x8C };

Что мне нужно сделатьс этим значением объединяется каждый элемент, чтобы получить что-то вроде этого:

data_value = 0x18118C

, а затем разделить это значение на 0x7FFFFF, чтобы оно было полезным в моей программе.В этом примере значение, которое я хотел бы получить в итоге: 0x18118C / 0x7FFFFF = 0,188

Как бы я поступил так?

Извините, я не предоставил больше кода, честно говоря, понятия не имею, с чего начать.

Ответы [ 2 ]

0 голосов
/ 18 мая 2018

Самый простой способ - сдвинуть значения в целое число правильного размера.В вашем примере:

int data_value = 0;
for (i = 0; i < 3; ++i) {
    data_value = data_value << 8;
    data_value |= data[i] & 0xff;    // Makes sure you are only adding 8 bits
}

Вы можете адаптировать это по мере необходимости для переменных размеров массива.Вам просто нужно убедиться, что data_value достаточно велика, чтобы вместить все.Поскольку вы работаете с 24-битными данными, будет работать 32-битное целое число.Затем вы присвоите data_value значению с плавающей запятой и выполните свое деление.

double data_double = data_value;
double final_value = data_double / 8388607.0

Вам необходимо использовать значение с плавающей запятой 0x7FFFFF, чтобы избежать целочисленного усечения.

0 голосов
/ 18 мая 2018

Объединение трех байтов в одно 24-битное (фактически 32-битное) значение является простым применением побитовых операторов Си.Вот это в подробном, "длинном" виде:

unsigned char data_buffer[] = { 24 , 17 , 140 };

unsigned long int data_value = 0;
data_value |= data_buffer[0];
data_value <<= 8;
data_value |= data_buffer[1];
data_value <<= 8;
data_value |= data_buffer[2];

Я бы, вероятно, написал это в более компактной форме:

unsigned long int data_value = 0;
data_value |= data_buffer[0];
data_value = (data_value << 8) | data_buffer[1];
data_value = (data_value << 8) | data_buffer[2];

Или вы можете сделать это в другом порядкетак сказать:

unsigned long int data_value = 0;
data_value |= (unsigned long)data_buffer[0] << 16;
data_value |= data_buffer[1] << 8;
data_value |= data_buffer[2];

(Здесь вам нужно дополнительное преобразование, однако, если вы используете 16-битный процессор, где обычный data_buffer[0] << 16 сдвинет все биты и потеряет их.)

Или вы можете сделать все это сразу:

unsigned long int data_value =
    ((unsigned long)data_buffer[0] << 16) |
                   (data_buffer[1] << 8) |
                    data_buffer[2];

В любом случае вы можете затем выполнить необходимое деление:

float float_value = (float)data_value / 0x7FFFFF;

(ВыВозможно, вы захотите использовать double вместо float. Или, в зависимости от ограничений встроенной среды, вы можете вообще не использовать прямую с плавающей точкой, как вы; вы не сказали.)

Когда я их распечатываю, я получаю запрошенные вами значения:

printf("data_value = %#lX, float_value = %f\n", data_value, float_value);

выход:

data_value = 0X18118C, float_value = 0.188036

Добавление: я забыл упомянуть, что для этих методовработают правильно, обычно действительно важно , чтобы ваши входные данные, т.е. массив data_buffer в вашем примере, имели тип unsigned char,Если это не так - например, если это просто char, который подписан на большинстве машин - у вас обычно возникают изнурительные проблемы с расширением знака.Например, ваше значение 140 - это шестнадцатеричное число 0x8c, как вы знаете, но оно интерпретируется как знаковое 8-битное число, это -116.И когда он участвует в выражении с другими целыми числами, он обычно расширяется до 0xff8c или 0xffffff8c, что, конечно, совсем не то, что вам нужно.(Вы можете обойти это с помощью дополнительных масок & 0xff, как предложено в ответе SteveB, но это неудобство. Гораздо проще использовать unsigned char.)

...