我有一个相当复杂的应用程序,它控制绘制的咖啡杯数。不同数量后,必须将水箱注满,否则必须丢弃咖啡渣。
该应用程序在几年内表现良好,现在我想添加一个风扇来干燥咖啡渣,以防止霉菌,现在几天后就会形成霉菌。
flash 的可用空间几乎被吃光了(经过多次优化后,只剩下 100 字节左右)。
随机显示位图(笑脸),每个位图大小为 392 字节,我有 7 个。
它们的存储方式如下:
//const unsigned char Sm1Dimension[] PROGMEM = {56, 56};
const unsigned char Smiley1[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x00, 0x00,
0x03, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0xff, 0x00,
... (cut out several lines of bytes)
0xfe, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00
};
const unsigned char Smiley2[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00,
0x3f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0xff, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x00,
... (cut out several lines of bytes)
0x0f, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xe0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
... and so on until
const unsigned char Smiley7[] PROGMEM = {...};
在第一种方法中,我通过 switch..case 结构选择要显示的位图,该结构工作得很好。 Adafruit GFX 库接受指针并按预期显示位图。
工作代码部分下方:
switch(cSmileySelect) // select Smiley
{
case 1:
pSmileyAdresse = Smiley1;
break;
case 2:
pSmileyAdresse = Smiley2;
break;
case 3:
pSmileyAdresse = Smiley3;
break;
case 4:
pSmileyAdresse = Smiley4;
break;
case 5:
pSmileyAdresse = Smiley5;
break;
case 6:
pSmileyAdresse = Smiley6;
break;
case 7:
pSmileyAdresse = Smiley7;
break;
default:
pSmileyAdresse = Smiley1;
break;
}
// void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t width, int16_t height, uint16_t color);
display.drawBitmap((128 - cSmileyBreite) / 2, 0 + (64 - cSmileyHoehe) / 2, pSmileyAdresse,
(unsigned int)cSmileyBreite, (unsigned int)cSmileyHoehe, WHITE);
在添加驱动风扇的逻辑时再次遇到内存不足后,我发现这个开关..case 结构消耗了大量的闪存。
我试图通过数学的方式替换switch..case来推导Flash中位图的指针,但没有得到结果。
我的测试是这样的:
pSmileyAdresse = (uint8_t*)(uint16_t)((Smiley7) + (2352 - (((cSmileySelect - 1) % 7) * (sizeof(Smiley7)) )));
幻数2352是7个笑脸的完整数组的大小,位图按降序存储(笑脸7位于最低地址)。
我的期望是,添加每个笑脸位图的大小应该得出下一个笑脸的地址,但无济于事。
下一个方法是,建立一个指向笑脸的指针数组......
const unsigned char* Smileys[] = {
&Smiley1[0], &Smiley2[0], &Smiley3[0], &Smiley4[0], &Smiley5[0], &Smiley6[0], &Smiley7[0], &Smiley13_bw[0]
};
...并通过以下方式获取所选笑脸的地址:
pSmileyAdresse = (const uint8_t*)(Smileys[cSmileySelect - 1][0]);
这可能有效,但是我的代码中的这个小添加使闪存中的代码增加了 3166 字节,将最大值增加了约 2000 字节。
为什么会这样?
最后:
有没有一种方法可以通过简单的数学推导笑脸的 PROGMEM 地址,而不突破闪存限制?
谢谢!
void drawBitmap(int16_t x, int16_t y, uint8_t *位图, int16_t 宽度, int16_t 高度, uint16_t 颜色);
AdafruitGFX 为
drawBitmap()
提供了两种重载方法。这个特殊的方法允许您传递一个指向位于 RAM 中的 bitmap
的指针,正如您从 源代码 中看到的那样,它不会从 PROGMEM 中读取数据,而只是获取一个字节b = bitmap[j * byteWidth + i / 8];
。因此,如果您使用函数签名调用该方法,则需要首先将数据复制到 RAM 缓冲区中,然后使用指向 RAM 缓冲区的指针调用该函数,显然这将占用 Smileyx 大小的 RAM 内存。
正确调用的API是第二个重载方法:
void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color)
注意到细微的差别是
const uint8_t bitmap[]
和 源代码 表明它直接从 PROGMEM 中读取一个字节:
b = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
这只需要 1 个字节的 RAM 来存储
b
,而不是 Smiley1 的大小。要使用此方法,只需直接传入 Smiley1
即可:
display.drawBitmap(x, y, Smiley1, w, h, color);