SSD1306是一款带控制器的用于OLED点阵图形显示系统的单片CMOS OLED/PLED驱动器。它由128个SEG(列输出)和64个COM(行输出)组成。该芯片专为共阴极OLED面板设计。
SSD1306内置对比度控制器、显示RAM(GDDRAM)和振荡器,以此减少了外部元件的数量和功耗。该芯片有256级亮度控制。数据或命令由通用微控制器通过硬件选择的6800/8000系通用并行接口、I2C接口或串行外围接口发送。该芯片适用于许多小型便携式应用,如手机副显示屏、MP3播放器和计算器等。
当RES#输入低电平时,芯片开始如下的初始化进程:
SSD1306驱动器集成了 6800/8080 系列通用并行接口,串行接口:SPI 接口以及 IIC 接口。通过SSD1306的 BS[2:0]引脚 来选择使用的接口类型,如下图(1为拉高,0为拉低):
(6800/8080系列通用并行接口不多介绍)
4线SPI接口包括:串行时钟(SCLK)、串行数据(SDIN)、数据/命令控制(D/C#)、片选(CS#)。在4线SPI模式下,D0用作SCLK,D1用作SDIN。对于未使用的数据管脚,D2应保持打开状态。从D3到D7,E和R/W#(WR#)的引脚连接到外部地(拉低)。
在SCLK每个上升沿,SDIN上的数据按 D7,D6,…,D0 的顺序(高位在前)移位到一个8位移位寄存器中。每八个时钟对D/C#进行一次采样,移位寄存器中的8位数据根据D/C#的采样结果决定写入到图形显示数据RAM(GDDRAM)或命令寄存器。
4线SPI的写时序如下所示:
3线SPI接口包括:串行时钟(SCLK)、串行数据(SDIN)和片选(CS#)。在3线SPI模式下,D0用作SCLK,D1用作SDIN。对于未使用的数据管脚,D2应保持打开状态。从D3到D7,R/W#(WR#),E,D/C# 的引脚连接到外部地(拉低)。
该操作类似于4线串行接口,但不使用D/C#引脚。
一共9位数据按 高位在前 的顺序,每9个时钟后全部移位到移位寄存器中:D/C#位(数据首位),D7到D0位。D/C# 位将确定移位寄存器中的8位(D7~D0)数据字节写入GDDRAM(D/C#=1)或命令寄存器(D/C#=0)。串行模式下,只允许写操作。
IIC总线包含从机地址位 SA0,数据信号线 SDA(SDAOUT/D2输出和SDAIN/D1输入)和时钟信号线 SCL组成。SDA和SCL线都必须接上拉电阻,RES#用来初始化芯片。
IIC设备在数据传输之前都必须识别从机地址。SSD1306的从机地址有 0111100b 和 0111101b 两种,通过将SA0(D/C#)脚上拉到高电平可以设置从机地址第七位为 1,将SA0(D/C#)脚下拉到低电平可以设置从机地址第七位为 0。通过SA0(D/C#)脚的上拉和下拉来设置从机地址,从而令总线上可以存在最多2个SSD1306驱动器。
SDAOUT/D2和SDAIN/D1连接到一起作为SDA。SDAIN引脚必须连接到SDA,SDAOUT引脚可以不连接。当SDAOUT引脚不连接,应答信号将会被12C总线忽略。
IIC写入时序如下所示:
SSD1306通过 D/C# 和 R/W# 两位来确定:读/写数据,写命令和读状态四种通信行为。具体如下图,不再赘述:
显示RAM:GDDRAM(Graphic Display Data RAM )内部结构如下所示:
GDDRAM是位映射静态RAM,大小为 128x64 位。GDDRAM分为8页(PAGE0~PAGE7),每页内 1个SEG对应1Byte数据,一页由 128 Byte 组成。一帧显示数据为 1024 Byte(1KB)。
1个数据字节写入GDDRAM时,当前列(SEG)同一页(PAGE)的所有行(COM)图像数据都被填充(即由列地址指针指向的整列(8位)被填充)。数据位D0写入顶行,数据位D7写入底行。(由上到下,由低到高)
页寻址模式是器件默认选择的GDDRAM寻址模式,通过“20H,02H”命令可以设置寻址模式为页寻址。
页寻址模式下,寻址只在一页(PAGEn)内进行,地址指针不会跳到其他页。每次向GDDRAM写入1byte显示数据后,列指针会自动+1。当128列都寻址完之后,列指针会重新指向SEG0而页指针仍然保持不变。通过页寻址模式我们可以方便地对一个小区域内数据进行修改。
水平寻址模式可以通过指令“20H,00H”来设置。
水平寻址模式下,每次向GDDRAM写入1byte数据后,列地址指针自动+1。列指针到达结束列之后会被重置到起始行,而页指针将会+1。页地址指针达到结束页之后,将会自动重置到起始页。水平寻址模式适用于大面积数据写入,例如一帧画面刷新。
(下图所示起始页为0,结束页为7;起始列为0,结束列为127)
垂直寻址模式可以通过指令“20H,01H”来设置。
垂直寻址模式下,每次向GDDRAM写入1byte数据之后,页地址指针将会自动+1。页指针到达结束页之后会被重置到0,而列指针将会+1。列地址指针达到结束页之后,将会自动重置到起始列。
(下图所示起始页为0,结束页为7;起始列为0,结束列为127)
1.设置对比度 (81H+A[7:0])
这是一条双字节指令,由第二条指令指定要设置的对比度级数。
A[7:0] 从 00H~FFH 分别指定对比度为 1~256 级。SEG(段)输出的电流大小随对比度级数的增加而增加。
2.设置全屏全亮 (A4H / A5H)
这是一条单字节指令,用于开关屏幕全亮模式。
A4H 设置显示模式为正常模式,此时屏幕输出GDDRAM中的显示数据。
A5H 设置显示模式为全亮模式,此时屏幕无视GDDRAM中的数据,并点亮全屏。
通过A5H设置全屏点亮之后可以通过A4H来回复正常显示。
3.设置正常/反转显示 (A6H / A7H)
这是一条单字节指令,用于设置屏幕显示
A6H 设置显示模式为 1亮0灭,而 A7H 设置显示模式为 0亮1灭
4.开关显示屏 (AEH / AFH)
这是一条单字节指令。
AEH 关闭屏幕,而 AFH 开启屏幕。
屏幕关闭时,所有SEG和COM的输出被分别置为Vss和高阻态。
1.设置GDDRAM寻址模式 (20H+A[1:0])
这是一条双字节指令,由 A[1:0] 指定要设置的地址模式。
A[1:0]=00b时为水平地址模式;A[1:0]=01b时为垂直地址模式;A[1:0]=10b时为页地址模式;A[1:0]=11b时为无效指令;
由于第二条指令前6位值无规定,所以直接用0替代,得到:00H-水平;01H-垂直;02H页
2.设置起始/终止列地址 (21H+A[6:0]+B[6:0])
这是一条三字节指令,由A[6:0]指定起始列地址,B[6:0]指定终止列地址。
同样,由于前1位值无规定,所以:A[6:0] 和 B[6:0] 从 00H~7FH 的取值指定起始/终止列地址为 0~127。
这条指仅在水平/垂直模式下有效,用来设置水平/垂直模式的初始列和结束列
3.设置起始/终止页地址 (22H+A[2:0]+B[2:0])
这是一条三字节指令,由A[2:0]指定起始也地址,B[2:0]指定终止页地址。
由于前5位值无规定,所以:A[2:0]和B[2:0]从 00H~07H 的取值指定起始/终止页地址为 0~7。
这条指仅在水平/垂直模式下有效,用来设置水平/垂直模式的初始页和结束页
4.设置起始列地址低位 (00H~0FH)
这是一条单字节指令。
高4位恒定为0H,低4位为要设置的起始列地址的低4位。这条指令仅用于页寻址模式。
5.设置起始列地址高位 (10H~1FH)
这是一条单字节指令
高4位恒定为1H,低4位为要设置的起始列地址的高4位。这条指令仅用于页寻址模式。
6.设置页地址 (B0H~B7H)
这是一条单字节指令
高4位恒定为BH,第5位规定为0,低3位用于设置页地址,从 B0H~B7H 分别设置起始页为 0~7。这条指令仅用于页寻址模式。
1.设置GDDRAM起始行 (40H~7FH)
这是一条单字节指令。
高2位规定为01b,由低6位的取值来决定起始行。整体指令从 40H~7FH 分别设置起始行为 0~63。
2.设置SEG映射关系 (A0H / A1H)
这是一条单字节指令。
A0H 设置GDDRAM的COL0映射到驱动器输出SEG0。
A1H 设置COL127映射到SEG0
3.设置COM扫描方向 (C0H / C8H)
这是一条单字节指令。
C0H 设置 从COM0扫描到COM[N-1],N为复用率
C1H 设置 从COM[N-1]扫描到COM0
4.设置复用率 (A8H+A[5:0])
这是一条双字节指令,由A[5:0]指定要设置的复用率
复用率(MUX ratio)即选通的COM行数,不能低于16,通过A[5:0]来指定。
A[5:0] 高两位无规定视为0,所以第二条指令从 0FH~3FH 的取值设置复用率为 1~64(即A[5:0]+1)。A[5:0]从0到14的取值都是无效的。
5.设置垂直显示偏移 (D3H+A[5:0])
这是一条双字节指令,由A[5:0]指定偏移量。
垂直显示偏移即整个屏幕向上移动的行数,最顶部的行会移到最底行。
A[5:0] 高两位无规定视为0,所以第二条指令从0FH~3FH的取值设置垂直偏移为 0~63
6.设置COM硬件配置 (DAH+A[5:4])
这是一条双字节指令,由A[5:4]进行设置。
A[5] 位设置COM左右反置,A[4] 用来设置序列/备选引脚配置,其他位有规定,规定如下所示。
SSD1306的COMn引脚一共有左边 COM32~COM63 和右边 COM0~COM31 共64个(金手指面朝上方)。通过设置A[5]可以让左右COM引脚的输出互换。A[5]=0时禁止左右反置,A[5]=1时启用左右反置。
COM引脚的排列有序列和奇偶间隔(备选)两种,通过A[4]进行设置。A[4]=0时使用序列COM引脚配置,A[5]=1时使用奇偶间隔(备选)COM引脚配置。
1.设置显示时钟分频数和fosc (D5H+A[7:0])
2.设置预充电周期 (D9H+A[7:0])
3.设置VCOMH输出的高电平 (DBH+A[6:4])
4.空操作 (E3H)
/**********************************************************************************
* 程序名: SSD1306驱动程序
* 作者: DaveoCKII
* 日期: 2020.3.12
* 版本: STC12C5A60S2
**********************************************************************************/
#ifndef _SSD1306_H_
#define _SSD1306_H_
#include
//------------------------------------定义列表------------------------------------//
sbit SCL = P3^4; // 时钟线
sbit SDA = P3^3; // 数据线
//------------------------------------函数列表------------------------------------//
void OLED_Init(void); // OLED 初始化
void OLED_Clear(void); // OLED 清屏
void OLED_WriteCmd(unsigned char cmd); // OLED 单次写命令
void OLED_WriteDat(unsigned char dat); // OLED 单次写数据
void OLED_WriteC(unsigned char cmd); // OLED 连续写命令 在结尾要加上IIC_STOP();
void OLED_WriteD(unsigned char dat); // OLED 连续写数据 在结尾要加上IIC_STOP();
void OLED_Frame(unsigned char P[8][128]); // OLED 一帧图像写入
//------------------------------------内部函数------------------------------------//
static void IIC_START(void); // IIC_开始信号 (重开始信号用此替代)
static void IIC_STOP(void); // IIC_结束信号
static unsigned char IIC_WaitACK(void); // IIC_等待应答 返回值: 0:NACK 1:ACK
static void IIC_Write(unsigned char dat); // IIC_写数据函数 参数:要写入的数据
static unsigned char IIC_Read(void); // IIC_读数据函数 返回值:读到的数据
static void delay1us(void); // 延时1us
//------------------------------------函数内容------------------------------------//
void OLED_WriteD(unsigned char dat)
{
IIC_START(); // 通信开始
IIC_Write(0X78); // 写从机地址'0111 100' 读写符号'0'
IIC_WaitACK();
IIC_Write(0X40); // 写数据 Co='0' C/D='100 0000'
IIC_WaitACK();
IIC_Write(dat); // 写入数据
IIC_WaitACK();
}
void OLED_WriteC(unsigned char cmd)
{
IIC_START(); // 通信开始
IIC_Write(0X78); // 写从机地址'0111 100' 读写符号'0'
IIC_WaitACK();
IIC_Write(0X00); // 写命令 Co='0' C/D='000 0000'
IIC_WaitACK();
IIC_Write(cmd); // 写入命令
IIC_WaitACK();
}
void OLED_WriteDat(unsigned char dat)
{
OLED_WriteD(dat);
IIC_STOP(); // 通信结束
}
void OLED_WriteCmd(unsigned char cmd)
{
OLED_WriteC(cmd);
IIC_STOP(); // 通信结束
}
void OLED_Init(void)
{
OLED_WriteC(0XAE); // 关OLED显示
// 基础设置
OLED_WriteC(0XA4); // 输出GDDRAM内容
OLED_WriteC(0XA6); // 正常显示(1亮0灭)
OLED_WriteC(0X81); // 设置对比度
OLED_WriteC(0X7F); // 第127级对比度
// COM和SEG输出设置
OLED_WriteC(0XD3); // 设置垂直显示偏移(向上)
OLED_WriteC(0X00); // 偏移0行
OLED_WriteC(0X40); // 设置GDDRAM起始行 0
OLED_WriteC(0XA8); // 设置MUX数 (显示行数)
OLED_WriteC(0X3F); // MUX=63 (显示63行)
OLED_WriteC(0XA1); // 左右反置关(段重映射)
OLED_WriteC(0XC8); // 上下反置关(行重映射)
OLED_WriteC(0XDA); // 设置COM引脚配置
OLED_WriteC(0X02); // 序列COM配置,禁用左右反置
// 时钟设置
OLED_WriteC(0XD5); // 设置DCLK分频和OSC频率
OLED_WriteC(0X80); // 无分频,第8级OSC频率
// 开OLED
OLED_WriteC(0X8D); // 启用电荷泵
OLED_WriteC(0X14); // 启用电荷泵
OLED_WriteC(0XAF); // 开OLED显示
IIC_STOP();
}
void OLED_Clear(void)
{
unsigned char i,j;
OLED_WriteC(0X00); // 水平寻址模式
OLED_WriteC(0X21); // 设置列起始和结束地址
OLED_WriteC(0X00); // 列起始地址 0
OLED_WriteC(0X7F); // 列终止地址 127
OLED_WriteC(0X22); // 设置页起始和结束地址
OLED_WriteC(0X00); // 页起始地址 0
OLED_WriteC(0X07); // 页终止地址 7
for(i=0; i<8; i++) // 写入一帧'0'
for(j=0; j<128; j++)
OLED_WriteD(0X00);
IIC_STOP();
}
void OLED_Frame(unsigned char P[8][128])
{
unsigned char i,j;
OLED_WriteC(0X20); // 设置GDDRAM模式
OLED_WriteC(0X00); // 水平寻址模式
OLED_WriteC(0X21); // 设置列起始和结束地址
OLED_WriteC(0X00); // 列起始地址 0
OLED_WriteC(0X7F); // 列终止地址 127
OLED_WriteC(0X22); // 设置页起始和结束地址
OLED_WriteC(0X00); // 页起始地址 0
OLED_WriteC(0X07); // 页终止地址 7
for(i=0; i<8; i++) // 写入一帧数据
for(j=0; j<128; j++)
OLED_WriteDat(P[i][j]);
IIC_STOP();
}
//----------------------------------内部函数内容-----------------------------------//
static void IIC_START(void)
{
SCL = 0; // SCL拉低 防止可能出现的各种误动作
delay1us();
SDA = 1; // SDA拉高
SCL = 1; // SCL拉高 准备发出起始信号
delay1us();
SDA = 0; // SDA拉低 发出起始信号
SCL = 0; // SCL拉低 开始传输
}
static void IIC_STOP(void)
{
SCL = 0; // SCL拉低 防止可能出现的各种误动作
SDA = 0; // SDA拉低
SCL = 1; // SCL拉高 准备发出结束信号
delay1us();
SDA = 1; // SDA拉高 发出结束信号
}
static unsigned char IIC_WaitACK(void)
{
bit s;
SCL = 0; // 拉低SCL
delay1us();
SDA = 1; // 拉高SDA 主机释放总线
delay1us();
SCL = 1; // 拉高SCL
delay1us();
s = SDA; // 采集SDA信号线状态
delay1us();
SCL = 0; // 拉低SCL 结束询问ACK
if(s)
return 0; // 无应答(ACK)
else
return 1; // 有应答(ACK)
}
static void IIC_Write(unsigned char dat)
{
unsigned char i;
for(i=0; i<8; i++)
{
SCL = 0; // 拉低SCL 准备写数据
SDA = dat & 0X80; // 写数据
dat <<= 1; // 数据格式:高位在前
SCL = 1; // 拉高SCL 发送数据
delay1us();
SCL = 0; // 拉低SCL 结束发送
}
}
static void delay1us(void)
{
}
//---------------------------------------------------------------------------------//
//------------------------------------定义结束--------------------------------------//
//---------------------------------------------------------------------------------//
#endif
DaveoCKII |