oled显示屏本质上就是一些微小的发光管的集合,它的显示原理和led排灯一 样,给1就亮,给0就灭,oled自带显存来存储这些值的集合。 值的注意的是,它是实时的,你往显存里面写1,那么对应位置会立刻变化,很多人以为,oled的显示是先往显存里面写数据,写完一块数据更新一块显示,其实不是这样的,oled和led排灯类似就是为了体现它是实时的这一特点,立刻在屏幕上面体现显存里面的内容。
如果是一块stm32在控制oled显示,通常的做法是在32里面开辟一块内存来存储oled显存里面的数据,这样做的好处是修改都是在32这一端修改,可以极大的提升速度,避免了从oled的显存里面读取数据这一过程。以12864oled举例,可以在stm32里面开辟一块oled[128][8]这样的内存来存储显存数据。
分割线。上面是为了说明我曾经犯的一个错误,误以为oled的显示不是实时的,曾经以为oled是根据页来刷新显示,每次需要等一页的数据都刷新完毕,不管数据是否发生变化,才会刷新显示。
一、通过显示缓存刷新oled
1 开辟内存空间,模拟oled显存
2 将内从空间里面的数据修改成所需要的显示数据
3 将内存空间的数据写入显存
//OLED的显存
//存放格式如下.
//[0]0 1 2 3 ... 127
//[1]0 1 2 3 ... 127
//[2]0 1 2 3 ... 127
//[3]0 1 2 3 ... 127
//[4]0 1 2 3 ... 127
//[5]0 1 2 3 ... 127
//[6]0 1 2 3 ... 127
//[7]0 1 2 3 ... 127
uint16_t OLED_GRAM[128][8];
//更新显存到LCD
void OLED_Refresh_Gram(void)
{
uint8_t i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++)OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA);
}
}
二、直接写数据到oled
直接是通过写数据函数写入oled
//显示16*16汉字
void OLED_ShowCHinese(unsigned char x , unsigned char y , unsigned char no)
{
unsigned char t,adder=0;
oled_set_pos(x,y);
for(t = 0 ;t < 16; t++)
{
OLED_WriteData(Hzk[2 * no][t]);
adder += 1;
}
oled_set_pos(x , y + 1);
for(t = 0 ; t < 16; t++)
{
OLED_WriteData(Hzk[2*no+1][t]);
adder += 1;
}
}
再看下通讯方式的数据快慢
一般IIC总线速度为400kbps,假设咱们的IIC通讯已经是最快了达到了这个速度,不考虑开启总线、应答信号和结束总线的时间开销,大约折算为50kByte/s,而对于128*64的OLED屏来说,完整描述一个屏需要128*64/8=1024个字节,咱们再退一步,不考虑发送器件地址、发送寄存器地址的开销,那么一秒钟可以传送50k/1024≈49帧完整画面,也就相当于,全屏刷新需要20ms左右。
实际上由于其他很多协议的开销,也就出现了20多ms一帧的情况。解决这个问题的根本办法,是换用SPI方式通信,一般SPI总线通讯速率可以到20Mbps,是IIC的50倍。如果还嫌慢,可以直接用8080并行总线方式(但是不确定OLED本身能否反应过来那么快的数据速率)。
简而言之,如果一屏我只需要更改一个数字的显示,那么我完全没有必要对整个屏幕刷屏,我只需要修改要修改的数字的显示区域的像素就可以了。然而无论IIC SPI 还是8080,都是以一个字节为基本单位传输的,因此画点的时候就可能出现把原先不要修改的点给覆盖了这样的情况。