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

У меня есть длинный массив из 64 значений от 0 до 15, которые занимают всего 8 бит для широтно-импульсной модуляции.

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

const byte wave[64] = {8,9,9,10,11,11,12,12,13,13,14,14,14,15,15,15,15,15,15,15,14,14,14,13,13,12,12,11,11,10,9,9,8,7,7,6,5,5,4,4,3,3,2,2,2,1,1,1,1,1,1,1,2,2,2,3,3,4,4,5,5,6,7,7};
//постоянная байтовая волна[2] = {8,9};
byte i = 0;
void setup() {pinMode(1,OUTPUT);}
void loop() {            //(Не беспокойтесь о коде здесь,
  analogWrite(1,wave[i]);//нужно просто получить программу
  i++;delay(1);          //для хранения данных)
}

Компилятор сказал, что Sketch использует 1112 и 1050 байт (3%) пространства для хранения программ. или разница в 62 байта.

Это говорит мне о том, что можно сэкономить много памяти, сохраняя их в 4-битном формате или в том, что я хотел бы назвать полубайтовым, переходя от 0 к f, а не от 00 до ff.

Как это сделать, не превратив код в нечитаемую кашу?

, 👍0

Обсуждение

Вы всегда можете использовать Nibbles. Просто сохраните число в первой половине байта, а другое во второй половине. чтобы прочитать его обратно, просто сдвиньте и И с соответствующей маской., @Kwasmich

Я понимаю, что это может помочь, просто интересно, не будет ли маскировка использовать много динамической памяти?, @B7th

Вы определенно можете поместить 64 из ваших 4-битных целых чисел в массив байтов с 32 слотами, но если вы планируете указать содержимое этого массива байтов, как в вашем примере кода, то это может не сильно помочь. Если, с другой стороны, вы читали свой массив 4-битных целых чисел откуда-то еще (например, из флэш-памяти или со входа UART), то вам может повезти. Объявив const byte wave[64], вы сказали своей программе выделить 64 байта, и корабль отплыл., @S. Imp

Если компилятор все делает правильно, это всего лишь ОДНА дополнительная инструкция (И) для чтения правого полубайта и ДВЕ инструкции (ПОМЕНКА + И) для чтения левого полубайта. Таким образом, для вашего кода требуется на 6 байт больше, но, с другой стороны, вы экономите 32 байта на своих данных., @Kwasmich

Это имеет большой смысл! Итак, я должен найти способ сохранить эти кусочки до того, как они будут в программе? Как-то можете порекомендовать?, @B7th

Вы уверены, что у вас недостаточно памяти? Насколько это вероятно? Вы собираетесь производить их десятками тысяч или можете просто купить чип с большей памятью? В противном случае я бы сказал, что это преждевременная оптимизация., @Thomas Weller

На самом деле я пришел к чему-то довольно интересному, превратив этот массив в переменную типа int. Это действительно долго, но с 64 * 4 бит все еще подходит! и я сэкономил целых 186 байт о_О, @B7th

данные выглядят как таблица поиска синусоидальной волны ... вам нужно только сохранить 1/4 волны, @jsotola

@jsotola Верно! Но фактические данные, с которыми я работаю, представляют собой набор нескольких синусоид вместе, поэтому необходим полный цикл., @B7th

Я думаю, вы можете [использовать союз](https://stackoverflow.com/questions/20005349/define-union-that-can-access-bits-nibbles-bytes), который является частью C. Затем компилятор выполнит все битовые манипуляции для вас. Но я не очень хорошо разбираюсь в C. Может быть, @Majenko сможет вмешаться., @Gerben


2 ответа


Лучший ответ:

1

Сохранение 4-битных значений в полубайтах возможно с помощью структур и битовых полей. Вам понадобится функция доступа для разделения "индекса массива" в индекс байта и селектор полубайта (младший бит "индекса массива") и вернуть или сохранить соответствующий полубайт.

Этот связанный вопрос о StackOverflow есть несколько ответов, показывающих, как это сделать. Очевидно, что при распаковке 4-битных фрагментов будут некоторые накладные расходы, поскольку к ним нельзя обратиться напрямую, но они будут незначительными и являются компромиссом для экономии памяти, когда памяти не хватает.

,

2

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

То есть 8,9 становится 0x89. Точно так же A равно 10, B равно 11 и т. д. Затем вы можете выполнить итерацию от 1 до 64 и выполнить некоторое деление и сдвиг битов, чтобы получить исходное значение, которое вы хотели. Это перебирает ваш 32-байтовый массив и извлекает 64 полубайтовых значения.

    const byte wave[32] = {0x89,0x9A,0xBB,0xCC,0xDD,0xEE,0xEF,0xFF,0xFF,0xFF,0xEE,0xED,0xDC,0xCB,0xBA,0x99,0x87,0x76,0x55,0x44,0x33,0x22,0x21,0x11,0x11,0x11,0x22,0x23,0x34,0x45,0x56,0x77};
    for(int i=0; i<64; i++) {
        byte val;
        if (i % 2) {
            // младший байт идет первым (LITTLE ENDIAN)
            val = wave[i/2] & 0x0F;
        } else {
            // БОЛЬШОЙ байт второй
            val = (wave[i/2] >> 4) & 0x0F;
        }
        Serial.printf("%i=%i\n", i, val);
    }

ПРИМЕЧАНИЕ: Endianness в вашей системе может отличаться от моей. В наши дни большинство систем используют обратный порядок байтов, но никогда не знаешь наверняка.

,