这篇文章概括介绍了SSD1306屏幕驱动芯片的基本使用方法1.1。 SSD1306是驱动128 * 64像素OLED的屏幕驱动芯片。 内置于SSD1306的对比度调整功能,显示RAM和振荡器,在简化外围电路的同时降低功耗。 有256个等级的亮度调节。 芯片可以通过并行通信6800/8000、串行通信I2C、SPI等多种方式进行通信。 本文介绍如何使用I2C串行协议与SSD1306进行通信。
图1-1
1.2硬件设计参考
表1-2
该表说明了应该如何使用不同的通信协议进行布线。 如果我们买来的是模块(见图1-1 ),商家已经为你安装了所有的硬件电路,所以不用担心。 但是,如果自行设计电路,请参阅(表1-2 ),更多参数请参阅SSD1306官方数据手册。
2.1 I2C协议概述本部分知识提供给不了解I2C知识的学生,已经掌握的学生请跳过本部分。
I2C协议是控制器和芯片之间的通信协议,如果主板是Arduino,则控制器是你的Arduino,芯片是SSD1306。 如果你使用的是单片机,单片机就是控制器。 I2C协议需要用于两根数据线,不可缺少。 (图1-1 )可以看出,这两条线分别是SCL和SDA,其中SCL用于提供时钟信号,并且所有信号的变化和采样节奏均服从SCL的指挥。 SDA是双向传输数据线,所有数据都通过这一条线传输,一次只能传输单向数据,不能在两侧同时发送。
2.2协议的详细信息是控制器通过向SSD1306发送字节来控制和发送数据,因此需要了解标准I2C协议如何定义字节发送规范。 SSD1306是控制器发送了控制命令,还是显示RAM数据将在后面叙述。
图2-1
图2-1显示了单片机向SSD1306发送1字节数据的完整过程。 值得注意的是,SCL的高低等级由控制器(即Arduino/单片机)控制。 也就是说,数据发送的节奏由控制器决定,所以可以通过编程控制器控制该节奏。 图2-1中的黑色细长竖线表示这是一个重要动作,下面的黑色数字表示这是第几步。 从第一步到第一步,SCL和SDA都处于高电平,根据I2C协议的规定,这是空闲的,没有数据传输。 在第1步中,SCL处于高电平,控制器控制SDA引脚处于低电平。 这是开始信号,告诉SSD1306“开始发送”。 请注意。 从现在开始,SCL为高电平时,SDA不能变更。 只有在SCL为低电平时,SDA才能更改。 SCL为高电平时,如果SDA发生变更,SSD1306会将其识别为开始位或结束位,从而引起传输错误。 简单地说,如果SCL为‘0’,SDA就可以写它的工作。 如果SCL为’1’,则工作为
I2C将字节的发送顺序规定为从上到下,因此从图中可以看到,控制器向SSD1306发送了二进制11010010。 发送数据后,SSD1306必须发送“0”,指示已接收到数据。 在图中的步骤10中,SCL处于低电平,表示SDA可以更改。 请在这里注意区分。 SDA由SSD1306决定,同时控制器的SDA端子进入读取状态。 表示响应完成且SCL上升时,已向控制器提交SSD1306个“0”响应位。 最后需要另一个终止信号,当步骤11和SCL为高电平时,控制器将SDA从“0”改变为“1”,以指示传输完成。 然后,SCL和SDA都处于高电平,表示空闲,在下一个启动信号之前没有数据发送。
2.3我知道指令和数据如何发送一个字节,我该怎么控制SSD1306? 这个字节可以是指令也可以是数据,那么SSD1306如何识别这是指令还是数据呢? 首先考虑一下什么是命令,什么是数据。 要使用此屏幕,需要设置亮度、显示坐标、扫描方法等,并且需要发送命令格式。如果要控制像素点的闪烁,请发送数据格式。
2.4传输格式上述是标准的1字节I2C协议,但使用I2C协议的芯片根据实际需要定义格式,不换药,本质相同。 根据数据手册,SSD1306的格式如下。
图2-
2
从最左边看起,先发送一个S(开始信号),然后发送7位地址位+1位(读1/写0),7+1可以先用程序组合好,变成一字节,然后发送;接着是ACK(应答),注意应答之后没有停止位,这是SSD1306规定的格式,紧接着发控制字节,然后应答;再然后发真正的1字节指令/数据,然后应答,最后停止位P。
这里解释下为什么要发送7位地址位,因为控制器的SCL和SDA引脚是可以连接多个器件的,比如连接两块功能不同的I2C协议的芯片,两块芯片怎么知道控制器是不是在找自己呢?这就需要地址来实现了,控制器发了7位地址,两块I2C芯片会将自己的地址跟它比对,一样的话就会发出应答并继续之后的通信,如果不一样,说明控制器找的不是自己,就忽略它,SSD1306的地址通常是0111100,也可能0111101。1位读写位通常设为0,因为主要是控制它显示,不需要读数据。
控制字节的格式在图2-2的右下角,Co设为‘0’即可,D/C是个重要的位,决定着后面1字节是显示数据还是指令,设为‘1’数据,‘0’指令。
3.1 显示原理
图3-1
图3-2
一块128 * 64的屏幕按图3-1进行划分成8页,编号0-7;128列,0-127。关注Page 2的某一列,是从上到下8个像素,这里对应着一字节数据的8位,写进显示RAM的数据直接控制着像素点的亮灭。根据图3-2,需关注的是最上面的像素对应的是写进显示RAM那个字节的最低位(LSB),最下面的像素对应的是最高位(MSB)。
本文介绍的寻址方式是页寻址。在页寻址模式下,发送指令设置好页和列坐标后,写入1字节显示RAM数据后,列坐标会自动加1,写到本Page的最后一列后,列坐标回到开头,而页坐标不变。要在其他页写数据,需要重新设置页和列坐标。
3.2 指令
表3-3
注意设置对比度是双字节指令,即需要完成两个图2-2的完整过程,第一次发送指令格式的10000001,告诉SSD1306我要设置的是对比度;第二次发送数据格式的0-255之间的数,设为你想要的对比度。
表3-4
八位的列坐标拆成高四位和低四位分别发送,寻址模式设置位页寻址,即A1A0为’10’,最下面的指令是设置列显示范围,可不进行设置,默认0-127
表3-5
最上面的指令是设置页显示范围,可不进行设置,默认0-7。
4.1 代码实现
本实验用的控制器是单片机STC89C52RC,屏幕是0.96寸的128 * 64像素OLED屏幕,参考代码如下。由于字库代码比较大,不便上传。这个字库也可以自行制作,用一个字体取模软件可以很方便地生成16进制代码,文章结尾提供该软件。
//’I2C.h’#include<reg52.h>sbit SCL = P1^3;sbit SDA = P1^2;void I2C_START(){ //开始信号SCL = 1;SDA = 1;SDA = 0;SCL = 0;}void I2C_WriteByte(unsigned char DATA){ //传输一字节unsigned char i = 0;while(i++ < 8){SCL = 0;SDA = DATA & 0x80;SCL = 1;DATA <<= 1;}SCL = 0;SDA = 1;SCL = 1;SCL = 0;}void I2C_STOP(){ //结束信号SDA = 0;SCL = 1;SDA = 1;} #include”I2C.h”#include”codelib.h”#define SlaveAddress_W 0x78void I2C_WriteCMD(unsigned char CMD){ //写指令I2C_START();I2C_WriteByte(SlaveAddress_W);I2C_WriteByte(0x00);I2C_WriteByte(CMD);I2C_STOP();}void I2C_WriteDATA(unsigned char DATA){ //写数据I2C_START();I2C_WriteByte(SlaveAddress_W);I2C_WriteByte(0x40);I2C_WriteByte(DATA);I2C_STOP();}void SSD_Init(){ //初始化设置I2C_WriteCMD(0xae);I2C_WriteCMD(0x00);I2C_WriteCMD(0x10);I2C_WriteCMD(0x40);I2C_WriteCMD(0x81);I2C_WriteCMD(0xcf);I2C_WriteCMD(0xa1);I2C_WriteCMD(0xc8);I2C_WriteCMD(0xa6);I2C_WriteCMD(0xa8);I2C_WriteCMD(0x3f);I2C_WriteCMD(0xd3);I2C_WriteCMD(0x00);I2C_WriteCMD(0xd5);I2C_WriteCMD(0x80);I2C_WriteCMD(0xd9);I2C_WriteCMD(0xf1);I2C_WriteCMD(0xda);I2C_WriteCMD(0x12);I2C_WriteCMD(0xdb);I2C_WriteCMD(0x40);I2C_WriteCMD(0x20); //设置页寻址I2C_WriteCMD(0x02);I2C_WriteCMD(0x8d);I2C_WriteCMD(0x14);I2C_WriteCMD(0xa4);I2C_WriteCMD(0xa6);I2C_WriteCMD(0xaf);}void SSD_Clear(){ //清空屏幕unsigned int x = 0;unsigned char y = 0;while(y < 8){I2C_WriteCMD(0x00);I2C_WriteCMD(0x10);I2C_WriteCMD(0xb0 + y);x = 0;while(x++ < 128)I2C_WriteDATA(0x00);y++;}}void SSD_displaystr(unsigned char x,y,unsigned char str[]){ //显示字符串,x为0~127,y为0~7,只能在同一页,不可超出长度unsigned char xcmd_H,xcmd_L,ycmd;unsigned char *p;p = str;xcmd_H = (x >> 4) + 0x10;xcmd_L = x & 0x0f;ycmd = 0xb0 + y;I2C_WriteCMD(xcmd_H);I2C_WriteCMD(xcmd_L);I2C_WriteCMD(ycmd);while(*p != ‘\0’){unsigned char i = 0;while(i < 8){I2C_WriteDATA(ASCIIcode[(*p) – 32][i]);i++;}p++;}I2C_WriteCMD(ycmd + 1);I2C_WriteCMD(xcmd_H);I2C_WriteCMD(xcmd_L);p = str;while(*p != ‘\0’){unsigned char i = 8;while(i < 16){I2C_WriteDATA(ASCIIcode[(*p) – 32][i]);i++;}p++;}} #include “SSD1306.h”void main(){SSD_Init();SSD_Clear();SSD_displaystr(0,0,”hello”);while(1);} 4.2 提供资源
SSD1306芯片数据手册
提取码:dthg
字体取模软件
提取码:dthg
快三大小单双稳赚买法二次发送数据格式的0-255之间的数,设为你想要的对比度。
表3-4
八位的列坐标拆成高四位和低四位分别发送,寻址模式设置位页寻址,即A1A0为’10’,最下面的指令是设置列显示范围,可不进行设置,默认0-127
表3-5
最上面的指令是设置页显示范围,可不进行设置,默认0-7。
4.1 代码实现
本实验用的控制器是单片机STC89C52RC,屏幕是0.96寸的128 * 64像素OLED屏幕,参考代码如下。由于字库代码比较大,不便上传。这个字库也可以自行制作,用一个字体取模软件可以很方便地生成16进制代码,文章结尾提供该软件。
//’I2C.h’#include<reg52.h>sbit SCL = P1^3;sbit SDA = P1^2;void I2C_START(){ //开始信号SCL = 1;SDA = 1;SDA = 0;SCL = 0;}void I2C_WriteByte(unsigned char DATA){ //传输一字节unsigned char i = 0;while(i++ < 8){SCL = 0;SDA = DATA & 0x80;SCL = 1;DATA <<= 1;}SCL = 0;SDA = 1;SCL = 1;SCL = 0;}void I2C_STOP(){ //结束信号SDA = 0;SCL = 1;SDA = 1;} #include”I2C.h”#include”codelib.h”#define SlaveAddress_W 0x78void I2C_WriteCMD(unsigned char CMD){ //写指令I2C_START();I2C_WriteByte(SlaveAddress_W);I2C_WriteByte(0x00);I2C_WriteByte(CMD);I2C_STOP();}void I2C_WriteDATA(unsigned char DATA){ //写数据I2C_START();I2C_WriteByte(SlaveAddress_W);I2C_WriteByte(0x40);I2C_WriteByte(DATA);I2C_STOP();}void SSD_Init(){ //初始化设置I2C_WriteCMD(0xae);I2C_WriteCMD(0x00);I2C_WriteCMD(0x10);I2C_WriteCMD(0x40);I2C_WriteCMD(0x81);I2C_WriteCMD(0xcf);I2C_WriteCMD(0xa1);I2C_WriteCMD(0xc8);I2C_WriteCMD(0xa6);I2C_WriteCMD(0xa8);I2C_WriteCMD(0x3f);I2C_WriteCMD(0xd3);I2C_WriteCMD(0x00);I2C_WriteCMD(0xd5);I2C_WriteCMD(0x80);I2C_WriteCMD(0xd9);I2C_WriteCMD(0xf1);I2C_WriteCMD(0xda);I2C_WriteCMD(0x12);I2C_WriteCMD(0xdb);I2C_WriteCMD(0x40);I2C_WriteCMD(0x20); //设置页寻址I2C_WriteCMD(0x02);I2C_WriteCMD(0x8d);I2C_WriteCMD(0x14);I2C_WriteCMD(0xa4);I2C_WriteCMD(0xa6);I2C_WriteCMD(0xaf);}void SSD_Clear(){ //清空屏幕unsigned int x = 0;unsigned char y = 0;while(y < 8){I2C_WriteCMD(0x00);I2C_WriteCMD(0x10);I2C_WriteCMD(0xb0 + y);x = 0;while(x++ < 128)I2C_WriteDATA(0x00);y++;}}void SSD_displaystr(unsigned char x,y,unsigned char str[]){ //显示字符串,x为0~127,y为0~7,只能在同一页,不可超出长度unsigned char xcmd_H,xcmd_L,ycmd;unsigned char *p;p = str;xcmd_H = (x >> 4) + 0x10;xcmd_L = x & 0x0f;ycmd = 0xb0 + y;I2C_WriteCMD(xcmd_H);I2C_WriteCMD(xcmd_L);I2C_WriteCMD(ycmd);while(*p != ‘\0’){unsigned char i = 0;while(i < 8){I2C_WriteDATA(ASCIIcode[(*p) – 32][i]);i++;}p++;}I2C_WriteCMD(ycmd + 1);I2C_WriteCMD(xcmd_H);I2C_WriteCMD(xcmd_L);p = str;while(*p != ‘\0’){unsigned char i = 8;while(i < 16){I2C_WriteDATA(ASCIIcode[(*p) – 32][i]);i++;}p++;}} #include “SSD1306.h”void main(){SSD_Init();SSD_Clear();SSD_displaystr(0,0,”hello”);while(1);} 4.2 提供资源
SSD1306芯片数据手册
提取码:dthg
字体取模软件
提取码:dthg