详细解析OLED及相关代码,基于SH1107的1.3寸OLED屏

前言:如果有什么问题的话欢迎大家在下方留言评论。

最近在做一些基于SH1107的1.3寸OLED屏幕相关的项目,现在对一些相关的命令、地址和代码做些总结。

一、显示地址

1、SH1107最大是支持128x128的矩阵面板的,现在以分辨率为64(H)x128(V)为准进行说明

H:Horizontal(横),即横向为64个像素点

V:Vertical(竖),即竖向为128个像素点

SH1107可参考以下的显示地址列表:

详细解析OLED及相关代码,基于SH1107的1.3寸OLED屏_第1张图片

① SH1107具有16页即page0-page15,每一页都为8行总共128行,也就是Seg0-Seg127

② SH1107具有128列,即Column0-Column127,也就是0-7F

这里使用的设置内存地址模式命令(Set memory addressing mode)为0x20,即页地址模式。页地址模式是指列写入数据后,列地址的指针会自动加1,如果列地址指针到达终止地址(0x7F)后,列地址指针将会返回到起始地址(0x00),但是页地址指针不会改变,如果需要访问下一页的内容,我们需要手动设置下一页的页地址和列地址,所以此模式下是OLED是一页一页刷新显示的,命令格式如下图:


2、这里我所使用的液晶屏以16页、64列为准,具体可参考下图的实物显示位置图

① OLED屏上每一行和每一列的显示方向,下图白色指标为行(H)的方向,一行为64个点,红色指标为列(V)的方向,一列为128个点,如下图:

详细解析OLED及相关代码,基于SH1107的1.3寸OLED屏_第2张图片

② OLED屏对应的全部显示地址列表,16页对应page0-page15,64列对应col0-col63,如下图:

详细解析OLED及相关代码,基于SH1107的1.3寸OLED屏_第3张图片

③ OLED屏对应的8192(64*128)个像素点,每一页里每一列都为D0-D7的8个点,程序里点亮的话也是8位数据传输,如下图:

详细解析OLED及相关代码,基于SH1107的1.3寸OLED屏_第4张图片


二、相关代码

1、在对应的页和列写数据

OLED_WR_Byte(0xb0,OLED_CMD); // 设置页地址
OLED_WR_Byte(0x0f,OLED_CMD); // 设置显示的列的低地址
OLED_WR_Byte(0x10,OLED_CMD); // 设置显示的列的高地址
OLED_WR_Byte(0xff,OLED_DATA);

在第一页的第16列写入全高电平,也就是将第16列的D7-D0写入11111111,将这八位对应的像素点全点亮,如下图(图1为OLED屏第16列被点亮的八个点,图2红框是对应的显示地址列表里的第16列):

详细解析OLED及相关代码,基于SH1107的1.3寸OLED屏_第5张图片
图1
详细解析OLED及相关代码,基于SH1107的1.3寸OLED屏_第6张图片
图2

① 程序OLED_WR_Byte (0xb0,OLED_CMD)的0xb0是设置页的地址,格式是根据设置页地址命令(Set Page Address)进行编写,该命令格式高四位的1011是固定的,而低四位是根据SH1107的16个页(00H-0FH)进行改变,第一页为0,所以传送的是0xb0,命令如下:

② 这里需要注意,列地址范围是00H-3FH,但是在发送命令的时候需要将列地址的高四位和低四位分开进行发送,程序里面设置的是0FH,即第16列。

③ 程序OLED_WR_Byte (0x0f,OLED_CMD)的0x0f是设置列的低地址,格式是根据设置列低地址(Set Column Address 4 Lower Bits)进行编写,该命令格式高四位的0000是固定的,而低四位则需要将程序指定的第16列的列地址0x0f(0000 1111)的低四位1111写入该命令的低四位,拼接起来就是0x0f,下图命令格式中的Lower column address就是列地址的低四位1111。

Lower column address为什么可以设置为4位?因为列地址是00H-3FH的,低四位最大可以设置为全1。

④ 程序OLED_WR_Byte (0x10,OLED_CMD)的0x10是设置列的高地址,格式是根据设置列高地址(Set Column Address 4 Higher Bits)进行编写,该命令格式高四位的0001是固定的,而低四位则需要将程序指定的第16列的列地址0x0f(0000 1111)的高四位0000写入该命令的低四位,拼接起来就是0x10,但是该命令格式的第四位是固定为0的只写Higher column address这三位。

那为什么Higher column address只能设置三位?因为列地址是00H-3FH的(本人使用的OLED屏幕),但是SH1107最大的列地址是可以达到00H-7FH的(具体可以参考前面的显示地址列表图),所以高位是可以设置为0111的,即为7。

