因为OLED屏所用的芯片是SSD1306,SSD1306芯片数据手册篇幅较长,主要看与OLED屏设置有关的部分,也可看经过整理翻译过来的中文手册,专门翻译OLED部分
OLED屏的初始化比较复杂,数据手册有给出,直接在main函数中调用即可
/**
* @brief OLED初始化,数据手册已给出
* @param 无
* @retval无
*/
void OLED_Init()
{
OLED_WritCommand(0xAE);
OLED_WritCommand(0x00);
OLED_WritCommand(0x10);
OLED_WritCommand(0x40);
OLED_WritCommand(0xB0);
OLED_WritCommand(0x81);
OLED_WritCommand(0xFF);
OLED_WritCommand(0xA1);
OLED_WritCommand(0xA6);
OLED_WritCommand(0xA8);
OLED_WritCommand(0x3F);
OLED_WritCommand(0xC8);
OLED_WritCommand(0xD3);
OLED_WritCommand(0x00);
OLED_WritCommand(0xD5);
OLED_WritCommand(0x80);
OLED_WritCommand(0xD8);
OLED_WritCommand(0x05);
OLED_WritCommand(0xD9);
OLED_WritCommand(0xF1);
OLED_WritCommand(0xDA);
OLED_WritCommand(0x12);
OLED_WritCommand(0xDB);
OLED_WritCommand(0x30);
OLED_WritCommand(0x8D);
OLED_WritCommand(0x14);
OLED_WritCommand(0xAF);
}
因为设备通信用到了IIC协议,协议的起始信号函数,发送一个字节函数和停止信号函数需要提前写好
I2C总线接口提供了写数据和命令到设备的接口。关于l2C总线的写模式的时序请参考下图:
1.从机地址位(SA0)
SSD1306在发送或接受任何信息之前必须识别从机地址。设备将会响应从机地址,后面跟随着从机地址位(SA0位)和读写选择位(R/W#位),格式如下:
b7 b6 b5 b4 b3 b2 b1 b0
0 1 1 1 1 0 SA0 R/W#
SA0位为从机地址提供了一个位的拓展。0111100或0111101都可以做为SSD1306的从机地址。D/C#引脚作为SA0用于从机地址选择。R/W#为用来决定I2C总线接口的操作模式。R/W#= 1,读模式。R/W#=0写模式
2.传输完从机地址之后,控制字节或数据字节开始通过SDA传输。
一个控制字节主要由CO和 D/C#位后面再加上六个0组成的。
a. 如果CO为设为逻辑0,后面传输的信息就只包含数据字节。
b. D/C#为决定了下个数据字节是作为命令还是数据。如果D/C位设为0,下一个数据就是命令。如果D/C#位设为1,下一个数据就是数据,将会存在GDDRAM (即OLED用来显示的地址)中。GDDRAM列地址指针将会在每次数据写之后自动加1.
3.IIC通信的起始信号函数,发送一个字节函数,应答信号函数应该根据IIC协议提前编写好,再按照上图的通信时序组合成两个OLED所用的函数,一个是发送命令的,一个是发送显示数据的
/**
* @brief OLED写命令
* @param 要写入的命令
* @retval无
*/
void OLED_WritCommand(unsigned char Command)
{
IIC_Start();
IIC_SendByte(0x78); //从机地址+读取
IIC_RecACK();
IIC_SendByte(0x00); //设置为写入指令
IIC_RecACK();
IIC_SendByte(Command); //写入指令
IIC_RecACK();
IIC_Stop();
}
/**
* @brief OLED写数据
* @param 要写入的数据
* @retval无
*/
void OLED_WritData(unsigned char Data)
{
IIC_Start();
IIC_SendByte(0x78); //从机地址+读取
IIC_RecACK();
IIC_SendByte(0x40); //设置为写入数据
IIC_RecACK();
IIC_SendByte(Data); //写入指令
IIC_RecACK();
IIC_Stop();
}
GDDRAM是一个为映射静态RAM保存位模式来显示。该RAM的大小为128 * 64为,RAM分为8页,从 PAGEO到PAGE7,用于单色128*64点阵显示,如下图所示
当一个数据字节写到GDDRAM中,所有当前列的同一页的行图像数据都会被被填充(比如,被列地址指针指向的整列(8位)都会被填充)。数据位DO写到顶行,而数据位D7写到底行
64 | 0列 | 1列 | 2列 | 3列 | …………………… | 124列 | 125列 | 126列 | 127列 | ||
---|---|---|---|---|---|---|---|---|---|---|---|
Page0 | bit0 | 第0行 | 0 | ||||||||
bit1 | 第1行 | 0 | |||||||||
bit2 | 第2行 | 0 | |||||||||
bit3 | 第3行 | 1 | |||||||||
bit4 | 第4行 | 0 | |||||||||
bit5 | 第5行 | 0 | |||||||||
bit6 | 第6行 | 0 | |||||||||
bit7 | 第7行 | 0 | |||||||||
Page1 | 8到15行 | ||||||||||
Page2 | 16到23行 | ||||||||||
Page3 | …… | ||||||||||
Page4 | …… | ||||||||||
Page5 | …… | ||||||||||
Page6 | …… | ||||||||||
Page7 | 56行到63行 |
要先写命令0x20,进入内存地址设置选项,然后再写下面的命令来设置使用哪种模式
A[1:0]:00 ==》 水平地址模式 ==》 0x00
A[1:0]:01 ==》 垂直地址模式 ==》 0x01
A[1:0]:10 ==》 页地址模式(上电默认) ==》 0x02
A[1:0]:11 ==》 无效
OLED_WritCommand(0x20); //设置内存地址
OLED_WritCommand(0x02); //设置页寻址模式
水平地址模式
第一页写满时,会自动跳到第二页,最后一页写满时,又会回到初始位置
垂直地址模式
第一列写满后会自动跳到第二列,最后列写满了会跳到初始位置,这个比较少用
页地址模式
一页写满后不会自动跳转
只有X[2:0]三位可变,共有23 = 8位组合,0~7bit,对应页号为:Page0 ~ Page7
OLED_WritCommand(0xB0); //选择Page0
OLED_WritCommand(0xB1); //选择Page1
OLED_WritCommand(0xB2); //选择Page2
因为在每写入一个数据后,指针会自动加1,就会不断的向后偏移,发送列选择命令,就可让指针重新回到最左边,或者到指定位置
//让指针回到最左边
OLED_WritCommand(0x00); //低位列
OLED_WritCommand(0x10); //高位列
因为只有128列,而用来设置列的命令加起来一共8bit,但27 = 128,所以只用7bit便可以定位所有列,设置低列的4bit加上设置高列的4bit
组成了8bit的列寻址组合,转为十进制便是对应的列
//设置指针去到屏幕最右边,即第127例
OLED_WritCommand(0x0F); //低位列
OLED_WritCommand(0x17); //高位列
/* 0x0F = 0000 1111 //低位
0x17 = 0001 0111 //高位
0111+1111 组合后转为十进制:127
*/
选择页之后就可以选择在哪一行显示,根据GGRAM给出的表格,从上到下,依次为第0行,数据位为bit0,第1行数据位为bit1,……直到第7行数据位为bit7;如下面写入数据0x80,则表示在bit7位(第7行)显示一个点,因为指针会自动加1,多次写入0x80后就变成一条直线
OLED_WritData(0x80);
OLED_WritData(0x80);
OLED_WritData(0x80);
OLED_WritData(0x80);
OLED_WritData(0x80);
因为每次写入数据都是写入到GDDRAM中的,SSD1306芯片不会自己清除内存,想清除掉上一次写入的内容,就要通过程序写入0来清除
/**
* @brief OLED清屏函数
* @param 无
* @retval无
*/
void OLED_Clear()
{
unsigned int i,j;
//先找出PAGE0~PAGE7
for(i = 0;i<8;i++)
{
OLED_WritCommand(0xB0+i);
//从第0列开始
OLED_WritCommand(0x00);
OLED_WritCommand(0x10);
//0到127列,依次写入0,每写入数据,列地址自动偏移
for(j = 0;j<128;j++)
{
OLED_WritData(0);
}
}
}
1.在第一次写入成功并显示图案后,如果不执行清屏函数,则该图案会一直保留,后续在其他位置写入数据不影响该图案
2.假如OLED屏在第1页写入数据0x80,则在第1页的第0列第7行显示一个点,再写入0x40,则在第1列第6行显示一个点,即写入数据成功后指针会自动加1到下一列,如果写入0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01则会显示一条从左下到右上的斜线;如果想显示一条水平直线,则一直写入0x80,指针一直加1后在原来点的右边再显示一个点
3.要记得调用OLED初始化函数