吃透OLED显示原理——玩转OLED模块各种使用方法

oled模块有4种工作模式,分别是6800、8080两种并行接口方式、 4线的穿行SPI接口方式、IIC接口方式。通过模块的BS1/BS2设置(通过硬件来设置),BS1/BS2的设置与模块接口模式的关系如表所示:
在这里插入图片描述
这是其中一种工作方式的模块,如图:
在这里插入图片描述
ALIENTEK OLED模块默认设置是BS0接GND,BS1和BS2接VCC(8080模式),如果想要设置成其他的模式,则需要在OLED的背面,用烙铁修改BS0-BS2的设置。(硬件改动)在这里插入图片描述
从原理图中我们可以知道,引出来总共有16个管脚,在16条线中,我们只用了15条,有一个是悬空的。15条线中,电源和地线占了2条,还剩下13条信号线。在不同模式下,我们需要的信号线数量是不同的,在8080模式下,需要全部13条,这其中有一条是共同的,那就是复位线RST(RES),该线我们可以直接接在MCU的复位上(要先确认复位方式一样),这样可以省掉一条线。 而在IIC模式下,仅需要2条线就够了!

8线并行工作模式这里不做介绍,大家可以去参考一下这篇文章https://blog.csdn.net/qq_38410730/article/details/80033873

刚才我们就了解到。iic的工作模式只需要两条线,如图:
在这里插入图片描述
iic的工作模式就是用两根线来模拟iic得到数据,如图:

//-----------------OLED IIC端口定义----------------  					   

#define OLED_SCLK_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_5)//SDA IIC接口的时钟信号
#define OLED_SCLK_Set() GPIO_SetBits(GPIOA,GPIO_Pin_5)

#define OLED_SDIN_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_7)//SCL IIC接口的数据信号
#define OLED_SDIN_Set() GPIO_SetBits(GPIOA,GPIO_Pin_7)

对于模拟iic,大家可以参考一下这篇文章,超详细:【STM32】IIC的基本原理

OLED控制器为SSD1306,也就是说:裸屏由SSD1306驱动,这也是一种较为广泛使用的led驱动芯片。

OLED模块显存

OLED本身是没有显存的,它的显存是依赖于SSD1306提供的。SSD1306的显存总共为128 * 64bit大小,SSD1306将这些显存分为了8页。每页包含了128个字节,总共8页,这样刚好是128*64的点阵大小。
在这里插入图片描述

但是由于OLED不能一次控制一个点阵,只能控制8个点阵;而且是垂直方向扫描控制;如下图;因此垂直方向坐标可选为0~~7;(8*8=64);水平方向可选坐标0~127.

在这里插入图片描述

因为每次写入都是按字节写入的,这就存在一个问题,如果我们使用只写方式操作模块,那么,每次要写8个点,这样,我们在画点的时候,就必须把要设置的点所在的字节的每个位都搞清楚当前的状态(0/1?),否则写入的数据就会覆盖掉之前的状态,结果就是有些不需要显示的点,显示出来了,或者该显示的没有显示了。这个问题在能读的模式下,我们可以先读出来要写入的那个字节,得到当前状况,在修改了要改写的位之后再写进GRAM,这样就不会影响到之前的状况了。但是这样需要能读GRAM,对于3线或4线SPI模式,模块是不支持读的,而且读->改->写的方式速度也比较慢。
所以我们采用的办法是在STM32的内部建立一个OLED的GRAM(共128个字节),在每次修改的时候,只是修改STM32上的GRAM(实际上就是SRAM),在修改完了之后,一次性把STM32上的GRAM写入到OLED的GRAM。当然这个方法也有坏处,就是对于那些SRAM很小的单片机(比如51系列)就比较麻烦了。

//OLED的显存
//存放格式如下.
//[0]0 1 2 3 ... 127	
//[1]0 1 2 3 ... 127	
//[2]0 1 2 3 ... 127	
//[3]0 1 2 3 ... 127	
//[4]0 1 2 3 ... 127	
//[5]0 1 2 3 ... 127	
//[6]0 1 2 3 ... 127	
//[7]0 1 2 3 ... 127 			   
u16 OLED_GRAM[128][8];	 

