目录
OLED介绍
OLED即有机发光管(Organic Light-Emitting Diode,OLED)。OLED显示技术具有自发光、广视角、几乎无穷高的对比度、较低功耗、极高反应速度、可用于绕曲性面板、使用温度范围广、构造及制程简单等有点,被认为是下一代的平面显示屏新兴应用技术。
OLED显示和传统的LCD显示不同,其可以自发光,所以不需要背光灯,这使得OLED显示屏相对于LCD显示屏尺寸更薄,同时显示效果更优。
常用的OLED屏幕有蓝色、黄色、白色等几种。屏的大小为0.96寸,像素点为128*64,所以我们称为0.96oled屏或者12864屏。
实验所用屏幕参数
- 模块尺寸:23.7 *23.8mm
- 电源电压:3.3-5.5V
- 驱动芯片:SSD1306
- 像素点阵规模:128x64(128列,64行,共8192颗LED)
OLED与开发板接线
OLED引脚
|
正点原子stm32f4探索者开发板
引脚
|
引脚说明
|
GND
|
GND
|
电源地
|
VCC
|
3.3V/5V
|
电源正
|
SCL
|
PB8(I2C1_SCL)
|
IIC时钟线
|
SDA
|
PB9(I2C1_SDA)
|
IIC数据线
|
显存与页寻址模式
驱动芯片SSD1306带有一个128x64 bit大小的GDDRAM,用于存放显示数据,也就是所谓的显存。显存中的数据与显示内容是息息相关的,具体来说,显存中的每一个bit对应一颗像素点,如果显存中的某个bit为1,则它对应的那颗像素LED被点亮,否则是熄灭的。

GDDRAM支持3种内存寻址模式,可以通过指令选择为:
①页寻址模式
②水平寻址模式
③垂直寻址模式。
这里讲解一下最常用的页寻址模式。
在页寻址模式下,每次写入一个字节的显示数据,列地址自动增1。当列地址超过127时,会自动回归到0。但是页指针不会改变,除非使用指令重新设置指向其他的页。
软件设计
IIC驱动代码
这里参考正点原子的IIC驱动代码,使用软件模拟IIC协议。如果对IIC还不是很了解可以参考这一篇:
使用正点原子stm32f4探索者开发板的IIC1接口(PB8和PB9),初始化PB8和PB9,IIC_SCL=1和IIC_SDA=1分别代表将时钟线、数据线拉高。
//初始化SSD1306
void OLED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
//GPIOB8,B9初始化设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
IIC_SCL=1;
IIC_SDA=1;
/******oled初始化部分放至后续讲解********/
}
接下来需要实现IIC的开始信号、结束信号、写字节函数,由于对OLED屏幕的操作主要是写数据,所以这里没有实现读函数。
IIC_Start()函数模拟了IIC传输数据的开始信号,即在时钟线高时将数据线拉低。
/**********************************************
//IIC Start
**********************************************/
void IIC_Start()
{
SDA_OUT(); //sda线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
IIC_Stop()函数模拟了IIC传输数据的结束信号,即在时钟线高时将数据线从低拉高。
/**********************************************
//IIC Stop
**********************************************/
void IIC_Stop()
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
delay_us(4);
}
IIC_Wait_Ack()函数模拟了IIC传输过程中的ACK信号,主机发送一个字节的数据后,若从机没有及时返回ACK响应,将停止数据传输。
void IIC_Wait_Ack()
{
u8 ucErrTime=0;
SDA_IN(); //SDA设置为输入
IIC_SDA=1;delay_us(1);
IIC_SCL=1;delay_us(1);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
}
}
IIC_SCL=0;//时钟输出0
}
Write_IIC_Byte()函数模拟了从主机发送一个字节数据到从机,高位在前,低位在后。
void Write_IIC_Byte(unsigned char txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
IIC_SDA=(txd&0x80)>>7;
txd<<=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
}
OLED驱动代码
oled初始化代码
//初始化SSD1306
void OLED_Init(void)
{
/******oled初始化部分********/
delay_ms(200);
OLED_WR_Byte(0xAE,OLED_CMD);//关闭显示
OLED_WR_Byte(0x40,OLED_CMD);//---set low column address
OLED_WR_Byte(0xB0,OLED_CMD);//---set high column address
OLED_WR_Byte(0xC8,OLED_CMD);//-not offset
OLED_WR_Byte(0x81,OLED_CMD);//设置对比度
OLED_WR_Byte(0xff,OLED_CMD);
OLED_WR_Byte(0xa1,OLED_CMD);//段重定向设置
OLED_WR_Byte(0xa6,OLED_CMD);//设置显示模式,设置为0xa6,显存里的1表示对应led亮,0表示对应led熄灭
OLED_WR_Byte(0xa8,OLED_CMD);//设置驱动路数
OLED_WR_Byte(0x1f,OLED_CMD);
OLED_WR_Byte(0xd3,OLED_CMD);//设置显示偏移量
OLED_WR_Byte(0x00,OLED_CMD);
OLED_WR_Byte(0xd5,OLED_CMD);//设置时钟分频数和fosc
OLED_WR_Byte(0xf0,OLED_CMD);
OLED_WR_Byte(0xd9,OLED_CMD);//设置预充期
OLED_WR_Byte(0x22,OLED_CMD);
OLED_WR_Byte(0xda,OLED_CMD);//设置com脚硬件配置
OLED_WR_Byte(0x02,OLED_CMD);
OLED_WR_Byte(0xdb,OLED_CMD);//设置Vcomh deselect level
OLED_WR_Byte(0x49,OLED_CMD);
OLED_WR_Byte(0x8d,OLED_CMD);//电荷泵设置
OLED_WR_Byte(0x14,OLED_CMD);
OLED_WR_Byte(0xaf,OLED_CMD);//开启显示
OLED_Clear();
}
oled显示汉字的程序如下,这里使用的是页寻址模式(本文前面已经介绍过),所以16*16的点阵分为两部分显示,首先显示上半部分的8*16,然后页指针+1,继续显示剩下的8*16。
//显示汉字,显示的汉字为16*16点阵
void OLED_ShowCHinese(u8 x,u8 y,u8 no)
{
u8 t,adder=0;
OLED_Set_Pos(x,y);
for(t=0;t<16;t++)//显示上半部分8*16点阵
{
OLED_WR_Byte(CHN[2*no][t],OLED_DATA);
adder+=1;
}
OLED_Set_Pos(x,y+1);
for(t=0;t<16;t++)//页指针+1后,显示上半部分8*16点阵
{
OLED_WR_Byte(CHN[2*no+1][t],OLED_DATA);
adder+=1;
}
}
//坐标设置
void OLED_Set_Pos(unsigned char x, unsigned char y)
{
OLED_WR_Byte(0xb0+y,OLED_CMD);
OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
OLED_WR_Byte((x&0x0f),OLED_CMD);
}
//cmd为1(OLED_DATA)时代表写显示数据,cmd为0(OLED_CMD)时代表写操作指令
void OLED_WR_Byte(unsigned dat,unsigned cmd)
{
if(cmd)
{
Write_IIC_Data(dat);
}
else {
Write_IIC_Command(dat);
}
}
/**********************************************
// 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();
}
/**********************************************
// 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();
}
16*16汉字点阵生成工具
- 设置字宽和字高;
- 点击“选项”,在字模选项界面中设置“点阵格式”为阴码,设置“取模方式”为列行式,设置“自定义格式”为C51格式;
- 返回软件主界面,输入想要生成的汉字,然后点击“生成自模”;
- 把生成的字模复制到keil中使用。

显示效果

完整代码资源
如果需要完整的工程文件可以看这里