OLED像素发光原理
OLED-有机发光半导体,在有机高分子聚合物的两端施加电压可发光,LED基于金属硅片发光,而OLED可以附于玻璃、塑料,可以用OLED做出曲面屏折叠屏,不同于LCD,OLED没有背光板,每个像素可以独立发光,基于这个特点,OLED可以做息屏提醒
既然每个像素都独立发光,如何控制像素显示需要的图像
如果使每个像素都独立引出正负极,可以但是需要连接的导线太多,显然是不行的。简化成每行每列引出正负级,采用逐行显示的方法,直到最后一行,依次循环,要求循环频率>24次/s肉眼才能看到完整的画面,OLED所有像素的阴极连接一起接地,OLED共阴
控制芯片控制OLED不断的逐行扫描,单片机连接控制芯片,向控制芯片发送要显示的内容
那么如何显示字符或者一个图画
解读数据手册这一段:GOODRAM是静态的RAM,大小128 x 64位,RAM被分为8个页面。从PAGE0 - PAGE7,也就是将64行分为8个部分,每页对应128个字节,低位在上,高位在下,每页的每列表示一个字节
那么可以定义二维数组GDDRAM[128][8]缓存在GDDRAM中,控制每个像素的阳极,这就需要依赖取模软件对字符或图片生成相应的数组
驱动SPI与OLED进行通讯
OLED显示字符
1.驱动STM32的spi,根据数据手册配置相应的GPIO ,需要注意的是OLED只需要两根线就能完成通讯,配置SPI时只需要SCK和MOSI对应的引脚
static void hal_OledConfig(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable SPI1 and GPIOA clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/* Configure SPI1 pins: SCK, MOSI */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 |GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//OLED¸´Î»Òý½Å
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_4);
//OLEDÃüÁî/Êý¾Ý¿ØÖÆÒý½Å
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_6);
/* SPI1 configuration */
SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx; //SPI1ÉèÖÃΪÁ½ÏßÈ«Ë«¹¤
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //ÉèÖÃSPI1ΪÖ÷ģʽ
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //SPI·¢ËͽÓÊÕ8λ֡½á¹¹
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //´®ÐÐʱÖÓÔÚ²»²Ù×÷ʱ£¬Ê±ÖÓΪ¸ßµçƽ
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //µÚ¶þ¸öʱÖÓÑØ¿ªÊ¼²ÉÑùÊý¾Ý
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSSÐźÅÓÉÈí¼þ£¨Ê¹ÓÃSSI룩¹ÜÀí
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //¶¨Ò岨ÌØÂÊÔ¤·ÖƵµÄÖµ:²¨ÌØÂÊÔ¤·ÖƵֵΪ8
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //Êý¾Ý´«Êä´ÓMSBλ¿ªÊ¼
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRCÖµ¼ÆËãµÄ¶àÏîʽ
SPI_Init(SPI1, &SPI_InitStructure);
/* Enable SPI1 */
SPI_Cmd(SPI1, ENABLE); //ʹÄÜSPI2ÍâÉè
}
2.确定OLED选择SPI进行通讯时支持哪种工作模式。查看数据手册,空闲状态时,SCLK为高电平,CPOL=1;在第二个跳变沿采样,CPHA=1,说明3线的SPI支持工作模式三,配置主机是需要与从机保持一致
分析通讯的数据格式:每九个时钟周期,总共有9位将被顺序移入移位寄存器:D/C#位,D7到D0位。D/C#位(顺序数据的第一个位)将确定移位寄存器中的后续数据字节是写入显示数据RAM(D/C#位=1)还是命令寄存器(D/C#位=0)
3.OLED引脚解读
复位引脚:拉低是,芯片的初始化被执行,在正常操作期间,保持这个引脚高电平
数据命令控制引脚:拉高时,SDA引脚上传送的数据被视为数据;拉低是。SDA传送的数据被视为命令传送到寄存器
4.修改OLED驱动的部分代码。
烧录程序时发现并不显示效果,官方提供的代码, 使用软件模拟spi,但是配置的GPIO信号来源于SPI外设,修改方式,要么不复用GPIO,要么将代码修改成硬件实现SPI通讯。
void OLED_WR_Byte(u8 dat,u8 cmd)
{
u8 i;
if(cmd)
OLED_DC_Set();
else
OLED_DC_Clr();
OLED_CS_Clr();
for(i=0;i<8;i++)
{
OLED_SCL_Clr();
if(dat&0x80)
OLED_SDA_Set();
else
OLED_SDA_Clr();
OLED_SCL_Set();
dat<<=1;
}
OLED_CS_Set();
OLED_DC_Set();
}
修改后的结果:
static void hal_Oled_WR_Byte(unsigned char dat,unsigned char cmd)
{
unsigned char retry=0;
if(cmd)
{
OLED_DC_Set();
}else
{
OLED_DC_Clr();
}
SPI1->DR=dat; //·¢ËÍÒ»¸öbyte
retry=0;
while((SPI1->SR & SPI_I2S_FLAG_BSY) != RESET)
{
retry++;
if(retry>200)
return;
}
OLED_DC_Set();
}
OLED显示汉字
首先分析取模软件生成的数组。以16X16的汉字为例,按照取模方式判断数组对应的每一列,以列行式为例。取模方式如下:
中(0) 景(1) 园(2) 电(3) 子(4)
DB 00H 00H F0H 10H 10H 10H 10H FFH 10H 10H 10H 10H F0H 00H 00H 00H 00H 00H 0FH 04H 04H 04H 04H FFH 04H 04H 04H 04H 0FH 00H 00H 00H;"中",0
DB 40H 40H 40H 5FH 55H 55H 55H 75H 55H 55H 55H 5FH 40H 40H 40H 00H 00H 40H 20H 0FH 09H 49H 89H 79H 09H 09H 09H 0FH 20H 40H 00H 00H;"景",1
DB 00H FEH 02H 42H 4AH CAH 4AH 4AH CAH 4AH 4AH 42H 02H FEH 00H 00H 00H FFH 40H 50H 4CH 43H 40H 40H 4FH 50H 50H 5CH 40H FFH 00H 00H;"园",2
DB 00H 00H F8H 88H 88H 88H 88H FFH 88H 88H 88H 88H F8H 00H 00H 00H 00H 00H 1FH 08H 08H 08H 08H 7FH 88H 88H 88H 88H 9FH 80H F0H 00H;"电",3
DB 80H 82H 82H 82H 82H 82H 82H E2H A2H 92H 8AH 86H 82H 80H 80H 00H 00H 00H 00H 00H 00H 40H 80H 7FH 00H 00H 00H 00H 00H 00H 00H 00H;"子",4
额,显示汉字的话有一定的针对性,不好写,不如使用源代码,需要手动改变汉字数组,不如字符灵活
void hal_Oled_ShowChinese(unsigned char x,unsigned char y,unsigned char num,unsigned char size1,unsigned char mode,unsigned char **Hzk1 )
{
u8 m,temp;
u8 x0=x,y0=y;
u16 i,size3=(size1/8+((size1%8)?1:0))*size1; //得到字体一个字符对应点阵集所占的字节数
for(i=0;i<size3;i++)
{
if(size1==16)
{temp=Hzk1[num][i];}//调用16*16字体
else if(size1==24)
{temp=Hzk2[num][i];}//调用24*24字体
else if(size1==32)
{temp=Hzk3[num][i];}//调用32*32字体
else if(size1==64)
{temp=Hzk4[num][i];}//调用64*64字体
else return;
for(m=0;m<8;m++)
{
if(temp&0x01)hal_Oled_DrawPoint(x,y,mode);
else hal_Oled_DrawPoint(x,y,!mode);
temp>>=1;
y++;
}
x++;
if((x-x0)==size1)
{x=x0;y0=y0+8;}
y=y0;
}
}
OLED显示图片
- 使用Img2Lcd将JPG格式改成BMP格式,并且分辨率为128X64
- 使用取模软件将图片转为代码
但是显示的图片是乱码,什么原因
hal_Oled_ShowPicture(0,0,63,64,BMP1,1);显示图片函数显示图片的大小为BMP图片像素的大小,通过观察Img2Lcd软件可以得出63,64,显示正常,