关于0.96OLED的显示过程详解(I2C通信方式)

一. 关于OLED显示屏的介绍

通常我们所用的OLED屏有白色、蓝色、黄蓝双色等几种;屏的大小为0.96寸,像素点为128*64,所以我们也称之为0.96OLED屏或者12864屏。

内部驱动IC为SSD1306;通信方式一般为SPI或者I2C。如下图所示,配置哪种模式主要是根据BS0、BS1和BS2这三个管脚的电平逻辑来的。

关于0.96OLED的显示过程详解(I2C通信方式)_第1张图片

二. I2C通信地址与通信过程

         

如手册上关于I2C地址的描述,根据DC引脚电平的不同,地址为,0111100和0111101两种,通常我们设置DC引脚接地,所以作为I2C从机的七位地址为0111100;又因为我们与驱动IC交互时,都是主机发送命令或者数据到IC,也就是只有写数据,没有读数据,所以从机地址为0x78。

关于0.96OLED的显示过程详解(I2C通信方式)_第2张图片

通信方式如上图所示:先发送从机地址,再发送命令字节,接着发送数据字节。注意每次主机要等待从机的应答。下图为写命令和写数据的代码示例。

/**********************************************
// IIC Write Command
**********************************************/
void Write_IIC_Command(unsigned char IIC_Command)
{
   IIC_Start();
   Write_IIC_Byte(0x78);            //Slave address,SA0=0
   IIC_Wait_Ack();
   Write_IIC_Byte(0x00);	       //write command
   IIC_Wait_Ack();
   Write_IIC_Byte(IIC_Command);
   IIC_Wait_Ack();
   IIC_Stop();
}
/**********************************************
// IIC Write Data
**********************************************/
void Write_IIC_Data(unsigned char IIC_Data)
{
   IIC_Start();
   Write_IIC_Byte(0x78);			//D/C#=0; R/W#=0
   IIC_Wait_Ack();
   Write_IIC_Byte(0x40);			//write data
   IIC_Wait_Ack();
   Write_IIC_Byte(IIC_Data);
   IIC_Wait_Ack();
   IIC_Stop();
}

 

三. 显示原理与取模方式

先来看关于OLED的显存分布情况。我们可以理解为:水平方向分布了128个像素点,垂直方向分布了64个像素点(如图一所示)。而驱动芯片在点亮像素点的时候,是以8个像素点为单位的。官方的例程推荐的是垂直扫描的方式,也就是先画垂直方向的8个像素点(如下图二所示),所以我们在画点的时候Y的取值为0-7,X的取值为0-127. 

//存放格式如下.
//[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 
关于0.96OLED的显示过程详解(I2C通信方式)_第3张图片 图一 图二

理解了OLED的显示方式,那么取模就很简单了,根据上面的情况,我们选择列行式的取模方式,如下图所示。

关于0.96OLED的显示过程详解(I2C通信方式)_第4张图片

取模完成,我们再来看看画点的算法。其实就是根据取模的方式按顺序画点,先画Y方向的八个点,再画X方向的128个点。以显示汉字为例,来分析一下

/***************************************************************
X:X坐标 Y:Y方向的页数  no:取模的汉字的序号

你(0) 好(1)

{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},/*"你",0*/

{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},/*"好",1*/

****************************************************************/
void tt_Oled_ShowChinese(unsigned char x,unsigned char y,unsigned char no)
{      			    
    UINT8 t;

    tt_Oled_Set_Pos(x,y);	
    for(t=0;t<16;t++){
        tt_Oled_WR_Byte(dis_word[2*no][t],OLED_DATA);
    }	
    tt_Oled_Set_Pos(x,y+1);
    for(t=0;t<16;t++){	
        tt_Oled_WR_Byte(dis_word[2*no+1][t],OLED_DATA);
    }					
}

因为我们的汉字大小是16*16的,所以会占两页,按照上面的分析,先画的是第一页(16*8个点),对应tt_Oled_WR_Byte(dis_word[2*no][t],OLED_DATA);,接着画第二页(16*8个点))tt_Oled_WR_Byte(dis_word[2*no][t],OLED_DATA);这样画完后我们就完成了一个汉字的显示(16*16)。怎么样,是不是很简单?

四. 给显示增加一点花样

网上关于OLED的显示例程很多,基本都大同小异,一般选一个移植,再根据我上面的设置,显示字符、汉字甚至图片都是没有问题的。但是我们这些显示都是静态的,那怎么显示动态的呢?例如水平滚动,垂直滚动,斜向滚动等等。其实这些本质上都是画点的顺序不同而已,我们先来看看手册上的描述,如下图

关于0.96OLED的显示过程详解(I2C通信方式)_第5张图片 垂直和水平滚动显示设置 关于0.96OLED的显示过程详解(I2C通信方式)_第6张图片 垂直和水平滚动显示设置举例

 根据手册我们知道,设置2A(向左滚动)和29(向右滚动)以及之后的五个数,就可以设置水平和垂直滚动的效果了。需要注意的是设置前需要先关滚动,当需要显示的内容刷新好之后再开启滚动。以下是我代码的设置:

    //以下添加水平滚动效果
    tt_Oled_WR_Byte(0x2e,OLED_CMD);//关滚动
    tt_Oled_WR_Byte(0x2A,OLED_CMD);//29向右,2a向左
    tt_Oled_WR_Byte(0x00,OLED_CMD);//A:空字节
    tt_Oled_WR_Byte(0x00,OLED_CMD);//B:水平起始页
    tt_Oled_WR_Byte(0x00,OLED_CMD);//C:水平滚动速度
    tt_Oled_WR_Byte(0x01,OLED_CMD);//D:水平结束页
    tt_Oled_WR_Byte(0x00,OLED_CMD);//E:每次垂直滚动位移
	//tt_Oled_WR_Byte(0x2f,OLED_CMD);//开滚动

备注:1. 本文章是个人总结,如有不足之处欢迎指正;

            2. 部分参考内容来源于手册和网络,如有侵权请联系我删除。

 

你可能感兴趣的:(随笔记录)