Вращение 1-битного растрового изображения для ЖК-экрана

Я храню некоторые пользовательские символы для ЖК-контроллера Hitachi HD44780 в массиве моего микроконтроллера (Arduino Mega). Символ представляет собой растровое изображение с глубиной цвета в один бит, шириной 5 пикселей и высотой 8 пикселей.

Чтобы сохранить как можно больше драгоценной памяти, я решил хранить данные повернутыми. В противном случае я бы потратил три бита на строку. Так, например, É будет храниться так:

---#####   0x1F
-#-#-#-#   0x55
#--#-#-#   0x95
---#-#-#   0x15
---#---#   0x11

Вывод должен выглядеть так:

-----#--   0x04
----#---   0x08
--------   0x00
---#####   0x1F
---#----   0x10
---####-   0x1E
---#----   0x10
---#####   0x1F

Мой вопрос заключается в том, как наиболее эффективно превратить это обратно в É. Мы говорим о 16 МГц процессоре с только 8 КБ ОЗУ, поэтому ключевым моментом является поддержание его как можно более быстрым и крошечным. Язык программирования — C (++).

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

В основном сканируйте первый входной байт, соответственно установите 3-й бит выходного массива, отсканируйте вторую строку, установите 4-й бит выходного массива и так далее.

Но есть ли лучший способ добиться этого?

1

Решение

Прежде всего, спасибо. Это самый интересный вопрос, который я видел за последние месяцы.

Так что пространство — это ограничение. На мой взгляд, основная проблема заключается в том, что есть затраты на извлечение и вставку битов, которые довольно быстро израсходуют память кода. Цикл, извлекающий один бит из массива из 5 байтов и вставляющий в массив из 8 байтов, может потребовать для этого хорошего куска исполняемого кода.

Я предлагаю другой способ представления данных для поддержки своего рода кодирование длин серий Выходной символ можно рассматривать как однобитовую строку, состоящую из потока 0/1 с, за которым следуют другие потоки 0/1 с, пока не будут заполнены 64 бита.

По сути, вы кодируете изменения состояния, а не фактическую битовую комбинацию.
Данные будут иметь ширину 1 бит для обозначения 0 или 1, шириной 3 бита для представления длины 1 … 8.

следовательно с

-----#--   0x04
----#---   0x08
--------   0x00
---#####   0x1F

Кодировка будет

  • 0101 — 0 бит, всего 6 битовых позиций, закодировано как 6 — 1 (——)
  • 1000 — 1 бит, всего 1 битная позиция, закодированная как 1 — 1 (#)
  • 0101 — 0 бит, всего 6 битовых позиций, закодировано как 6 — 1 (——)
  • 1000 — 1 бит, всего 1 битная позиция, закодированная как 1 — 1 (#)
  • 0111 — 0 бит, всего 8 битовых позиций, закодировано как 8 — 1 (———)
  • 0101 — 0 бит, всего 6 битовых позиций, закодировано как 6 — 1 (——)
  • 1100 — 1 бит, всего 5 битовых позиций, закодировано как 5 — 1 (#####)

Это 3,5 байта вместо 4 байтов для кодирования.


Разновидность темы — не кодировать первые 3 бита на каждый байт. Когда исполняемый код приходит к этому, он автоматически помещает три 0 в него. Это снизило бы стоимость кодирования маленького примера выше до примерно 2,5 байтов за счет некоторого дополнительного исполняемого кода.

Я думаю, что выгода в том, что вы каждый раз вытягиваете биты из одного куска байта и разбрасываете их на биты одного байта. IMNSHO, который собирается получить самый большой размер за доллар.

0

Другие решения

Есть ли лучший способ добиться этого?

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

Чтобы упаковать во время компиляции:

  1. Создайте 32 константы (или eunm)

    #define L_____ 0
    #define L____X 1
    #define L___X_ 2
    ...
    #define LXXXX_ 30
    #define LXXXXX 31
    
  2. Сделать макросы

    #define PACK8_5(a,b,c,d,e,f,g,h) \
    ((((((uint64_t)(a) << 5) + (b)) << 5) + (c)) << 5) + (d) ...
    #define UNPACK40_5(a) \
    ((a) >> 32) & 31, ((a) >> 24) & 31, ((a) >> 16) & 31, ((a) >> 8) & 31, (a) & 31
    #define CHBM(a,b,c,d,e,f,g,h) (UNPACK40_5(PACK8_5((a),(b),(c),(d),(e),(f),(g),(h))))
    
  3. Сделайте битовую карту персонажа. Что хорошо в этом, так это то, что исходный код может выглядеть как растровое изображение символа.

    unsigned char letter[5] = { CHBM( \
    L__X__, \
    L_X___, \
    L_____, \
    LXXXXX, \
    LX____, \
    LXXXX_, \
    LX____, \
    LXXXXX) };
    

Распаковывать во время выполнения — возможны различные способы. Ниже приведена простая идея.

void unpack5to8(unsigned char dest[8], const unsigned char src[5]) {
uint64_t pack = src[0];
for (unsigned i=1; i<5; i++) {
pack <<= 8;
pack += src[i];
}
for (unsigned i=8; i>0; ) {
i--;
dest[i] = pack & 31;
pack >>= 5;
}

Другая идея — использовать больше кода, но 32-битных переменных. Здесь OP может профилировать различные коды.

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector