0.96寸OLED模块-简述如何修改OLED_ShowChar()函数达到修改显示字体大小的目的

首先上OLED_ShowChar()函数

//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示
//size:选择字体 48/24/32/16/12
void OLED_ShowChar(u8 x, u8 y, u8 chr, u8 Char_Size)
{
    unsigned char c = 0, i = 0;
    c = chr - ' '; //得到偏移后的值
    if (x > Max_Column - 1) {x = 0; y = y + 2;}
    if (Char_Size == 48)
    {
            OLED_Set_Pos(x, y);
        for (i = 0; i < 24; i++)
            OLED_WR_Byte(F24X48[c * 144 + i], OLED_DATA);
        OLED_Set_Pos(x, y + 1);
        for (i = 0; i < 24; i++)
            OLED_WR_Byte(F24X48[c * 144 + i +24], OLED_DATA); 
            OLED_Set_Pos(x, y + 2);
        for (i = 0; i < 24; i++)
            OLED_WR_Byte(F24X48[c * 144 + i +48], OLED_DATA); 
            OLED_Set_Pos(x, y + 3);
    for (i = 0; i < 24; i++)
            OLED_WR_Byte(F24X48[c * 144 + i +72], OLED_DATA); 
        OLED_Set_Pos(x, y + 4);
        for (i = 0; i < 24; i++)
            OLED_WR_Byte(F24X48[c * 144 + i +96], OLED_DATA); 
        OLED_Set_Pos(x, y + 5);
        for (i = 0; i < 24; i++)
            OLED_WR_Byte(F24X48[c * 144 + i +120], OLED_DATA); 

    }
    else if(Char_Size == 32)
    {
            OLED_Set_Pos(x, y);
        for (i = 0; i < 16; i++)
            OLED_WR_Byte(F16X32[c * 64 + i], OLED_DATA);    
            OLED_Set_Pos(x, y+1);
        for (i = 0; i < 16; i++)
            OLED_WR_Byte(F16X32[c * 64+ i+16], OLED_DATA);    
            OLED_Set_Pos(x, y+2);
        for (i = 0; i < 16; i++)
            OLED_WR_Byte(F16X32[c * 64 + i+32], OLED_DATA);    
            OLED_Set_Pos(x, y+3);
        for (i = 0; i < 16; i++)
            OLED_WR_Byte(F16X32[c * 64 + i+48], OLED_DATA);            
    }
    //F12X24字库:一行36个,
    else if (Char_Size == 24)
    {
            OLED_Set_Pos(x, y);
        for (i = 0; i < 12; i++)
            OLED_WR_Byte(F12X24[c * 36 + i], OLED_DATA);  //18*2
        OLED_Set_Pos(x, y + 1);
        for (i = 0; i < 12; i++)
            OLED_WR_Byte(F12X24[c * 36 + i +12], OLED_DATA); 
            OLED_Set_Pos(x, y + 2);
        for (i = 0; i < 12; i++)
            OLED_WR_Byte(F12X24[c * 36 + i +24], OLED_DATA); 
    }
    else if (Char_Size == 16)
    {
        OLED_Set_Pos(x, y);
        for (i = 0; i < 8; i++)
            OLED_WR_Byte(F8X16[c * 16 + i], OLED_DATA);
        OLED_Set_Pos(x, y + 1);
        for (i = 0; i < 8; i++)
            OLED_WR_Byte(F8X16[c * 16 + i + 8], OLED_DATA);
    }
    else
    {
        OLED_Set_Pos(x, y);
        for (i = 0; i < 6; i++)
            OLED_WR_Byte(F6x8[c][i], OLED_DATA);

    }
}

这个函数原来没有Char_Size == 32这个分支,我在使用过程中需要显示适中的大小,所以研究了下,完成了16*32字体。

这个函数内能够显示的只有ASCALL码表内的符号,并且字库内的符号必须要按照ASCALL码表顺序排列,否则显示出来的不是你想要的。

我之前不懂,为了显示℃这个符号,随意在字库内找了个位置,将℃的对应的值粘贴,结果OLED原本显示正常的符号“.”变成了“-”,我看下了,这两个正好是上下关系,所以,一定要按顺序写字库。

其次是取字符软件的正确使用,因为没有人可以请教,一个小问题都要研究好久。

第一是取模方式的设置:

第二是如何取到你想要大小的模,我想要取16*32的模,可是取出来后总觉得有问题,参考已有的字库,取其他大小的模,发现行数不对。

直到我偶然瞥见这句话“对应英文长宽比xx*xx”

才发现我如果想取16*32,那么红圈内参数的设置应该是32*32。生成字模后,得到4*16个十六进制数。

因为我手头其他大小的字体是能正常运行的,我只需要依葫芦画瓢的写32大小的else if 就好了,但是我还是花了不少时间,为了方便大家也为了给将来的自己看,我把分析模仿的过程写下来。

