关于OLED模块的小总结
1. OLED模块
首先是所用的OLED模块的一些参数
尺寸:0.96寸
分辨率:128*64
通信方式:I2C
模块内部驱动芯片:SSD1315
管脚定义:GND、VCC、SCK、SDA
1.1 接口方式
OLED模块提供了4种接口方式有,分别是:6800、8080两种并行接口方式、 4线的穿行SPI接口方式、IIC接口方式;接口方式是由硬件电路来确定的,具体参数详情可参考对应驱动芯片的数据手册;
2. OLED模块初始化
OLED的发光原理不同于LCD,即使上电也无法显示内容,得输入正确的代码才能进行正常显示;OLED模块在使用前进行初始化,之后才能正常显示指定内容,下面OLED模块初始化代码:
//注释只是对命令字节简单的介绍
//关于初始化命令字节的详细描述,可以参考对应驱动芯片的数据手册
//OLED模块初始化
OLED_I2C_Write_Byte(0xAE, OLED_CMD); //display off --- 关闭显示
OLED_I2C_Write_Byte(0x00, OLED_CMD); //set lower column address --- 设置起始列地址的低四位,00h~0Fh
OLED_I2C_Write_Byte(0x10, OLED_CMD); //set higher column address --- 设置起始列地址的高四位,10h~17h
OLED_I2C_Write_Byte(0x40, OLED_CMD); //set display start line --- 设置起始行寄存器,04h~7Fh
OLED_I2C_Write_Byte(0xB0, OLED_CMD); //set page address --- 设置页地址,B0h~B7h
OLED_I2C_Write_Byte(0x81, OLED_CMD); //set contrast control --- 设置对比度
OLED_I2C_Write_Byte(0x7F, OLED_CMD); //127,01h~FFh
OLED_I2C_Write_Byte(0xA1, OLED_CMD); //set segment remap --- 设置SEG重映射,A0h/A1h
OLED_I2C_Write_Byte(0xA6, OLED_CMD); //normal display --- 即“1”点亮像素点
//A6h --- “1”点亮像素点
//A7h --- “0”点亮像素点
OLED_I2C_Write_Byte(0xA8, OLED_CMD); //set multiplex ratio --- 设置多路复用率
OLED_I2C_Write_Byte(0x3F, OLED_CMD); //duty = 1/64,00h~3Fh
OLED_I2C_Write_Byte(0xC8, OLED_CMD); //com scan direction --- Com口扫描方向,C0h/C8h
OLED_I2C_Write_Byte(0xD3, OLED_CMD); //set display offset --- 设置显示抵消
OLED_I2C_Write_Byte(0x00, OLED_CMD); //00h~3Fh
OLED_I2C_Write_Byte(0xD5, OLED_CMD); //set osc division --- 设置时钟分配和振荡频率
OLED_I2C_Write_Byte(0x80, OLED_CMD);
OLED_I2C_Write_Byte(0xD9, OLED_CMD); //set pre-charge period --- 设置预充电周期
OLED_I2C_Write_Byte(0x22, OLED_CMD);
OLED_I2C_Write_Byte(0xDA, OLED_CMD); //set com pin configuration --- 设置COM口引脚配置
OLED_I2C_Write_Byte(0x12, OLED_CMD);
OLED_I2C_Write_Byte(0xDB, OLED_CMD); //set vcomh --- 设置COM电压等级
OLED_I2C_Write_Byte(0x20, OLED_CMD); //0x00 —— 0.65*Vcc
//0x10 —— 0.71*Vcc
//0x20 —— 0.77*Vcc
//0x30 —— 0.83*Vcc
OLED_I2C_Write_Byte(0x8D, OLED_CMD); //set charge pump enable --- 设置电荷泵使能
OLED_I2C_Write_Byte(0x14, OLED_CMD);
OLED_I2C_Write_Byte(0xAF, OLED_CMD); //display on --- 打开显示
3. 显示字符和字符串
在初始化OLED之后,如何在屏幕上显示字符呢?
在这之前,先了解一下SSD1315内部的RAM;SSD1315内部有个SRAM称为GDDRAM(Graphic Display Data RAM),大小是128 × 64 bits,被分为8个 PAGE,用于单色128×64点阵显示,当我们往这个RAM写入数据,就会显示特定内容,如图:
每个PAGE8行,共128列;当写入一个字节数据时,该字节数据会以低位在上,高位在下的形式,写入当前列的同一个PAGE的所有行,如图所示:
接下来再说说内存寻址模式,SSD1315有3种内存寻址模式,分别是: 页寻址模式(page addressing mode), 水平寻址模式(horizontal addressing mode)和垂直寻址模式(vertical addressing mode),分别对应的命令字节为:20h、21h、22h,因为OLED模块复位之后默认是 page addressing mode,所以下面只讲页寻址模式;其他两种模式跟页寻址模式的差异就是地址指针自增方式不一样,详情可以参考一下SSD1315的数据手册。
在页寻址模式下,每当对RAM进行读写操作之后,列地址指针会自动+1,直到列地址指针指向列结束地址后,会重新指向列开始地址;而且在该模式下,一定要设置新的页面和列地址才能访问下一个页面的内容,也就是下面这两行代码:
//写入的页地址和列地址根据自身需求来定
//这只是个例子
OLED_I2C_Write_Byte(0xB0, OLED_CMD); //set page address --- 设置页地址,B0h~B7h
OLED_I2C_Write_Byte(0x00, OLED_CMD); //set lower column address --- 设置起始列地址的低四位,00h~0Fh
OLED_I2C_Write_Byte(0x10, OLED_CMD); //set higher column address --- 设置起始列地址的高四位,10h~17h
//上面两个参数共同决定了列地址的值,范围是00h~7Fh,即0~127
在确定在OLED的显示位置后,就是如何生成字模并将表示字模数据发送给OLED了。
ASCII字符的字体大小是可以通过取模软件自定的,但常用的字体大小是8×16和6×12这两种,因为字体太小会看不清,字体太大的话就太占空间,下面以8×16的字体来举例。
一个8×16大小的字体需要占用8×16个bit的空间,也就是说需要占用8列×2个PAGE,所以128×64的OLED一共能显示4行,每行16个这个大小的字符。然后再来了解一下如何生成ASCII字符的字模,我用的取模软件是 PCtoLCD2002,取模过程如图所示:
-
选择字符模式
2.点击选项,按照图片所示进行设置
对面部分选项进行说明
阴码(亮为1)还是阳码(亮为0)是要根据命令字节A6h/A7h来决定的。
“取模方式”要根据设置的寻址方式来选择,具体取模过程可以参考右下角的“取模演示”,取模方式要和寻址方式对应。
“每行显示数据”会影响生成字模数据的格式,因为只是影响到数据的格式,字模数据本身是正确的,所以影响不大,可以根据自身的需求去修改格式。 -
设置完之后,在输入栏内输入字符,然后点击生成字模即可
PS:如果想生成字体大小为6×12的字模,可修改字宽和字高的参数。
那就是说,如果想在OLED的第1页第1列上显示一个字符,先设置页地址为0xB0和列地址为0x00和0x10,再写入该字符的字节数据的前8个字节,然后再设置页地址为0xB1和列地址为0x00和0x10,再写入该字符的字节数据的后8个字节,这样就实现在OLED显示一个字符了。
搞定了显示单个字符,那显示字符串也不是什么问题了,因为显示字符串就是向OLED连续写入字符而已,只需要在程序上加入一个循环就能实现了。
实现代码如下:
//显示字符
void OLED_Show_Char(u8 row, u8 col, u8 ascii_char)
{
u8 i,j;
i = ascii_char - ' '; //获取字符偏移量,这是因为字库跟标准ASCII码表相差32,即一个空格
OLED_I2C_Write_Byte((0xB0+(row&0x07)),OLED_CMD); //设置页地址
OLED_I2C_Write_Byte((col&0x0F), OLED_CMD); //设置列地址
OLED_I2C_Write_Byte(((col&0xF0)>>4)|0x10, OLED_CMD);
for(j=0;j<8;j++)
{
OLED_I2C_Write_Byte(oled_fonts1608[i][j], OLED_DAT);
}
OLED_I2C_Write_Byte((0xB0+(row&0x07)+1),OLED_CMD); //设置下一页地址
OLED_I2C_Write_Byte((col&0x0F), OLED_CMD); //设置列地址
OLED_I2C_Write_Byte(((col&0xF0)>>4)|0x10, OLED_CMD);
for(j=0;j<8;j++)
{
OLED_I2C_Write_Byte(oled_fonts1608[i][j+8], OLED_DAT);
}
}
//显示字符串
void OLED_Show_String(u8 row, u8 col, u8 *ascii_string)
{
while(*ascii_string != '\0')
{
if(col == 128) //防止出现长度大于16的字符串在同一行显示的情况
{
col = 0;
row += 2;
}
OLED_Show_Char(row, col, *ascii_string);
col += 8;
ascii_string++;
}
}
//ASCII表可显示字符
//字体大小:8 × 16
const unsigned char oled_fonts1608[][16]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 0
0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
0xF0,0x08,0xF0,0x00,0xE0,0x18,