Вставка 1-32 бит в 64-битный (8x8 байт) буфер - PullRequest
0 голосов
/ 05 марта 2020

Я пытаюсь вставить значение длиной от 1 до 32 бит в буфер размером 8 байт (64 бита).

Например, у меня есть 12-битное значение, которое я хочу вставить в бит позиции с 7 по 18.

Единственный способ, которым я могу думать об этом, - преобразовать мое 12-битное значение в 64-битное значение, сместить его, а затем установить все биты в моем буфере таким образом, а затем разделить мое 64-битное значение в 8 байтов. В 8-байтовом кадре могут быть другие данные ... Есть ли лучший способ сделать это?

Ниже будет приведен пример кода.

byte tx_msg[8] = {0};
uint32_t random_value = 77;
uint64_t buffer = 0;
// In this example, start point is bit 7, length is 12.

buffer = (uint64_t)random_value << (64 - 12 - 7);
for(int i = 0; i < 8; i++) {
    tx_msg[7-i] = tx_msg[7-i] | buffer >> (i*8);
}

1 Ответ

1 голос
/ 05 марта 2020

Прежде всего вам необходимо четко определить порядок следования битов. Предполагая, что бит LSB упорядочивается первым:

| Byte0  | Byte1  | ...
-----------------------
|01234567|01234567| ...

Так, например:

|00000001|10000000|

будет Byte0 == 0x80 и Byte1 == 0x08 (потому что шестнадцатеричное представление является MSB первым).

Тогда я бы предложил более универсальный интерфейс:

void copyBits( uint8_t* dest, int offset, uint32_t bits, int length ) ;

, где length биты из bits (начиная с LSB) будут скопированы в offset биты в dest.

Простой (но неоптимальный с точки зрения производительности) метод состоит в том, чтобы копировать побитовое копирование следующим образом:

#include <stdint.h>
#include <stdlib.h>

void copyBits( uint8_t* dest, int offset, uint32_t bits, int length )
{
    for( int b = 0; b < length; b++ )
    {
        int source_bit = (bits & (0x01 << b)) == 0 ? 0 : 1 ;

        div_t bit_dest = div( offset + b, 8 ) ;
        if( source_bit == 0 )
        {
            dest[bit_dest.quot] &= ~(0x01 << bit_dest.rem) ;
        }
        else
        {
            dest[bit_dest.quot] |= (0x01 << bit_dest.rem) ;
        }
    }
}

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

Пример использования:

uint8_t x[8] = {0};

insertBits( x, 7, 0x555, 12 ) ;

for( int i = 0; i < sizeof( x ); i++ )
{
    printf( "%02X", x[i] ) ;
}

В результате получается

80AA020000000000

, который в двоичном виде в LSB сначала битовый порядок:

LSB --->
0000 0001 0101 0101 0100 0000 0000 ...
        ^-------------^
           0x555 (12 bits) copied here
...