如何在oled显示上优化C for循环以进行字体渲染

时间:2014-07-18 17:56:47

标签: c optimization

我需要优化此功能:优化for循环的任何奇怪方法? (我认为早期休息是不可能的)

void SeeedGrayOLED::putChar(unsigned char C)
{
if(C < 32 || C > 127) //Ignore non-printable ASCII characters. This can be modified for multilingual font.
{
    C=' '; //Space
}   

uint8_t k,offset = 0;
char bit1,bit2,c = 0;

for(char i=0;i<16;i++)
{
    for(char j=0;j<32;j+=2)
    {

        if(i>8){
            k=i-8;
            offset = 1;
        }else{
            k=i;
        }

        // Character is constructed two pixel at a time using vertical mode from the default 8x8 font
        c=0x00;
        bit1=(pgm_read_byte(&hallfetica_normal[C-32][j+offset]) >> (8-k))  & 0x01;  
        bit2=(pgm_read_byte(&hallfetica_normal[C-32][j+offset]) >> ((8-k)-1)) & 0x01;
       // Each bit is changed to a nibble
        c|=(bit1)?grayH:0x00;
        c|=(bit2)?grayL:0x00;
        sendData(c);
    }
}

}

我在数组hallfetica_normal中有一个字体,是一个uint8_t数组的数组,可能是压缩的还是类似的?

此代码在arduino上运行,ad我可以从500到0进行倒计时,每10 / 20ms一个单位减少。

修改

这是你的指示之后的新代码,谢谢大家: 我希望以不同的方式组织字体,以减少对pgm_read_byte的调用..(比如改变方向......我不知道)

void SeeedGrayOLED::putChar(unsigned char C)
{
if(C < 32 || C > 127) //Ignore non-printable ASCII characters. This can be modified for multilingual font.
{
    C=' '; //Space
}   

char c,byte = 0x00;
unsigned char nibble_lookup[] = { 0, grayL, grayH, grayH | grayL };

for(int ii=0;ii<2;ii++){
    for(int i=0;i<8;i++)
    {
        for(int j=0;j<32;j+=2)
        {
            byte = pgm_read_byte(&hallfetica_normal[C-32][j+ii]);
            c = nibble_lookup[(byte >> (8-i)) & 3];
            sendData(c);
        }
    }
}

}

2 个答案:

答案 0 :(得分:4)

好吧,你好像是通过pgm_read_byte(&hallfetica_normal[C-32][j+offset])不必要地连续两次读取相同的字节。您可以将一次加载到局部变量中。

此外,您可以通过将代码分解为两个循环来避免每次迭代if(i>8){检查;一个i从0变为8,另一个从9变为15.(虽然我怀疑你真的打算>=在这里,使循环边界0-7然后8-15。)也意味着像offset这样的东西会变成常数值,这会有所帮助。

答案 1 :(得分:2)

为了尽可能快地使内循环,我试图用查找表去除所有分支,看看是否有帮助。

首先,我在循环外定义查找表:

/* outside the loop */
unsigned char h_lookup[] = { 0, grayH };
unsigned char l_lookup[] = { 0, grayL };

然后在循环内部,由于您正在测试最低有效位,因此可以将其用作查找表的索引。如果清楚,那么查找索引将为0.如果已设置,则查找索引将为1:

/* inside the loop */
byte = pgm_read_byte(&hallfetica_normal[C-32][j+offset]);
c = h_lookup[((byte >> (8-k)) & 0x01)] |
    l_lookup[((byte >> (8-k-1)) & 0x01)]
sendData(c);

由于您正在屏蔽和测试2个相邻位8-k8-k-1,因此您可以在单个查找表中列出所有4种可能性:

/* Outside loop */
unsigned char nibble_lookup[] = { 0, grayL, grayH, grayH | grayL };

然后查找变得极为简化。

/* loop */
byte = pgm_read_byte(&hallfetica_normal[C-32][j+offset]);
c = nibble_lookup[(byte >> (8-k)) & 3];
sendData(c);

另一个答案已经解决了如何处理内循环顶部的分支。