目录
- 1. OLED屏介绍
- 2. OLED如何显示一个点
- 3. 配置OLED屏幕
- 4. OLED显示字符串和汉字
- 5. OLED屏幕显示图片
- 6. 总结
1. OLED屏介绍
- OLED(Organic Light Emitting Diode):有机发光二极管
- OLED显示屏:性能优异的新型显示屏,具有功耗低、相应速度快、宽视角、轻薄柔韧等特点
本文使用的是0.96寸OLED模块,小巧玲珑、占用接口少、简单易用,是电子设计中非常常见的显示屏模块。
OLED屏幕特点
供电:3~5.5V
通信协议:I2C/SPI
分辨率:128*64
OLED屏分两种,一种是4针OLED,通过IIC总线通信,另一种是7针OLED,通过SPI总线通信如下图所示:
OLED屏幕显存:
OLED本身是没有显存的,他的现存是依赖SSD1306提供的,而SSD1306提供一块显存。
SSD1306显存总共为128*64bit大小,SSD1306将这些显存分成了8页。每页包含了128个字节。
OLED屏幕原理
STM32内部建立一个缓存(共128*8个字节),每次修改的时候,只是修改STM32上的缓存(实际上就是SRAM),修改完后一次性把STM32上的缓存数据写入到OLED的GRAM。这个方法也有坏处,对于SRAM很小的单片机(51系列)就比较麻烦。
OLED屏幕常用指令
-
0X81: 设置对比度。包含两个字节,第一个0X81为命令,随后方法是的一个字节要设置这个对比度,值越大屏幕越亮。
-
0XAE/0XAF: 0XAE为关闭显示命令,0XAF为开启显示命令。
-
0X8D: 电荷泵设置,包含两个字节,第一个为命令字,第二个为设置值,第二个字节的BIT2表示电荷泵的开关状态,该位为1开启电荷泵,为0则关闭。模块初始化的时候,这个必须要开启,否则看不到屏幕显示。
-
0XB0~B7:用于设置页地址,其低三位的值对应GRAM页地址。
-
0X00~0X0F:用于设置显示时的起始列地址低四位。
-
0X10~0X1F: 用于设置显示时的起始列地址高四位。
2. OLED如何显示一个点
OLED屏幕分为页寻址模式,水平地址模式,垂直地址模式。
本文主要介绍用的最多的页寻址模式,页寻址模式如下图:
首先把整个OLED屏幕分成八页,也就是把OLED的屏幕把宽平均分成了八份。
比如,想在第3行第0列的开头显示一个点,那就是按位来配置,0000 1000(0x08)。
3. 配置OLED屏幕
我们配置硬件IIC的步骤就是根据下面这张时序图,发送一次数据后不断获取不同的应答即可。
硬件IIC配置:
#include "stm32f10x.h"
#include "oled.h"void IIC_Configuration(void)
{GPIO_InitTypeDef GPIO_InitStructure;I2C_InitTypeDef I2C_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );RCC_APB1PeriphClockCmd( RCC_APB1Periph_I2C1, ENABLE );//PB6--SCL PB7--SDLGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);I2C_DeInit(I2C1);I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;I2C_InitStructure.I2C_ClockSpeed = 400000;I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;I2C_InitStructure.I2C_OwnAddress1 = 0x30;I2C_Init(I2C1, &I2C_InitStructure);I2C_Cmd(I2C1, ENABLE);}void I2C_WriteByte(uint8_t addr,uint8_t data)
{while( I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); //检查IIC总线是否繁忙I2C_GenerateSTART(I2C1, ENABLE); //开启IIC,发送起始信号while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //EV5主模式I2C_Send7bitAddress(I2C1, OLED_ADDRESS , I2C_Direction_Transmitter); //发送OLED地址while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //检查EV6I2C_SendData(I2C1, addr); //发送寄存器地址while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING));I2C_SendData(I2C1, data); //发送数据while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING));I2C_GenerateSTOP(I2C1, ENABLE);
}
写命令函数&写数据函数:
void WriteCmd(unsigned char IIC_Command) //写命令
{I2C_WriteByte(0x00,IIC_Command);
}void WriteDat(unsigned char IIC_Data) //写数据
{I2C_WriteByte(0x40,IIC_Data);
}
OLED初始化:
void OLED_Init(void) //OELD屏幕初始化
{delay_ms(100);WriteCmd(0xAE); //display offWriteCmd(0x20); //Set Memory Addressing Mode WriteCmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,InvalidWriteCmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7WriteCmd(0xc8); //Set COM Output Scan DirectionWriteCmd(0x00); //---set low column addressWriteCmd(0x10); //---set high column addressWriteCmd(0x40); //--set start line addressWriteCmd(0x81); //--set contrast control registerWriteCmd(0xff); //ÁÁ¶Èµ÷½Ú 0x00~0xffWriteCmd(0xa1); //--set segment re-map 0 to 127WriteCmd(0xa6); //--set normal displayWriteCmd(0xa8); //--set multiplex ratio(1 to 64)WriteCmd(0x3F); //WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM contentWriteCmd(0xd3); //-set display offsetWriteCmd(0x00); //-not offsetWriteCmd(0xd5); //--set display clock divide ratio/oscillator frequencyWriteCmd(0xf0); //--set divide ratioWriteCmd(0xd9); //--set pre-charge periodWriteCmd(0x22); //WriteCmd(0xda); //--set com pins hardware configurationWriteCmd(0x12);WriteCmd(0xdb); //--set vcomhWriteCmd(0x20); //0x20,0.77xVccWriteCmd(0x8d); //--set DC-DC enableWriteCmd(0x14); //WriteCmd(0xaf); //--turn on oled panel
}
设置起点坐标:
void SetPos(unsigned char x,unsigned char y) //设置起点坐标
{WriteCmd(0xb0+y);WriteCmd((x&0xf0)>>4|0x10); //取高位WriteCmd((x&0x0f)|0x01); //取低位
全屏填充(可以全屏填充,也可用于清屏):
void OLED_Fill(unsigned char Fill_Data) //全屏填充
{unsigned char m,n;for(m=0;m<8;m++){WriteCmd(0xb0+m);WriteCmd(0x00);WriteCmd(0x10);for(n=0;n<128;n++){WriteDat(Fill_Data);}}
}
清屏:
void OLED_Clean(void) //清屏
{OLED_Fill(0x00);
}
打开/关闭OLED:
void OLED_ON(void) //打开OLED
{WriteCmd(0X8D); //设置电荷泵WriteCmd(0X14); //开启电荷泵WriteCmd(0XAF); //OLED唤醒
}void OLED_OFF(void) //关闭OLED
{WriteCmd(0X8D); //设置电荷泵WriteCmd(0X10); //关闭电荷泵WriteCmd(0XAE); //关闭OLED
}
4. OLED显示字符串和汉字
OLED显示字符串:
//显示字符串
void OLED_ShowStr(unsigned char x,unsigned char y,unsigned char ch[],unsigned TextSize)
{unsigned char c = 0,i = 0,j = 0;switch(TextSize){case 1: //8*16模式{while(ch[j] != '\0'){c = ch[j] - 32;if(x>126){x= 0;y++; }OLED_SetPos(x,y);for(i=0;i<6;i++)WriteDat( F6x8[c][i] );x+=6 ;j++; }}break;case 2: //16*16模式{while(ch[j] !='\0'){c= ch[j] - 32;if(x >120){x = 0;y++ ;}OLED_SetPos(x,y);for(i = 0;i<8;i++)WriteDat( F8X16[c*16+i] );OLED_SetPos(x,y+1);for(i = 0;i<8;i++)WriteDat( F8X16[c*16+i+8] );x+=8;j++;} }break;}
}
OLED显示汉字:
//显示汉字 (x:横坐标 y:纵坐标 N:字数)
void OLED_ShowCN(unsigned char x,unsigned char y,unsigned char N)
{unsigned char wm=0;unsigned int addr = 32*N;OLED_SetPos(x,y);for(wm=0;wm<16;wm++){WriteDat( F16X16[addr]);addr +=1; }OLED_SetPos(x,y+1);for(wm=0;wm<16;wm++){WriteDat( F16X16[addr]);addr +=1; }}
然后通过取字模软件(PCtoLCD2002),输入我们想显示的汉字和大小,通过软件生成字库,再添加到我们代码中的字库文件里。
以我自己的工程为例,如下:
5. OLED屏幕显示图片
//显示图片
//x0:横坐标;y0:纵坐标;x1:图片起点;y1:所占页数;BMP[]:选用的结构体名称
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[])
{unsigned int j=0;unsigned char x,y;if(y1%8 == 0)y = y1/8;elsey = y1/8 +1;for(y=y0;y<y1;y++){OLED_SetPos(x0,y);for(x=x0;x<x1;x++){ WriteDat(BMP[j++]);} }
}
步骤:
- 选一张照片,保存格式改为.png
- 将大小调整为跟我们的屏幕一样的分辨率(128*64)
- 改完大小之后再保存为BMP格式。
- 打开我们的取模软件(Image2Lcd v2.9),生成一个文档。
- 然后把数组里面的内容粘贴到BMP1的数组里面。
最终效果:
6. 总结
本文使用的是4针OLED屏,是通过硬件IIC驱动,当然大家也可以通过软件IIC实现,使用引脚更加灵活。同时大家也可以使用7针的OLED屏,通过SPI进行驱动。
文献:https://blog.csdn.net/aaaaaaaa123345/article/details/124350330