//更新显存到LCD		 
void OLED_Refresh_Gram(void)
{
	u8 i,n;		    
	for(i=0;i<8;i++)  
	{  
		OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
		OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
		for(n=0;n<128;n++)OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA); 
	}   
}

SSD1306命令

在这里插入图片描述
1:命令0X81:设置对比度。包含两个字节,第一个0X81为命令,随后发送的一个字节为要设置的对比度的值。这个值设置得越大屏幕就越亮。
2:命令0XAE/0XAF:0XAE为关闭显示命令;0XAF为开启显示命令。
3:命令0X8D:包含2个字节,第一个为命令字,第二个为设置值,第二个字节的BIT2表示电荷泵的开关状态,该位为1,则开启电荷泵,为0则关闭。在模块初始化的时候,这个必须要开启,否则是看不到屏幕显示的。
4:命令0XB0~B7:用于设置页地址,其低三位的值对应着GRAM的页地址。
5:命令0X00~0X0F:用于设置显示时的起始列地址低四位。
6:命令0X10~0X1F:用于设置显示时的起始列地址高四位。

更多的命令请参考这个,强烈建议去看,很详细:SSD1306(OLED驱动芯片)指令详解

介绍完工作模式以及驱动芯片,我们可以开始使用这一款iic oled模块

代码详解

#define OLED_CMD  0	//写命令
#define OLED_DATA 1	//写数据

对oled进行初始化

//初始化SSD1306					    
void OLED_Init(void)
{ 	
  	 
 	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	 //使能A端口时钟
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7;	 
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
 	GPIO_Init(GPIOA, &GPIO_InitStructure);	  //初始化GPIO
 	GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_7);	
 
    delay_ms(200);

    OLED_WR_Byte(0xAE,OLED_CMD);//--display off
	OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
	OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
	OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  
	OLED_WR_Byte(0xB0,OLED_CMD);//--set page address
	OLED_WR_Byte(0x81,OLED_CMD); // contract control
	OLED_WR_Byte(0xFF,OLED_CMD);//--128   
	OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap 
	OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverse
	OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
	OLED_WR_Byte(0x3F,OLED_CMD);//--1/32 duty
	OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction
	OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
	OLED_WR_Byte(0x00,OLED_CMD);//
	
	OLED_WR_Byte(0xD5,OLED_CMD);//set osc division
	OLED_WR_Byte(0x80,OLED_CMD);//
	
	OLED_WR_Byte(0xD8,OLED_CMD);//set area color mode off
	OLED_WR_Byte(0x05,OLED_CMD);//
	
	OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge Period
	OLED_WR_Byte(0xF1,OLED_CMD);//
	
	OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartion
	OLED_WR_Byte(0x12,OLED_CMD);//
	
	OLED_WR_Byte(0xDB,OLED_CMD);//set Vcomh
	OLED_WR_Byte(0x30,OLED_CMD);//
	
	OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enable
	OLED_WR_Byte(0x14,OLED_CMD);//
	
	OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
}  

OLED_Clear(); //清屏,每次初始化完成后建议先清理屏幕

//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!	  
void OLED_Clear(void)  
{  
	u8 i,n;		    
	for(i=0;i<8;i++)  
	{  
		OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
		OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
		for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA); 
	} //更新显示
}

在我们平时使用的自模中,有两种常见的取模方式,一个是 6 * 8,另一个则是8 * 16的,第一个说的是在8行6列的矩形表格中取出我们想要的字符,第二个则是在16行8列的矩形表格中取出字符。正如下面代码注释中写的一样,因为oled中每一页只有8个行,所以就需要使用下一页的空间。所以就有了我们平时使用选择的字体大小,当然,这些都是常用的字体大小,我们也可以自己通过字符取模软件制作自己喜欢的字体大小。关于字符取模软件,将在后面讲解。