⑤程序OLED_WR_Byte(0xff,OLED_DATA)的0xff是对应设置的一列全点亮。

下面是另外一个显示位置,可根据前面对应着参考位置变化时两者命令的区别:

OLED_WR_Byte(0xbf,OLED_CMD);         // 设置页地址
OLED_WR_Byte(0x00,OLED_CMD);      // 设置显示的列的低地址
OLED_WR_Byte(0x10,OLED_CMD);      // 设置显示的列的高地址
OLED_WR_Byte(0xff,OLED_DATA);  

在最后一页第16页的第1列的八位像素点全点亮,如下图:

详细解析OLED及相关代码,基于SH1107的1.3寸OLED屏_第7张图片
详细解析OLED及相关代码,基于SH1107的1.3寸OLED屏_第8张图片


2、设置坐标函数 OLED_Set_Pos()

void OLED_Set_Pos(unsigned char x, unsigned char y)   
{     
        OLED_WR_Byte(0xb0+y,OLED_CMD);     
        OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);    // 设置列高地址   
         OLED_WR_Byte(x&0x0f,OLED_CMD);         // 设置列低地址
}   

参数x是列(0-63,也就是列地址最多为0x3F,SH1107最多可达0x7F),y是页(0-15,也就是页地址最多为0x0F) 

(1) 手册上SH1107芯片的OLED最大可达128*128个点(128列、16页每页8行即128行),项目上的OLED只有64*128个点(64列、16页每页8行即128行)

(2) 函数OLED_Set_Pos(31, 0)指第一页的第31列:

        ① 31=0x1F代入((x&0xf0)>>4)|0x10,0x1F&0xF0即保留高位的0001得到十六进制为0x10(低四位&0全清为0),>>4即将0x10向右移动4位为0x01,|0x10即将0x01|0x10为0x11,而0x11也就是根据手册上的设置列高地址的命令,该命令的高四位D7 D6 D5 D4为0 0 0 1(这是固定不变的,也就是0x11左边的0001),低四位的D3为0(这是发送命令时固定好的),而D2 D1 D0是根据刚刚运算得出的0x11的低三位的001进行设置。这个设置列高地址的命令也就是将31=0x1F(第32行,因为0-31)的高四位0001根据设置列高地址命令格式0001 0XXX的形式填补到该命令的低四位0XXX里。

        ② 31=0x1F代入x&0x0f,即0x1F & 0x0F保留了低四位的1111得0x0F,也就是设置列低地址的命令形式0000XXXX(见手册),高四位的0000是固定的,而XXXX就是根据得出的0x0F的低四位1111进行设置的。

        ③ 总结:也就是设置的行数31=0x1F的高四位0001和低四位1111分为两个命令执行,即高四位0001按照列高地址的命令打包为00010001,而低四位按照列低地址的命令打包为00001111。

举例:

OLED_Set_Pos(31,0);
OLED_WR_Byte(0xff,OLED_DATA);

点亮第一页的第32列,如下图:

详细解析OLED及相关代码,基于SH1107的1.3寸OLED屏_第9张图片
详细解析OLED及相关代码,基于SH1107的1.3寸OLED屏_第10张图片

3、显示字符函数 OLED_ShowChar()

void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size)
{               
        u8 i = 0;               
        if(x > Max_Column - 1)     
        {         
                x = 0;         
                y = y + 2;   
         }     
        if(Char_Size == 16)   
         {         
                OLED_Set_Pos(x, y);             
                for(i = 0; i < 8; i++)         
                {           
                        OLED_WR_Byte(F8X16[chr*16+i], OLED_DATA);       
                 }       
                OLED_Set_Pos(x, y+1);         
                for(i = 0; i < 8; i++)       
                {             
                        OLED_WR_Byte(F8X16[chr*16+i+8], OLED_DATA);       
                 }   
         }     
        else     
        {             
                OLED_Set_Pos(x, y);         
                for(i = 0; i < 6; i++)       
                 {             
                        OLED_WR_Byte(F6x8[chr][i], OLED_DATA);           
                 }     
        }
 }

功能:在指定位置显示一个字符 参数:x为列地址,y为页地址,chr是字符数组的某个元素,Char_Size是选择字体:这里字体有8x16和6x8两种类型

分析:

(1) if(x > Max_Column - 1)是判断如果列地址超过了一页的终止地址时就自动切换到当前页数+2的页(比如当前是第一页的话那就会切换到第三页)

(2) 当Char_Size==16的话选择8x16字体,这里需要对字体长宽比进行了解,使用的取模软件是PCtoLCD2002:

①软件的字模选项设置如下:

详细解析OLED及相关代码,基于SH1107的1.3寸OLED屏_第11张图片

② 如果需要的是8x16字体的,这里需要注意字宽是想要设置的英文长度的2倍,而字高需要设置为8的整数倍也就是16,代表显示的时候用了2页,因为是页地址模式,当第一页8列写完后会在第二页继续写8列,如下图:

详细解析OLED及相关代码,基于SH1107的1.3寸OLED屏_第12张图片

(3) 字符E的8x16格式数组生成后为:0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00

① 先设置页数和列数:

OLED_Set_Pos(x, y) 

② 这里是将数组的前8个元素进行写入,也就是将第一页写完,结果是将字符E的上半部分填充到第一页:

for(i = 0; i < 8; i++)
{
        OLED_WR_Byte(F8X16[chr*16+i], OLED_DATA);
}  

③ 接着设置字符E下半部分写入第二页y+1,x要跟上半部分x的位置设置一样:

OLED_Set_Pos(x, y+1); 

④ 这里是将数组的后8个元素进行写入,也就是将字符E的下半部分填充到第二页:

for(i = 0; i < 8; i++)
{
        OLED_WR_Byte(F8X16[chr*16+i+8], OLED_DATA);
}  

显示如下:

详细解析OLED及相关代码,基于SH1107的1.3寸OLED屏_第13张图片

所以这里的字符显示函数如果你懂了的话,其它的显示中文、显示字符串等等都是一个道理,无非就是设置好页数和列数,然后根据字体的大小对页数进行填充,如果掌握了的话你自己也就可以编写自己想要的显示功能函数了。


4、显示图片函数 OLED_DrawBMP()

void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
{          
        unsigned int j=0;     
        unsigned char x,y;     
        for(y=y0;y        {         
                OLED_Set_Pos(x0,y);         
                for(x=x0;x                {                   
                        OLED_WR_Byte(BMP[j++],OLED_DATA);                     
                }   
        }

功能:显示BMP图片,分辨率为64×128
参数:x0为起始的列数,y0为起始的页数,x1为终点列数,y1为终点页数,BMP[]为BMP图片的取模数组 

分析:

(1) 如果要直接提取图片进行显示的话,这里可以使用PCtoLCD2002软件进行提取,点击软件左上角新建,宽高设置为64x128,如下图:

详细解析OLED及相关代码,基于SH1107的1.3寸OLED屏_第14张图片
详细解析OLED及相关代码,基于SH1107的1.3寸OLED屏_第15张图片
详细解析OLED及相关代码,基于SH1107的1.3寸OLED屏_第16张图片

(2) 该图片提取出来的数组为:

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,
0xFC,0xFE,0xFF,0xFF,0xFF,0xFF,0xFE,0xFC,0xF8,0xF4,0xC0,0x80,0x00,0x00,0x00,0x80,
0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,
0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFE,0xF8,0xE0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xE0,0xF8,0xFC,0xFE,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xC0,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x07,0xE7,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x07,0x3F,0x7F,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0x00,0x40,0x80,0xC0,0xC0,0xFC,0xFE,0xF0,0xF0,0xF0,0xF0,0xF0,0xC8,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0xFF,0xE7,0x3F,0xFC,0x00,
0xF8,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,
0x80,0xFC,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x07,0x1E,0x01,0x0F,0x08,0x00,0x00,
0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFC,0xF0,
0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x0F,0x1F,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x01,0x07,0x0F,0x1F,0x3F,0x7F,0x7F,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFE,0xFC,0xF8,0xF0,0xF8,0xFE,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x80,0xC0,0xC0,0xC0,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0x0F,0x0F,0x0F,0x17,0x01,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x00,

(3) 如果函数为OLED_DrawBMP(0,0,64,16,BMP1),那么:

OLED_Set_Pos(x0,y); 指轮询16个页数,每一页都是从第1列开始

OLED_WR_Byte(BMP[j++],OLED_DATA);  指将每一页的64列填充满,之后需要跳转到下一页时使用OLED_Set_Pos(x0,y)设置到下一页的第一列处继续进行填充,这里是64个元素填充一页

(4) 显示结果如下:

详细解析OLED及相关代码,基于SH1107的1.3寸OLED屏_第17张图片


大家可以参考SH1107的资料手册:https://download.csdn.net/download/Grey_Street/12259292

CSDN和同步更新,欢迎浏览,CSDN博客入口:https://blog.csdn.net/Grey_Street

你可能感兴趣的:(详细解析OLED及相关代码,基于SH1107的1.3寸OLED屏)