Создание байта (8 бит) из 4 2 бит

Я пытаюсь найти способ получить как можно больше из ограниченной памяти в моем микроконтроллере (32 КБ) и ищу предложения или указатели на алгоритм, который выполняет то, что я пытаюсь сделать.

Небольшая предыстория: я отправляю биты в манчестерском кодировании через SPI (последовательный периферийный интерфейс) непосредственно из DMA. Поскольку наименьшая возможная единица, которую я могу хранить в DMA, — это байт (8 бит), мне приходится представлять свои 1 как 0b11110000, а мои 0 — как 0b00001111. В основном это означает, что для каждого бита информации мне нужно использовать байт (8 бит) памяти. Что очень неэффективно.

Если бы я мог уменьшить это так, чтобы мои 1 были представлены как 0b10, а мои 0 как 0b01, мне нужно было бы использовать только 1/4 байта (2 бита) для каждого 1 бита памяти, что хорошо для моего решение.

Вот если бы я мог сохранять в DMA по битам, это не было бы проблемой, но работать конечно нужно с байтами. Итак, я знаю, что решение моей проблемы включает в себя сбор 8 бит (или, в моем случае, 4 2 бита) и последующее сохранение в DMA в виде байта.

Вопросы:

Есть ли стандартный способ решить эту проблему?

Как я могу создать 8-битное число из набора 4 2-битных чисел? Но я хочу не сложения этих цифр, а того, как это выглядит, когда собрано вместе.

Например: у меня есть следующие 4 2-битных числа (имея в виду, что 0b10 представляет 1, а 0b01 представляет 0) (Кроме того, тип, в котором они хранятся, открыт для решения, поскольку, очевидно, существует нет такого понятия, как 2-битный тип)

Число1: 0b01 Число 2: 0b10 Число 3: 0b10 Число4: 0b01

И я хочу создать из них следующее 8-битное число:

8-битный номер: 0b01 10 10 01 или без пробелов 0b01101001 (0x69)

я программирую на с


person Remixed123    schedule 23.01.2014    source источник


Ответы (3)


Кажется, что вы можете упаковать четыре числа a, b, c, d, каждое из которых равно нулю или единице, например так:

64 * (a + 1) + 16 * (b + 1) + 4 * (c + 1) + (d + 1)

Это использует тот факт, что x + 1 кодирует ваше двухбитное целое число: 1 становится 0b10, а 0 становится 0b01.

person Kerrek SB    schedule 23.01.2014
comment
Я чувствую, что реализация битового сдвига была бы более понятной: (a + 1)<<6 + (b + 1)<<4 + (c + 1)<<2 + (d + 1) - person Macattack; 23.01.2014
comment
Как вы так быстро ответили на этот вопрос? Пораженный и благодарный, вы, возможно, только что помогли мне уменьшить использование памяти в 4 раза! - person Remixed123; 23.01.2014
comment
Спасибо, Macattack, не стесняйтесь добавлять это в качестве ответа, и какой бы я ни использовал, я буду знать галочку. Извини, Керрек, я поторопился... но все равно впечатлен твоей скоростью! - person Remixed123; 23.01.2014
comment
Отлично, но вы можете пойти еще лучше! Делайте все добавления параллельно: ((((a << 2) | b) << 2) | c) << 2) | d) + 0x55 Сдвиг только на 2 каждый раз работает быстрее, если процессор не имеет бочкообразного переключателя. - person Gene; 23.01.2014

Это манчестерская кодировка, поэтому 0b11110000 и 0b00001111 должны быть единственными кандидатами. Если да, то уменьшите память в 8 раз.

uint8_t PackedByte = 0;
for (i=0; i<8; i++) {
  PackedByte <<= 1;
  if (buf[i] == 0xF0) //  0b11110000
    PackedByte++;
}

С другой стороны, если это манчестерская кодировка и у нее может быть идеальная кодировка, тогда возможны 3 результата: 0, 1, неопределенный.

uint8_t PackedByte = 0;
for (i=0; i<8; i++) {
  int upper = BitCount(buf[i] >> 4);
  int lower = BitCount(buf[i] & 0xF);
  if (upper > lower)
    PackedByte++;
  else if (upper == lower)
    Hande_Indeterminate();
}

Различные упрощения, отсутствующие в приведенном выше, но показанные для логического потока.

person chux - Reinstate Monica    schedule 23.01.2014
comment
Привет, Чукс, не уверен, что понимаю, как это работает, так как мне нужен нарастающий фронт для представления 0 и задний фронт для представления 1. Как мне представить это с помощью 1 бита с манчестерским кодированием? - person Remixed123; 23.01.2014
comment
@ Remixed123 Извините. Мой ответ сосредоточен на получении, а не на передаче. Я все еще думаю, что вы можете использовать 1 упакованный бит для указания следующих 8 битов SPI, таких как 0b11110000 или ob00001111. Более сложная задача заключается в чтении SPI с идеей, что данные закодированы в Манчестере. Вы делаете 4-кратную передискретизацию при отправке. Если вы также получаете то же самое, этот ответ может помочь. - person chux - Reinstate Monica; 23.01.2014
comment
Было бы здорово, если бы я мог использовать 1 бит для указания следующих восьми битов моего SPI. Не уверен, что мой микроконтроллер имеет такой уровень конфигурируемости SPI. У этой функции есть название? Таким образом, я могу найти его в таблице данных для моего микроконтроллера. Что касается принимающей стороны, это набор (до 2048) индивидуально адресованных интегральных схем. Каждый из них берет часть пакета и передает остальные. - person Remixed123; 23.01.2014
comment
Нет. Что я предлагаю отправить, так это то, что в вашем буфере данных для отправки вы извлекаете 1 бит за раз, а затем отправляете в SPI 8-битный байт 0b11110000 или 0b00001111. Если вы не можете передать SPI 8 бит за раз, настройте локальный буфер из 8 и каждый раз, когда вам нужно отправить бит, тяните оттуда, пополняя этот 8-битный буфер с помощью 0b11110000 или 0b00001111 по мере необходимости на основе следующий бит из буфера data. - person chux - Reinstate Monica; 23.01.2014
comment
Хорошо, на самом деле это интересный подход. Мне нужно посмотреть, можно ли отправить данные без нарушения связи или времени. Может быть возможно установить правильное время, настроив таймер, но заставить его отправлять в одном постоянном потоке без каких-либо перерывов может быть сложно. - person Remixed123; 23.01.2014

Чтобы получить число abcd из (a,b,c,d), вам нужно сдвинуть число на свои места и ИЛИ: -

(a<<6)|(b<<4)|(c<<2)|d

person Vikram Bhat    schedule 23.01.2014