首先是函数内的第一句话, c = chr - ' ';   chr代表你输入的字符,稍微了解下ASCALL码就能明白,这是为了得到输入字符在表内的排名。 

16*32字库是一堆十六进制的数组,一个16*32的字符实际上就是16*32,一共512个像素点的亮灭显示的,一个16进制数代表8个像素点的亮灭,例如0x51=>01010001,1表示亮,0表示灭。

512/8=64

所以16*32的字符需要64个数来表示。

使用OLED_Set_Pos(x, y);确认起始坐标后,就可以开始逐列逐行的写入,

        for (i = 0; i < 16; i++)
            OLED_WR_Byte(F16X32[c * 64 + i], OLED_DATA);   

i<16:16这个值怎么得到,因为我们要的是16*32,所以是16,假如你要24*48,那你就需要写24

c * 64:表示我们所要写的字符的起始位置

假设我们需要显示空格,空格在ASCALL码表内是第0个位置,所以 c = chr - ' ';得到C=0, 我们就从字库的第0个16进制数开始写入(所以假如我们字库的顺序不对,就不能正确显示我们想要的字符)

屏幕写完一行后,开始写下一行,x不变,y+1

一行写16个,我们一共64个,所以需要写4行

    else if(Char_Size == 32)
    {
            OLED_Set_Pos(x, y);
        for (i = 0; i < 16; i++)
            OLED_WR_Byte(F16X32[c * 64 + i], OLED_DATA);    
            OLED_Set_Pos(x, y+1);
        for (i = 0; i < 16; i++)
            OLED_WR_Byte(F16X32[c * 64+ i+16], OLED_DATA);    
            OLED_Set_Pos(x, y+2);
        for (i = 0; i < 16; i++)
            OLED_WR_Byte(F16X32[c * 64 + i+32], OLED_DATA);    
            OLED_Set_Pos(x, y+3);
        for (i = 0; i < 16; i++)
            OLED_WR_Byte(F16X32[c * 64 + i+48], OLED_DATA);            
    }

我在调试时,忘记了将y+1,最后只显示了最后一行,虽然当时错了,但是我知道离成功不远了。

当然我们日常使用不会只使用ASCALL表内的内容,我们要显示中文等字符,就需要创建一张新的表。这张表不需要按顺序排列。

下面是void OLED_Print(u8 x, u8 y, char *s,u8 size)的函数,可以显示ASCALL表字符,也可以显示自己字库内的字符。

太长了,只截取字体大小为16的部分

void OLED_Print(u8 x, u8 y, char *s,u8 size)
{
    u8 i,k,t,length;
    u8 c[2];
    length = strlen(s);//取字符串总长
    
    if(size==16)
    {
        for(k=0; k<length; k++)
        {
            if(*(s+k) <= 127){//小于128是ASCII符号
                OLED_ShowChar(x,y,*(s+k),16);
                x += 8;//x坐标右移8
            }else if(*(s+k) > 127){//大于127,为汉字,前后两个组成汉字内码
                c[0]=*(s+k);
                c[1]=*(s+k+1);//取汉字的内码
                for(i=0;i<sizeof(codeGB_16)/ sizeof(codeGB_16[0]);i++){//查数组
                    if(c[0] == codeGB_16[i].Index[0]&&c[1] == codeGB_16[i].Index[1]){
                        //查询到这个字
                        OLED_Set_Pos(x,y);    
                        for(t=0;t<16;t++)
                            OLED_WR_Byte(codeGB_16[i].Msk[t],OLED_DATA);//写入字模

                        OLED_Set_Pos(x,y+1);    
                        for(t=16;t<32;t++)
                            OLED_WR_Byte(codeGB_16[i].Msk[t],OLED_DATA);

                        x += 16;
                        k += 1; //汉字占2B,跳过一个    
                        break;
                    }
                }
            }
        }
    }
}
struct  typFNT_GB16 codeGB_16[] =          // 数据表  16x16 扫描方式:列行式
{
"",{0x00,0x00,0xFE,0x12,0x92,0xB2,0xD2,0x92,0x92,0x92,0xD2,0xB2,0x9E,0x00,0x00,0x00,
                    0x40,0x30,0x0F,0x04,0x84,0x64,0x1F,0x04,0x04,0x04,0xFF,0x04,0x04,0x04,0x00,0x00
},
"",{0x00,0x80,0x60,0xF8,0x07,0x00,0x3E,0x22,0x22,0xE2,0x22,0x22,0x3E,0x00,0x00,0x00,
            0x01,0x00,0x00,0xFF,0x20,0x11,0x09,0x05,0x03,0xFF,0x03,0x05,0x09,0x11,0x20,0x00
},

//自由添加
}
原文地址:https://www.cnblogs.com/hexia7935/p/14612443.html