/* 在指定位置显示一个字符,包括部分字符
	x:0~127
	y:0~63			 
	size:选择字体 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;}  //Max_Column:最大列:128; x:设置列数; y:设置页数
	if(Char_Size ==16)  //此时需要两页的同一列,8*16的点阵
	{
		OLED_Set_Pos(x,y);	 //若 x = y = 2,则设置的为第3页的第3列,  注意:每一页只有八行
		for(i=0;i<8;i++)     
		OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);   //通过i的递增,循环画点,此时将第2页第2列的8行都写入了数据
		OLED_Set_Pos(x,y+1);   //由于画点的数目行数不够,此时需要第3页的第2列来续画点
		for(i=0;i<8;i++)	   
		OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);   //接着画完,直到第16个点结束
	}
	else 
	{	
		OLED_Set_Pos(x,y);  //6*8的点阵,不需要其他的页来续画
		for(i=0;i<6;i++)
		OLED_WR_Byte(F6x8[c][i],OLED_DATA);	  //二维数组,c控制第几行,i控制第几列,故不需要其他的操作即可画完
	}
}

下面的的 if(x>120)并不是错误,因为前面的x+=8;下文的注释中有解释,可以好好想想。

void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size)  //显示字符串
{
	unsigned char j=0;
	while (chr[j]!='\0')  //判断字符串是否结束
	{		
		OLED_ShowChar(x,y,chr[j],Char_Size); // 一个一个画字符
		x+=8;   //x 设置的是列,一个字符的大小为8*16,即行16列8,每次显示为一个后,都需要向高列移8列
		if(x>120){x=0;y+=2;} // 最高为128列,超过的话则需要重新从零列开始,由于此时需要别的页数来续画,避免重叠,需要 y += 2。
		j++; //循环画字符串
	}
}

显示2个数字,具体都在下面的代码中写出,需要注意的是,下面的 " " 表示的是ASCII值32

//m^n函数
u32 oled_pow(u8 m,u8 n)
{
	u32 result=1;	 
	while(n--)result*=m;    
	return result;
}			

//显示2个数字
//x,y :起点坐标	 
//len :数字的位数
//size:字体大小
//mode:模式	0,填充模式;1,叠加模式
//num:数值(0~4294967295);	 		  
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2)
{         	
	u8 t,temp;
	u8 enshow=0;						   
	for(t=0;t<len;t++)
	{
		temp=(num/oled_pow(10,len-t-1))%10;
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
				OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
				continue;
			}else enshow=1; 
		 	 
		}
	 	OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2); 
	}
} 

上面的几个都是我们平时最为基本的用法,有些学习者想要用它来完成更加不一样的操作,下面便有,介绍之前,先来介绍一下我们常用的取模软件

PCtoLCD2002

界面如下!
在这里插入图片描述
我们在用的时候先打开左上角的文件,进行新建。输入我们的宽高,6 * 8或者8 * 16都是按照这个来取模的,可以自己设定大小。在正上角的地方有一个齿轮一样的东西,我们在设定好大小之后便需要打开它。如图:

在这里插入图片描述在这里插入图片描述
把上面的都做好之后就可以画自己想要的东西了。因为oled是128 * 64,所以我们最大的大小就是这个,我们可以在128 * 64上写字,画图,等等,出来的就是一整个画面,这也是满屏的一种方式,后面还有一种取模软件,取得是图片,比如一些动漫人物。

介绍完取模软件,我们便可以继续我们的操作了!

1:画直线
通常我们使用如下图中一样的点想画直线时总是得到一个个点,这是因为我们一般使用的字符大小都是6 * 8或者8 * 16,里面的点大小并不是充满整个矩形的(上面有解释)我们需要做的便是打开我们的字符软件,把点改大一点便可!
在这里插入图片描述
2:显示图片(比如一些动漫人物)

先上图
在这里插入图片描述这个跟上面的差不多,各有千秋!
篇幅感觉有点长了。还有更多的玩法,下次更新,也欢迎介绍给我,私信即可!如有错误感谢指出,共同学习。
两个软件在百度都有。

版权声明:本文为CSDN博主「windsuifeng」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43872149/article/details/104712248

oled模块有4种工作模式,分别是6800、8080两种并行接口方式、 4线的穿行SPI接口方式、IIC接口方式。通过模块的BS1/BS2设置(通过硬件来设置),BS1/BS2的设置与模块接口模式的关系如表所示:
在这里插入图片描述
这是其中一种工作方式的模块,如图:
在这里插入图片描述
ALIENTEK OLED模块默认设置是BS0接GND,BS1和BS2接VCC(8080模式),如果想要设置成其他的模式,则需要在OLED的背面,用烙铁修改BS0-BS2的设置。(硬件改动)在这里插入图片描述
从原理图中我们可以知道,引出来总共有16个管脚,在16条线中,我们只用了15条,有一个是悬空的。15条线中,电源和地线占了2条,还剩下13条信号线。在不同模式下,我们需要的信号线数量是不同的,在8080模式下,需要全部13条,这其中有一条是共同的,那就是复位线RST(RES),该线我们可以直接接在MCU的复位上(要先确认复位方式一样),这样可以省掉一条线。 而在IIC模式下,仅需要2条线就够了!

8线并行工作模式这里不做介绍,大家可以去参考一下这篇文章https://blog.csdn.net/qq_38410730/article/details/80033873

刚才我们就了解到。iic的工作模式只需要两条线,如图:
在这里插入图片描述
iic的工作模式就是用两根线来模拟iic得到数据,如图:

//-----------------OLED IIC端口定义----------------  					   

#define OLED_SCLK_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_5)//SDA IIC接口的时钟信号
#define OLED_SCLK_Set() GPIO_SetBits(GPIOA,GPIO_Pin_5)

#define OLED_SDIN_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_7)//SCL IIC接口的数据信号
#define OLED_SDIN_Set() GPIO_SetBits(GPIOA,GPIO_Pin_7)

对于模拟iic,大家可以参考一下这篇文章,超详细:【STM32】IIC的基本原理

OLED控制器为SSD1306,也就是说:裸屏由SSD1306驱动,这也是一种较为广泛使用的led驱动芯片。

OLED模块显存

OLED本身是没有显存的,它的显存是依赖于SSD1306提供的。SSD1306的显存总共为128 * 64bit大小,SSD1306将这些显存分为了8页。每页包含了128个字节,总共8页,这样刚好是128*64的点阵大小。
在这里插入图片描述

但是由于OLED不能一次控制一个点阵,只能控制8个点阵;而且是垂直方向扫描控制;如下图;因此垂直方向坐标可选为0~~7;(8*8=64);水平方向可选坐标0~127.

在这里插入图片描述

因为每次写入都是按字节写入的,这就存在一个问题,如果我们使用只写方式操作模块,那么,每次要写8个点,这样,我们在画点的时候,就必须把要设置的点所在的字节的每个位都搞清楚当前的状态(0/1?),否则写入的数据就会覆盖掉之前的状态,结果就是有些不需要显示的点,显示出来了,或者该显示的没有显示了。这个问题在能读的模式下,我们可以先读出来要写入的那个字节,得到当前状况,在修改了要改写的位之后再写进GRAM,这样就不会影响到之前的状况了。但是这样需要能读GRAM,对于3线或4线SPI模式,模块是不支持读的,而且读->改->写的方式速度也比较慢。
所以我们采用的办法是在STM32的内部建立一个OLED的GRAM(共128个字节),在每次修改的时候,只是修改STM32上的GRAM(实际上就是SRAM),在修改完了之后,一次性把STM32上的GRAM写入到OLED的GRAM。当然这个方法也有坏处,就是对于那些SRAM很小的单片机(比如51系列)就比较麻烦了。

//OLED的显存
//存放格式如下.
//[0]0 1 2 3 ... 127	
//[1]0 1 2 3 ... 127	
//[2]0 1 2 3 ... 127	
//[3]0 1 2 3 ... 127	
//[4]0 1 2 3 ... 127	
//[5]0 1 2 3 ... 127	
//[6]0 1 2 3 ... 127	
//[7]0 1 2 3 ... 127 			   
u16 OLED_GRAM[128][8];	 

//更新显存到LCD		 
void OLED_Refresh_Gram(void)
{
	u8 i,n;		    
	for(i=0;i<8;i++)  
	{  
		OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
		OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
		for(n=0;n<128;n++)OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA); 
	}   
}

SSD1306命令

在这里插入图片描述
1:命令0X81:设置对比度。包含两个字节,第一个0X81为命令,随后发送的一个字节为要设置的对比度的值。这个值设置得越大屏幕就越亮。
2:命令0XAE/0XAF:0XAE为关闭显示命令;0XAF为开启显示命令。
3:命令0X8D:包含2个字节,第一个为命令字,第二个为设置值,第二个字节的BIT2表示电荷泵的开关状态,该位为1,则开启电荷泵,为0则关闭。在模块初始化的时候,这个必须要开启,否则是看不到屏幕显示的。
4:命令0XB0~B7:用于设置页地址,其低三位的值对应着GRAM的页地址。
5:命令0X00~0X0F:用于设置显示时的起始列地址低四位。
6:命令0X10~0X1F:用于设置显示时的起始列地址高四位。

更多的命令请参考这个,强烈建议去看,很详细:SSD1306(OLED驱动芯片)指令详解

介绍完工作模式以及驱动芯片,我们可以开始使用这一款iic oled模块

代码详解

#define OLED_CMD  0	//写命令
#define OLED_DATA 1	//写数据

对oled进行初始化

//初始化SSD1306					    
void OLED_Init(void)
{ 	
  	 
 	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	 //使能A端口时钟
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7;	 
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
 	GPIO_Init(GPIOA, &GPIO_InitStructure);	  //初始化GPIO
 	GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_7);	
 
    delay_ms(200);

    OLED_WR_Byte(0xAE,OLED_CMD);//--display off
	OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
	OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
	OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  
	OLED_WR_Byte(0xB0,OLED_CMD);//--set page address
	OLED_WR_Byte(0x81,OLED_CMD); // contract control
	OLED_WR_Byte(0xFF,OLED_CMD);//--128   
	OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap 
	OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverse
	OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
	OLED_WR_Byte(0x3F,OLED_CMD);//--1/32 duty
	OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction
	OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
	OLED_WR_Byte(0x00,OLED_CMD);//
	
	OLED_WR_Byte(0xD5,OLED_CMD);//set osc division
	OLED_WR_Byte(0x80,OLED_CMD);//
	
	OLED_WR_Byte(0xD8,OLED_CMD);//set area color mode off
	OLED_WR_Byte(0x05,OLED_CMD);//
	
	OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge Period
	OLED_WR_Byte(0xF1,OLED_CMD);//
	
	OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartion
	OLED_WR_Byte(0x12,OLED_CMD);//
	
	OLED_WR_Byte(0xDB,OLED_CMD);//set Vcomh
	OLED_WR_Byte(0x30,OLED_CMD);//
	
	OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enable
	OLED_WR_Byte(0x14,OLED_CMD);//
	
	OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
}  

OLED_Clear(); //清屏,每次初始化完成后建议先清理屏幕

//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!	  
void OLED_Clear(void)  
{  
	u8 i,n;		    
	for(i=0;i<8;i++)  
	{  
		OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
		OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
		for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA); 
	} //更新显示
}

在我们平时使用的自模中,有两种常见的取模方式,一个是 6 * 8,另一个则是8 * 16的,第一个说的是在8行6列的矩形表格中取出我们想要的字符,第二个则是在16行8列的矩形表格中取出字符。正如下面代码注释中写的一样,因为oled中每一页只有8个行,所以就需要使用下一页的空间。所以就有了我们平时使用选择的字体大小,当然,这些都是常用的字体大小,我们也可以自己通过字符取模软件制作自己喜欢的字体大小。关于字符取模软件,将在后面讲解。

/* 在指定位置显示一个字符,包括部分字符
	x:0~127
	y:0~63			 
	size:选择字体 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;}  //Max_Column:最大列:128; x:设置列数; y:设置页数
	if(Char_Size ==16)  //此时需要两页的同一列,8*16的点阵
	{
		OLED_Set_Pos(x,y);	 //若 x = y = 2,则设置的为第3页的第3列,  注意:每一页只有八行
		for(i=0;i<8;i++)     
		OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);   //通过i的递增,循环画点,此时将第2页第2列的8行都写入了数据
		OLED_Set_Pos(x,y+1);   //由于画点的数目行数不够,此时需要第3页的第2列来续画点
		for(i=0;i<8;i++)	   
		OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);   //接着画完,直到第16个点结束
	}
	else 
	{	
		OLED_Set_Pos(x,y);  //6*8的点阵,不需要其他的页来续画
		for(i=0;i<6;i++)
		OLED_WR_Byte(F6x8[c][i],OLED_DATA);	  //二维数组,c控制第几行,i控制第几列,故不需要其他的操作即可画完
	}
}

下面的的 if(x>120)并不是错误,因为前面的x+=8;下文的注释中有解释,可以好好想想。

void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size)  //显示字符串
{
	unsigned char j=0;
	while (chr[j]!='\0')  //判断字符串是否结束
	{		
		OLED_ShowChar(x,y,chr[j],Char_Size); // 一个一个画字符
		x+=8;   //x 设置的是列,一个字符的大小为8*16,即行16列8,每次显示为一个后,都需要向高列移8列
		if(x>120){x=0;y+=2;} // 最高为128列,超过的话则需要重新从零列开始,由于此时需要别的页数来续画,避免重叠,需要 y += 2。
		j++; //循环画字符串
	}
}

显示2个数字,具体都在下面的代码中写出,需要注意的是,下面的 " " 表示的是ASCII值32

//m^n函数
u32 oled_pow(u8 m,u8 n)
{
	u32 result=1;	 
	while(n--)result*=m;    
	return result;
}			

//显示2个数字
//x,y :起点坐标	 
//len :数字的位数
//size:字体大小
//mode:模式	0,填充模式;1,叠加模式
//num:数值(0~4294967295);	 		  
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2)
{         	
	u8 t,temp;
	u8 enshow=0;						   
	for(t=0;t<len;t++)
	{
		temp=(num/oled_pow(10,len-t-1))%10;
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
				OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
				continue;
			}else enshow=1; 
		 	 
		}
	 	OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2); 
	}
} 

上面的几个都是我们平时最为基本的用法,有些学习者想要用它来完成更加不一样的操作,下面便有,介绍之前,先来介绍一下我们常用的取模软件

PCtoLCD2002

界面如下!
在这里插入图片描述
我们在用的时候先打开左上角的文件,进行新建。输入我们的宽高,6 * 8或者8 * 16都是按照这个来取模的,可以自己设定大小。在正上角的地方有一个齿轮一样的东西,我们在设定好大小之后便需要打开它。如图:

在这里插入图片描述在这里插入图片描述
把上面的都做好之后就可以画自己想要的东西了。因为oled是128 * 64,所以我们最大的大小就是这个,我们可以在128 * 64上写字,画图,等等,出来的就是一整个画面,这也是满屏的一种方式,后面还有一种取模软件,取得是图片,比如一些动漫人物。

介绍完取模软件,我们便可以继续我们的操作了!

1:画直线
通常我们使用如下图中一样的点想画直线时总是得到一个个点,这是因为我们一般使用的字符大小都是6 * 8或者8 * 16,里面的点大小并不是充满整个矩形的(上面有解释)我们需要做的便是打开我们的字符软件,把点改大一点便可!
在这里插入图片描述
2:显示图片(比如一些动漫人物)

先上图
在这里插入图片描述这个跟上面的差不多,各有千秋!
篇幅感觉有点长了。还有更多的玩法,下次更新,也欢迎介绍给我,私信即可!如有错误感谢指出,共同学习。
两个软件在百度都有。

版权声明:本文为CSDN博主「windsuifeng」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43872149/article/details/104712248

生成海报
点赞 0

windsuifeng

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

OV7670摄像头模块资料

OV7670摄像头模块资料 一、实物图和原理图 二、模块简介 OV7670 是 OV( OmniVision)公司生产的 CMOS VGA 图像传感器。该传感器体积小、工作电压低,提供单片 VGA

基于STM32的指纹密码锁

设计简介: 本设计是基于单片机的指纹密码锁,主要实现以下功能: 矩阵按键输入密码,并通过按键显示*号可通过按键或手机开门密码可通过按键进行开门可通过蓝牙模块连接手机进行开门可通过指纹进