zoukankan      html  css  js  c++  java
  • 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
    },
    
    //自由添加
    }
  • 相关阅读:
    Key-Value Memory Network
    Deep Mask Memory Network with Semantic Dependency and Context Moment for Aspect Level Sentiment Clas
    Deep Memory Network在Aspect Based Sentiment方向上的应用
    Deep Memory Network 深度记忆网络
    Self Attention 自注意力机制
    Attention基本公式及其变种
    *端策略优化算法(PPO)
    Policy Gradient 算法
    一本通 农场派对
    A
  • 原文地址:https://www.cnblogs.com/hexia7935/p/14612443.html
Copyright © 2011-2022 走看看