一、介绍
OLED,即有机发光二极管(Organic Light-Emitting Diode),又称为有机电激光显示(OrganicElectroluminesence Display, OELD)。OLED 由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一代的平面显示器新兴应用技术。
二、实验材料
OLED显示屏:
驱动器型号:使用MCU控制OLED本质上是MCU与屏的驱动控制器进行通信,本项目中OLED的驱动器是SSD1306。
物理尺寸:0.96寸
分辨率:在图像方面,分辨率表示图像上的像素点的个数和分布情况。物理尺寸相同时,分辨率越大,则图片更清晰。
像素点:构成图像的最小单元,每个像素点仅有一种颜色。
与OLED通信:通信方式、通信速度、接口…
开发板: 采用STM32f103系列
原理图:
确定使用SPI通信,分析以上引脚的配置方法:
O_MOSI – 数据传输引脚(主发从收) PB15 推挽复用输出
(这里没有O_MISO引脚原因是驱动OLED时,不需要接收来自OLED的数据)
O_CLK – 时钟引脚 PB13 推挽复用输出
O_RST – 复位引脚(低电平有效) PB14 推挽输出
O_DC – 数据/命令选择引脚 PB12 推挽输出
使用OLED屏时,会传输各类数据,至少包含 字模数据 和 坐标数据,但这些数据都是通过O_MOSI数据线传输的,为了区分各类数据的类型,所以OLED上有O_DC引脚:
当O_DC表示数据选择时,接下来流过O_MOSI的一个字节将视为参数。
当O_DC表示命令选择时,接下来流过O_MOSI的一个字节将视为命令。
OLED显示文字
在单色屏下,一般文字的大小为16 x 16 、 24 x 24 或 32 x 32。
0x00,0x80,0x60,0xF8,0x07,0x40,0x20,0x18,0x0F,0x08,0xC8,0x08,0x08,0x28,0x18,0x00,
0x01,0x00,0x00,0xFF,0x00,0x10,0x0C,0x03,0x40,0x80,0x7F,0x00,0x01,0x06,0x18,0x00,/“你”,0/
0x10,0x10,0xF0,0x1F,0x10,0xF0,0x00,0x80,0x82,0x82,0xE2,0x92,0x8A,0x86,0x80,0x00,
0x40,0x22,0x15,0x08,0x16,0x61,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00,/“好”,1/
/***********************************
函数名:spi2_init
参数:无
返回值:无
功能:SPI2初始化
备注:SPI2_SCK PB13
SPI2_MOSI PB15
连接到OLED
***********************************/
static void spi2_init(void)
{
GPIO_InitTypeDef gpio_InitStruct;
SPI_InitTypeDef spi_InitStruct;
/*1.将SPI2相关引脚配置为复用*/
//激活相应的GPIOx
RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOB, ENABLE);
//引脚的推挽复用输出(变为SPI2引脚)
gpio_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP ;
gpio_InitStruct.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15 ;
gpio_InitStruct.GPIO_Speed = GPIO_Speed_2MHz ;
//导入清单,进行配置
GPIO_Init (GPIOB, &gpio_InitStruct);
/*2.激活SPI2,SPI2库函数初始化*/
RCC_APB1PeriphClockCmd (RCC_APB1Periph_SPI2, ENABLE);//36MHz
//需要根据模块的不同调整配置
spi_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4 ;//36 / 4 == 9M Hz
spi_InitStruct.SPI_CPHA = SPI_CPHA_1Edge ;
spi_InitStruct.SPI_CPOL = SPI_CPOL_Low ;
spi_InitStruct.SPI_DataSize = SPI_DataSize_8b ; //一帧数据8位
spi_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB ;//先发送数据高位
//几乎是固定的配置
spi_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex ;//全双工
spi_InitStruct.SPI_CRCPolynomial = 0x7 ;//CRC多项式
spi_InitStruct.SPI_Mode = SPI_Mode_Master ;//主机模式
spi_InitStruct.SPI_NSS = SPI_NSS_Soft ;//软件管理从设备
SPI_Init (SPI2, &spi_InitStruct);
/*3.使能SPI1*/
SPI_Cmd(SPI2,ENABLE);
}
/***********************************
函数名:spi2_send_recv_byte
参数:u8 data 待发送内容
若用于接收数据,则该参数任意填写
返回值:u8 接收内容
若用于发送数据,则该返回值可以忽略
功能:SPI2发送并接收一个字节
备注:每发送1位数据后,就会在半个周期
后接收到一位数据
***********************************/
static u8 spi2_send_recv_byte(u8 data)
{
//等待本次可以发送
while(RESET == SPI_I2S_GetFlagStatus (SPI2, SPI_I2S_FLAG_TXE));
//往DR写入数据
SPI_I2S_SendData (SPI2, data);
//等待数据可以接收
while(RESET == SPI_I2S_GetFlagStatus (SPI2, SPI_I2S_FLAG_RXNE));
//从DR读取数据
return SPI_I2S_ReceiveData (SPI2);
}
/****************************************************************************
函数功能:发送命令函数
函数参数:
Command :要发送的命令
****************************************************************************/
static void OLED_WriteCom(u8 Command)
{
DC_L; //数据/命令选择管脚拉低,表示发送的是命令
spi2_send_recv_byte(Command); //发送命令
}
/****************************************************************************
函数功能:发送参数函数
函数参数:
Data :要发送的参数
*****************************************************************************/
static void OLED_WriteData(u8 Data)
{
DC_H; //数据/命令选择管脚拉高,表示发送的是数据
spi2_send_recv_byte(Data); //发送数据
}
void OLED_init(void)
{
GPIO_InitTypeDef gpio_InitStruct;
//1. 引脚初始化
//激活相应的GPIOx
RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOB, ENABLE);
//引脚的推挽输出
gpio_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP ;
gpio_InitStruct.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_14 ;
gpio_InitStruct.GPIO_Speed = GPIO_Speed_2MHz ;
//导入清单,进行配置
GPIO_Init (GPIOB, &gpio_InitStruct);
//2. SPI2通信接口初始化
spi2_init();
//3. OLED初始时的命令
RST_L;
TIM1_delayms(500);
RST_H;
TIM1_delayms(500);
OLED_WriteCom(0xAE); /*display off*/
OLED_WriteCom(0x00); /*set lower column address*/
OLED_WriteCom(0x10); /*set higher column address*/
OLED_WriteCom(0x40); /*set display start line*/
OLED_WriteCom(0xB0); /*set page address*/
OLED_WriteCom(0x81); /*contract control*/
OLED_WriteCom(0xBF); /*对比度值*/
OLED_WriteCom(0xA1); /*set segment remap 左右翻转*/
OLED_WriteCom(0xA6); /*normal / reverse*/
OLED_WriteCom(0xA8); /*multiplex ratio*/
OLED_WriteCom(0x3F); /*duty = 1/64*/
OLED_WriteCom(0xad); /*set charge pump enable*/
OLED_WriteCom(0x8a); /* 0x8a ??VCC */
OLED_WriteCom(0x32); /*0X30---0X33 set VPP 8V */
OLED_WriteCom(0xC8); /*Com scan direction*/
OLED_WriteCom(0xD3); /*set display offset*/
OLED_WriteCom(0x00); /* 0x20 */
OLED_WriteCom(0xD5); /*set osc division*/
OLED_WriteCom(0x80);
OLED_WriteCom(0xD9); /*set pre-charge period*/
OLED_WriteCom(0x22); /*0x22*/
OLED_WriteCom(0xDA); /*set COM pins*/
OLED_WriteCom(0x12);
OLED_WriteCom(0xdb); /*set vcomh*/
OLED_WriteCom(0x40);
OLED_WriteCom(0x8D);
OLED_WriteCom(0x14);
OLED_WriteCom(0xAF); /*display ON*/
OLED_Clear(0,0,127,7); //清屏函数
}
/*************************************************************************
函数功能:OLED设置坐标函数
参数说明:
x:像素点的X轴坐标,x的范围0~127,
y:像素点的Y轴坐标,y为页的范围0~7
返回值:无
**************************************************************************/
static void OLED_SetPos(u8 x, u8 y)
{
x = x & 0x7F; // x = x % 0x80
y = y & 7; // y = y % 8
OLED_WriteCom(0xB0 + y); //页地址设置:光标设置到第y页
OLED_WriteCom(((x & 0xf0) >> 4)| 0x10);
OLED_WriteCom((x & 0x0f) | 0x00); //列地址设置:光标设置到第x列
}
//显示汉字
void OLED_DisGB2312(u8 x,u8 y,u8 size,u8 *model)
{
u8 i,j;
x = x & 127;
y = y & 7;
size = size / 8 * 8;
for(i = y; i < y + size/8 ; i++)
{
OLED_SetPos(x , i);
for(j = x ; j < x + size ; j++)
{
OLED_WriteData(*model);
model++;
}
}
}
在PCtoLCD软件中,若取模设置相同,则英文取模大小是汉字取模大小的一半(字宽减半)。
//英文字符
void OLED_DisASCII(u8 x,u8 y,u8 size,u8 *model)
{
u8 i,j;
x = x & 127;
y = y & 7;
size = size / 8 * 8;
for(i = y; i < y + size/8 ; i++)
{
OLED_SetPos(x , i);
for(j = x ; j < x + size/2 ; j++)
{
OLED_WriteData(*model);
model++;
}
}
}