我们学习的OLED的主控芯片是SH1106,并且的我们的OLED是64×128点阵。![在这里插入图片描述](https://img-blog.csdnimg.cn/20190714162128444.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0RyZWFtZXJfSEhI,size_16,color_FFFFFF,t_70)
其中的行划分是按照每8个纵列划分,即每行有8列,方便以字节为单位整体操作。
硬件连接电路如下:
具体的操作函数分别如下:
初始化函数:
void OLED_DISPLAY_ON (void){//OLED屏初始值设置并开显示
u8 buf[28]={
0xae,//0xae:关显示,0xaf:开显示
0x00,0x10,//开始地址(双字节)
0xd5,0x80,//显示时钟频率?
0xa8,0x3f,//复用率?
0xd3,0x00,//显示偏移?
0XB0,//写入页位置(0xB0~7)
0x40,//显示开始线
0x8d,0x14,//VCC电源
0xa1,//设置段重新映射?
0xc8,//COM输出方式?
0xda,0x12,//COM输出方式?
0x81,0xff,//对比度,指令:0x81,数据:0~255(255最高)
0xd9,0xf1,//充电周期?
0xdb,0x30,//VCC电压输出
0x20,0x00,//水平寻址设置
0xa4,//0xa4:正常显示,0xa5:整体点亮
0xa6,//0xa6:正常显示,0xa7:反色显示
0xaf//0xae:关显示,0xaf:开显示
}; //
I2C_SAND_BUFFER(OLED0561_ADD,COM,buf,28);
}
利用I2C总线写入OLED控制芯片即可,需要注意的是,有些功能的设定,需要先写入该功能的控制号,告诉芯片要设置哪个功能,再写入具体的参数值,以用来设置特定功能。
OLED清屏显示:
void OLED_DISPLAY_CLEAR(void){//清屏操作
u8 j,t;
for(t=0xB0;t<0xB8;t++){ //设置起始页地址为0xB0
I2C_SAND_BYTE(OLED0561_ADD,COM,t); //页地址(从0xB0到0xB7)
I2C_SAND_BYTE(OLED0561_ADD,COM,0x10); //起始列地址的高4位
I2C_SAND_BYTE(OLED0561_ADD,COM,0x00); //起始列地址的低4位
for(j=0;j<132;j++){ //整页内容填充
I2C_SAND_BYTE(OLED0561_ADD,DAT,0x00);
}
}
}
}
意思是:先从第一行清除,即先写入第一行的行标号,再写入列的起始地址,其中0x10,0x00中的两个高四位1、0是特殊标志位,用来表示列,两个数的低四位组合起来便是0x0000 0000正好代表列的起始地址,而0x00000000-0x11111111正好代表了128列,后面利用for循环逐渐从第1列至第128列清零。
字符和数字、汉字占用的OLED原理图如下:
经过计算可知显示字母的数字、字母和汉字,每个汉字占16列,每行最多可有8个汉字,16个字符,该OLED有8行。
字符显示函数:
void OLED_DISPLAY_8x16(u8 x, //显示字母的页坐标(从0到7)(此处不可修改)
u8 y, //显示字母的列坐标(从0到128)
u16 w){ //要显示字母的编号
u8 j,t,c=0;
y=y+2; //因OLED屏的内置驱动芯片是从0x02列作为屏上最左一列,所以要加上偏移量
for(t=0;t<2;t++){
I2C_SAND_BYTE(OLED0561_ADD,COM,0xb0+x); //页地址(从0xB0到0xB7)
I2C_SAND_BYTE(OLED0561_ADD,COM,y/16+0x10); //起始列地址的高4位
I2C_SAND_BYTE(OLED0561_ADD,COM,y%16); //起始列地址的低4位
for(j=0;j<8;j++){ //整页内容填充
I2C_SAND_BYTE(OLED0561_ADD,DAT,ASCII_8x16[(w*16)+c-512]);//为了和ASII表对应要减512
c++;}x++; //页地址加1
}
}
其实字符显示函数和清屏函数的原理基本相同,直接调用即可,注意书写的时候每个字母、汉字是占两个大行的,若在第0行书写了汉字或字母,则下次写到下一行的时候,必须传输大行标号2,因为第1大行已经被占用。
字符串显示函数:
void OLED_DISPLAY_8x16_BUFFER(u8 row,u8 *str){
u8 r=0;
while(*str != '\0'){
OLED_DISPLAY_8x16(row,r*8,*str++);
r++;
}
}
函数中定义了变量r=0,然后最多是r=16,每次要写入下一个的时候,r×8,因为无论是汉字还是字母都占用了8列,为了不产生冲突
使用示例:
OLED_DISPLAY_8x16_BUFFER(0," YoungTalk "); //显示字符串
OLED_DISPLAY_8x16_BUFFER(6," Temp:"); //显示字符串
该函数需要注意无论如何传输,传输的字符串的长度不能超过16,可以加空格居中等等。
汉字显示函数:
void OLED_DISPLAY_16x16(u8 x, //显示汉字的页坐标(从0xB0到0xB7)
u8 y, //显示汉字的列坐标(从0到63)
u16 w){ //要显示汉字的编号
u8 j,t,c=0;
for(t=0;t<2;t++){
I2C_SAND_BYTE(OLED0561_ADD,COM,0xb0+x); //页地址(从0xB0到0xB7)
I2C_SAND_BYTE(OLED0561_ADD,COM,y/16+0x10); //起始列地址的高4位
I2C_SAND_BYTE(OLED0561_ADD,COM,y%16); //起始列地址的低4位
for(j=0;j<16;j++){ //整页内容填充
I2C_SAND_BYTE(OLED0561_ADD,DAT,GB_16[(w*32)+c]);
c++;}x++; //页地址加1
}
I2C_SAND_BYTE(OLED0561_ADD,COM,0xAF); //开显示
}
汉字显示函数和字母、数字显示函数使用方法基本相同,其需要注意的地方和前面相同,需要注意的是第二个形参是以16位单位乘的,目的和前面相同,为了汉字不发生重叠,最后一个参数是汉字标号,定义在了.h文件中。
使用示例:
OLED_DISPLAY_16x16(2,2*16,0);//汉字显示 洋桃电子
OLED_DISPLAY_16x16(2,3*16,1);
OLED_DISPLAY_16x16(2,4*16,2);
OLED_DISPLAY_16x16(2,5*16,3);
图像显示函数:
void OLED_DISPLAY_PIC1(void){ //显示全屏图片
u8 m,i;
for(m=0;m<8;m++){//
I2C_SAND_BYTE(OLED0561_ADD,COM,0xb0+m);
I2C_SAND_BYTE(OLED0561_ADD,COM,0x10); //起始列地址的高4位
I2C_SAND_BYTE(OLED0561_ADD,COM,0x02); //起始列地址的低4位
for(i=0;i<128;i++){//送入128次图片显示内容
I2C_SAND_BYTE(OLED0561_ADD,DAT,PIC1[i+m*128]);}
}
}
下面是几个.h头文件:
1、ASCILL表(只有结构,目的是为了符合上述的算法,使表达起来更加清晰)
// ------------------ ASCII字模的数据表 ------------------------ //
// 码表从0x20~0x7e //
// 字库: 纵向取模下高位// (调用时要减512)
// -------------------------------------------------------------- //
uc8 ASCII_8x16[] = { // ASCII
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // - -
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x38,0xFC,0xFC,0x38,0x00,0x00, // -!-
0x00,0x00,0x00,0x0D,0x0D,0x00,0x00,0x00,
0x00,0x0E,0x1E,0x00,0x00,0x1E,0x0E,0x00, // -"-
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x20,0xF8,0xF8,0x20,0xF8,0xF8,0x20,0x00, // -#-
0x02,0x0F,0x0F,0x02,0x0F,0x0F,0x02,0x00,
....
};
2、汉字表:
uc8 GB_16[] = { // 数据表
//"洋",
0x10,0x22,0x64,0x0C,0x80,0x08,0x49,0x4A,
0x4C,0xF8,0x4C,0x4A,0x49,0x08,0x00,0x00,
0x04,0x04,0xFE,0x01,0x04,0x04,0x04,0x04,
0x04,0xFF,0x04,0x04,0x04,0x06,0x04,0x00,
//"桃",
0x10,0x10,0xD0,0xFF,0x50,0x90,0x20,0x40,
0xFF,0x00,0xFF,0x40,0x20,0x30,0x00,0x00,
0x04,0x03,0x00,0xFF,0x80,0x44,0x22,0x19,
0x07,0x00,0x3F,0x41,0x46,0x40,0x70,0x00,
//"电",
0x00,0xF8,0x48,0x48,0x48,0x48,0xFF,0x48,
0x48,0x48,0x48,0xFC,0x08,0x00,0x00,0x00,
0x00,0x07,0x02,0x02,0x02,0x02,0x3F,0x42,
0x42,0x42,0x42,0x47,0x40,0x70,0x00,0x00,
//"子",
0x80,0x80,0x82,0x82,0x82,0x82,0x82,0xE2,
0xA2,0x92,0x8A,0x86,0x80,0xC0,0x80,0x00,
0x00,0x00,0x00,0x00,0x00,0x40,0x80,0x7F,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
3、图片表(不全面)
uc8 PIC1[] = // 数据表
{
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,
......
};
至于这些汉字如何显示是通过取模软件来产生相应的段码,根据我们的算法,我们应该选择纵向8点向下高位,选择合适的格式,将产生的段码直接排列到汉字头文件中后面,排列整齐,根据顺序写出相应的汉字标号即可,至于图片段码的产生,直接上传合适的图片格式(格式正确bmp格式,无灰度等)
取模软件如下图: