OLED模块

目录

一:OLED使用原理

硬件部分

SSD1306框图及引脚定义

选择通信接口

原理图

软件部分

4线SPI的传输时序

 3线SPI的传输时序

I2C的通信时序

执行逻辑框图

二:基本命令表

滚动命令表

寻址设置命令表

硬件配置命令表

时间及驱动命令

初始化过程(内部提供VCC)

三:使用部分

OLED显示汉字

显示图像

照片显示在屏幕上面

制作菜单选择界面

倒置屏幕

把0.96寸的移植到1.3寸的文件下里

四:问题解决

汉字编译出现错误

编码格式的转化

五:代码部分

  OLED写命令

OLED写数据

函数初始化

显示光标位置


一:OLED使用原理

 

 0.96寸----显示原理

        OLED的显存分布情况。我们可以理解为:水平方向分布了128个像素点,垂直方向分布了64个像素点。而驱动芯片在点亮像素点的时候,是以8个像素点为单位的。官方的例程推荐的是垂直扫描的方式,也就是先画垂直方向的8个像素点(如下图所示),所以我们在画点的时候Y的取值为0-7,X的取值为0-127。页是芯片设计者为了方便将同一列的8个点阵编成一组,用一个8bit数表示,这样的8行128个数被称为1页。(一共8页,每页128个字节)

  

硬件部分

SSD1306框图及引脚定义


选择通信接口

设置相应的B0,B1,B2,可以选择我们不同的通信方式。

其他引脚在不同通信协议下的意义:

原理图

I2C:


可以看到B0,B1,B2.满足选择通信接口的要求

SPL接口原理图:

可以看到B0,B1,B2.满足选择通信接口的要求

软件部分

https://mp.csdn.net/mp_blog/creation/editor/138286468icon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/138286468

4线SPI的传输时序

        串行传输只允许写,不允许读。因此,只有两个功能:写命令、写数据

        E和R/W#时钟没用到,接低电平,CS#片选接低电平,表示始终选中此芯片

        D/C#:高电平:数据,低电平:命令

D0:是串行时钟,在每个上升沿时,从机采样数据

D1:数据输入线,时钟线上升沿,数据维持稳定,从机采样数据。一个时钟,只发送一位

 3线SPI的传输时序

D/C:     D/C是借用SDIN引脚指定的,一个时钟,发送一位,但是在每个字节之前,先发送一个位,表示D/C之后,再跟8个位,传输一个字节。      每次传输的一个字节,都有9个位:第一个是D心,指定此字节是命令还是数据,剩下8个,才是真正的字节。

I2C的通信时序

串行传输只允许写,不允许读

CSDN

        Co(连续模式位):Co = 1,每发送一个字节数据前都加一个Control byte(命令和数据可以灵活切换)

        Co = 0,在字节数据前只发送一个Control byte,之后全部都是字节数据

D/C#表示了我们选择写数据还是写命令。

D/C#=1-------写数据。

D/C#=0------写命令

执行逻辑框图


        左上角:128*64bit像素的点阵显示屏,以左上角为原点,向右为x正轴(0~127),向下为y正轴(0~63)

        左下角:128*8Byte的GDDRAM,x轴与点阵显示屏一样,y轴有所不同,8位一组分为一页,范围为PAGE0 ~ PAGE7,共8页。每传输一个字节数据,将其展开,纵向排列(LSB在上,MSB在下),一位控制一个像素点

        每写完一个字节数据后,内部的地址指针自动向右移动一个单位。当写到页的最后一字节时,地址指针默认回到页的起始位置,也可以通过配置寻址模式实现自动换页,换到下一页的开头

        如果想要实现Y坐标的任意指定,需要读取GGDRAM,但串行传输只允许写数据,那需要在程序中定义缓存数组来实现:先读写缓存数组,最后一起更新到屏幕的GDDRAM中

二:基本命令表

滚动命令表

寻址设置命令表

硬件配置命令表

时间及驱动命令

初始化过程(内部提供VCC)

三:使用部分

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "key.h"
#include "exit.h"
#include "UART.h"
#include "OLED.h"
#include "iwdg.h"

int main(void)
{

	HAL_Init();                         /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    delay_init(72);                     /* 延时初始化 */
    LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	Uart_Init(115200);
	
	
//	/*显示一个字符:必须使用‘’符号*/
//	OLED_ShowChar(0,0,'A',OLED_8X16);
//	OLED_ShowChar(0,20,'A',OLED_6X8);

//	/*显示一个字符串*/
//	OLED_ShowString(20,0,"Hello Word!",OLED_8X16);
//	OLED_ShowString(20,20,"Hello Word!",OLED_6X8);

/*--------------------------------------------------------------------------*/	
	/*
	指定长度(Length)>数据长度(Number)------在数据前面补0
	指定长度(Length)<数据长度(Number)------数据的高位丢失
	不要在数据前面加 0,不然会变为8进制
	*/
	
//	/*显示数字的函数*/
//	OLED_ShowNum(0,0,12345,5,OLED_8X16);   //十进制,正整数
//	OLED_ShowSignedNum(48,0,-66,2,OLED_8X16);  //符号数字(十进制,整数)
//	OLED_ShowHexNum(0,20,0xA5A5,4,OLED_8X16);   //十六进制数字(十六进制,正整数)
//	OLED_ShowBinNum(0,40,0XA5A5,16,OLED_8X16); //二进制数字(二进制,正整数)
//	OLED_ShowFloatNum(40,20,81.232,2,3,OLED_8X16);  //浮点数字(十进制,小数)
	

/*-----------------------------------------------------------*/
	/*显示汉字*/
//	OLED_WriteCommand(0x2E);        //关闭滚动
//	OLED_ShowChinese(0,0,"你好,世界。");
	
//	//显示流动汉字
//		OLED_WriteCommand(0x2E);        //关闭滚动
//  OLED_WriteCommand(0x27);        //水平向左或者右滚动 26/27
//  OLED_WriteCommand(0x00);        //虚拟字节
//	OLED_WriteCommand(0x00);        //起始页 0
//	OLED_WriteCommand(0x07);        //滚动时间间隔
//	OLED_WriteCommand(0x07);        //终止页 7
//	OLED_WriteCommand(0x00);        //虚拟字节
//	OLED_WriteCommand(0xFF);        //虚拟字节
//	OLED_ShowChinese(0,0,"你好,世界。");
//	OLED_ShowChinese(0,16,"你好,西安。");
//	OLED_WriteCommand(0x2F);        //开启滚动



/*------------------------------------------------*/
//	/*显示图像*/
//	OLED_ShowImage(0,0,102,64,SA);

//		//显示照片
//		OLED_GetPoint(0,0);
//		
		
		OLED_Update();
		
		
/*-------------------------------------------*/
   //OLED printf函数使用方法和c语言中的使用方法一样
	 //这个没有办法显示汉字
	 //OLED_Printf(0,0,OLED_8X16,"Num1:%05d",123);

/*------------------------绘图函数-------------*/


//	OLED_DrawPoint(0,0);  //点亮一个像素点
//	OLED_DrawPoint(0,1);  //点亮一个像素点
//	OLED_DrawPoint(0,2);  //点亮一个像素点
//	OLED_DrawPoint(0,3);  //点亮一个像素点
//	OLED_DrawPoint(0,4);  //点亮一个像素点
//	OLED_DrawPoint(0,5);  //点亮一个像素点
//	OLED_DrawPoint(0,6);  //点亮一个像素点
//	OLED_DrawPoint(0,7);  //点亮一个像素点
//	OLED_Update();
//	
	
	
	while(1)
	{
	
		

	}
	
}

OLED显示汉字

取模

将这写文字的16进制的代码复制下来,到OLED_Data.c文件的

const ChineseCell_t OLED_CF16x16[] = {}里面去,按照下面的内容。


/*汉字字模数据*********************/

/*相同的汉字只需要定义一次,汉字不分先后顺序*/
/*必须全部为汉字或者全角字符,不要加入任何半角字符*/

/*宽16像素,高16像素*/
const ChineseCell_t OLED_CF16x16[] = {
	
	",",
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x58,0x38,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,0x18,0x24,0x24,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	
	"你",
	0x00,0x80,0x60,0xF8,0x07,0x40,0x20,0x18,0x0F,0x08,0xC8,0x08,0x08,0x28,0x18,0x00,
	0x01,0x00,0x00,0xFF,0x00,0x10,0x0C,0x03,0x40,0x80,0x7F,0x00,0x01,0x06,0x18,0x00,
	
	"好",
	0x10,0x10,0xF0,0x1F,0x10,0xF0,0x00,0x80,0x82,0x82,0xE2,0x92,0x8A,0x86,0x80,0x00,
	0x40,0x22,0x15,0x08,0x16,0x61,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00,
	
	"世",
	0x20,0x20,0x20,0xFE,0x20,0x20,0xFF,0x20,0x20,0x20,0xFF,0x20,0x20,0x20,0x20,0x00,
	0x00,0x00,0x00,0x7F,0x40,0x40,0x47,0x44,0x44,0x44,0x47,0x40,0x40,0x40,0x00,0x00,
	
	"界",
	0x00,0x00,0x00,0xFE,0x92,0x92,0x92,0xFE,0x92,0x92,0x92,0xFE,0x00,0x00,0x00,0x00,
	0x08,0x08,0x04,0x84,0x62,0x1E,0x01,0x00,0x01,0xFE,0x02,0x04,0x04,0x08,0x08,0x00,
	
	/*按照上面的格式,在这个位置加入新的汉字数据*/
	//...
	
	"西",
	0x02,0x02,0xE2,0x22,0x22,0xFE,0x22,0x22,0x22,0xFE,0x22,0x22,0xE2,0x02,0x02,0x00,
	0x00,0x00,0xFF,0x48,0x44,0x43,0x40,0x40,0x40,0x43,0x44,0x44,0xFF,0x00,0x00,0x00,/*",0*/
	"安",
	0x80,0x90,0x8C,0x84,0x84,0x84,0xF5,0x86,0x84,0x84,0x84,0x84,0x94,0x8C,0x80,0x00,
	0x00,0x80,0x80,0x84,0x46,0x49,0x28,0x10,0x10,0x2C,0x23,0x40,0x80,0x00,0x00,0x00,/*1*/

	
	/*未找到指定汉字时显示的默认图形(一个方框,内部一个问号),请确保其位于数组最末尾*/
	"",		
	0xFF,0x01,0x01,0x01,0x31,0x09,0x09,0x09,0x09,0x89,0x71,0x01,0x01,0x01,0x01,0xFF,
	0xFF,0x80,0x80,0x80,0x80,0x80,0x80,0x96,0x81,0x80,0x80,0x80,0x80,0x80,0x80,0xFF,

};

代码: 

OLED_ShowChinese(0,0,"你好。");

汉字流动代码:

OLED显示流动汉字

OLED_WriteCommand(0x2E);        //关闭滚动
OLED_WriteCommand(0x27);        //水平向左或者右滚动 26/27
OLED_WriteCommand(0x00);        //虚拟字节
OLED_WriteCommand(0x00);        //起始页 0
OLED_WriteCommand(0x07);        //滚动时间间隔
OLED_WriteCommand(0x07);        //终止页 7
OLED_WriteCommand(0x00);        //虚拟字节
OLED_WriteCommand(0xFF);        //虚拟字节
OLED_ShowChinese(0,0,"你好,世界。");
OLED_ShowChinese(0,16,"你好,西安。");
OLED_WriteCommand(0x2F);        //开启滚动
OLED_Update();
	

显示图像

和上面的文字取模是一个道理

输入宽x (0~127)          高y (0~63)    范围

然后再面板中画出想要的图像,把16进制文件复制到 OLED_Data.c

	/*显示图像*/
	OLED_ShowImage(0,0,128,64,SA);


	OLED_Update();

照片显示在屏幕上面

取模软件只能打开BMP格式的照片,所以需要使用PS把照片进行处理一下。一般是进行2个操作:调整图片的大小,去调颜色(进行二值化处理)

ps处理图片

1:为了凸显轮廓细节

2:进行二值化

3:改变图像尺寸:

注意宽度和高度的取值范围,单位必须为像素。

4:再次进行二值化(效果更加好)

5:保存图片

保存格式选择BMP格式,取模软件只能识别BMP格式的图片。

这个一般直接默认就欧克。

这个里面我们的PS处理完成,取模和上面的一样。

注意:代码中的宽度和高度必须和我们改变图片的尺寸为一样的。

//	/*显示图像*/
	OLED_ShowImage(0,0,102,64,SA);

		//显示照片
		
		
		OLED_Update();

制作菜单选择界面

函数:

/*显存控制函数*/
void OLED_Clear(void);   清除全部
void OLED_ClearArea(int16_t X, int16_t Y, uint8_t Width, uint8_t Height); 清除部分指定区域
void OLED_Reverse(void);    全部取反
void OLED_ReverseArea(int16_t X, int16_t Y, uint8_t Width, uint8_t Height);  指定区域取反

效果:

	while(1)
	{
	
				
		OLED_ShowString(0,0,"Hello Word!",OLED_8X16);
		OLED_ShowString(0,20,"Hello STM32!",OLED_8X16);
		
		OLED_ReverseArea(0,0,90,16);  //取反
		delay_ms(1500);
		OLED_Update();
		
		
		OLED_ClearArea(0,0,128,16);    //清除指定部分区域
		OLED_ShowString(0,0,"Hello Word!",OLED_8X16);
		OLED_ReverseArea(0,20,93,16);     //取反
		delay_ms(1500);
		OLED_Update();

	}

OLED菜单选择界面

倒置屏幕

如果在有一些的情况下,需要把我们的OLED屏幕反着叉的话,进行下面的操作。

在OLED.C文件下找到OLED_Init()函数:

原本的:

OLED_WriteCommand(0xA1);	//设置左右方向,0xA1正常,0xA0左右反置
	
OLED_WriteCommand(0xC8);	//设置上下方向,0xC8正常,0xC0上下反置

改为:

	
	OLED_WriteCommand(0xA0);	//设置左右方向,0xA1正常,0xA0左右反置
	
	OLED_WriteCommand(0xC0);	//设置上下方向,0xC8正常,0xC0上下反置

显示的东西出现倒置,在把屏幕叉反,显示的东西为正,满足我们的要求。

把0.96寸的移植到1.3寸的文件下里

原来的:

void OLED_SetCursor(uint8_t Page, uint8_t X)
{
	/*如果使用此程序驱动1.3寸的OLED显示屏,则需要解除此注释*/
	/*因为1.3寸的OLED驱动芯片(SH1106)有132列*/
	/*屏幕的起始列接在了第2列,而不是第0列*/
	/*所以需要将X加2,才能正常显示*/
//	X += 2;
	
	/*通过指令设置页地址和列地址*/
	OLED_WriteCommand(0xB0 | Page);					//设置页位置
	OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4));	//设置X位置高4位
	OLED_WriteCommand(0x00 | (X & 0x0F));			//设置X位置低4位
}

取消X+=2的注释,1.3寸的OLED就可以正常使用了

四:问题解决

汉字编译出现错误

使用UTF-8编码可能会出现:

解决方法:

--no-multibyte-chars

开启软件对UTF-8写入汉字写入代码的支持了

编码格式的转化

我们使用不同的编码格式,需要对于的OLED的文件需要转化为对应的格式。

把文件到导入里面,转化为需要的编码格式。

在OLED Data.h文件里面该:

#define OLED_CHN_CHAR_WIDTH			2		UTF-8编码格式给3,GB2312编码格式给2

五:代码部分

我们使用的为l2C 0.96寸的OLED,编码格式为GB2312.

l2C可以参考我们的(I2C的代码不做解释):

https://mp.csdn.net/mp_blog/creation/editor/138002186icon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/138002186

  OLED写命令


  * 函    数:OLED写命令
  * 参    数:Command 要写入的命令值,范围:0x00~0xFF
  返 回 值:无

void OLED_WriteCommand(uint8_t Command)
{
	OLED_I2C_Start();				I2C起始
	OLED_I2C_SendByte(0x78);		发送OLED的I2C从机地址
	OLED_I2C_SendByte(0x00);	    控制字节,给0x00,表示即将写命令
	OLED_I2C_SendByte(Command);		写入指定的命令
	OLED_I2C_Stop();				I2C终止
}

            D/C=1--->写数据;    D/C=0---->写命令。

从机地址:SA0默认为低电平,我们对于OLED是写入(0--->主机给从机发送数据);

0 1 1 1 1 0 0 0=0x78;   如果有多个从机地址重复可以拉高SA改变从机地址。

        按照I2C的通信时序,首先开始i2C的通信,选择OLED的从机地址,接收应答。选择模式有2个(c0为决定,1--->连续模式,0--非连续模式):

(模式1:发送一个命令,应答;在发送一个数据应答,循环往复-----连续模式

模式2:发送一个命令,应答,后面的全部是发送数据,应答。在次模式下,只需要发送一个命令,既可------非连续模式。)

我们选择模式2:0 0 0 0 0 0 0 0=0x00,然后再接收一个从机的应答。这个时候已经进入我们的写命令了,下一个直接发送我们需要写入的命令,再接收一个从机的应答。然后就停止了。

关于代码中没有接收写接收从机应答?

void OLED_I2C_SendByte
{
    .......
    OLED_W_SCL(1);		//额外的一个时钟,不处理应答信号
	OLED_W_SCL(0);
}

再处理完之后,我们加了一个信号,不处理应答。也就不用接收从机的应答了,下面不在解释关于接收从机的问题。

OLED写数据


  * 函    数:OLED写数据
  * 参    数:Data 要写入数据的起始地址
  * 参    数:Count 要写入数据的数量
  * 返 回 值:无
 
void OLED_WriteData(uint8_t *Data, uint8_t Count)
{
	uint8_t i;
	
	OLED_I2C_Start();				I2C起始
	OLED_I2C_SendByte(0x78);		发送OLED的I2C从机地址
	OLED_I2C_SendByte(0x40);	    控制字节,给0x40,表示即将写数据
	循环Count次,进行连续的数据写入
	for (i = 0; i < Count; i ++)

		OLED_I2C_SendByte(Data[i]);	依次发送Data的每一个数据
	}
	OLED_I2C_Stop();				I2C终止
}

前面的和上面一样。0100 0000=0x40表示我们进入的写数据模式。因为进入的是写非连续模式,下面可以一直写数据。

函数初始化

        完全是根据初始化过程(内部提供VCC)下面的表来使用的。

显示光标位置

  * 函    数:OLED设置显示光标位置
  * 参    数:Page 指定光标所在的页,范围:0~7
  * 参    数:X 指定光标所在的X轴坐标,范围:0~127
  * 返 回 值:无
  * 说    明:OLED默认的Y轴,只能8个Bit为一组写入,即1页等于8个Y轴坐标
  
void OLED_SetCursor(uint8_t Page, uint8_t X)
{
	/*如果使用此程序驱动1.3寸的OLED显示屏,则需要解除此注释*/
	/*因为1.3寸的OLED驱动芯片(SH1106)有132列*/
	/*屏幕的起始列接在了第2列,而不是第0列*/
	/*所以需要将X加2,才能正常显示*/
//	X += 2;
	
	/*通过指令设置页地址和列地址*/
	OLED_WriteCommand(0xB0 | Page);				    置页位置
	OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4));	设置X位置高4位
	OLED_WriteCommand(0x00 | (X & 0x0F));			设置X位置低4位
}

y:页的前5个位命令,后3个位为页的地址。(一共8页,一页8个位) 

X: 命令前4位=0000  后面4位表示x的低4位数据。

X:命令前4位=0001 后面4位为x的高8位。因为x的高8位在命令中表示的是,低4为所以,需要左移4个字节。

  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值