为lcd屏幕旋转1位位图

时间:2017-08-06 22:59:51

标签: c++ c arrays arduino atmega

我在微控制器(Arduino Mega)的阵列中存储了Hitachi HD44780 LCD控制器的一些自定义字符。字符基本上是位图,颜色深度为1位,宽5 px,高8 px。

为了节省尽可能多的宝贵内存,我决定存储旋转的数据。否则我会浪费每行三位。例如,É会像这样存储:

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

输出应如下所示:

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

我的问题是,将这种情况转变为É的最有效方法是什么。我们在谈论一个只有8 KB RAM的16 MHz处理器,所以保持它尽可能快和微小是关键。编程语言是C(++)。

我个人的想法是创建所需的8字节数组并从左到右扫描行,用一些位掩码设置这些位。这就是为什么我也会对字母进行镜像,这样我就可以轻松地将我的位掩码移位并将其用于两个数组。

基本扫描第一个输入字节,相应地设置输出数组的第3位,扫描第二行,设置输出数组的第4位,依此类推。

但有没有更好的方法来实现这一目标?

2 个答案:

答案 0 :(得分:0)

首先,谢谢。这是我几个月来看到的最有趣的问题。

所以空间是约束。我认为主要的问题是位提取和插入成本会很快耗尽代码内存。从5个字节的数组中提取单个位的循环,插入到8个字节的数组中可能需要大量可执行代码来执行此操作。

我建议用不同的方式来表示数据是支持一种run-length encoding.输出字符可以被认为是一个单位字符串,由0 / 1s流组成,后跟其他0流/ 1s直到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即将获得最大规模的收益。

答案 1 :(得分: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) };
    
  4. 要在运行时解压缩 - 可能有多种方法。以下是一个简单的想法。

    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可以分析不同代码的地方。