OLED相信大家都认识,是一个很常见的显示模块,但是现在网上买的许多oled显示模块因为底层驱动的原因,在编程时对显示有很大的局限性(特别是对51内核的单片机),在定义坐标行数显示的时候往往需要是8的倍数,以下便是针对这个问题做出的改进。
首先介绍一下这篇文章的核心思想,我们都知道以oled12864为例,其实就是128*64个灯,当选择相应坐标的灯点亮就能显示相对应的数字,字符或者是图像。针对上面问题,我们可以建立和显示屏分辨率一样的二维数组,当我们需要将数值显示到显示屏上时,先将数值赋值给数组相同坐标上的值。所以,我们的核心思想其实就是写一个可以在显示屏上任意位置点亮灯的程序,然后结合这个程序和取模软件实现在显示屏任意坐标显示的功能。
二维表:
unsigned char OLED_GRAM[144][8];
以下是打点程序:
//画点
//x:0~127
//y:0~63
//t:1 填充 0,清空
void OLED_DrawPoint(u8 x,u8 y,u8 t)
{
u8 i,m,n;
i=y/8;
m=y%8;
n=1<<m;
if(t){OLED_GRAM[x][i]|=n;}
else
{
OLED_GRAM[x][i]=~OLED_GRAM[x][i];
OLED_GRAM[x][i]|=n;
OLED_GRAM[x][i]=~OLED_GRAM[x][i];
}
}
有了这个程序就可以显示数字,字符,汉字,图片等等:
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//sizey:选择字体 6x8 8x16
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 sizey,u8 mode)
{
u8 chr1,m,temp;
u8 i=0,size1;
u8 x0=x,y0=y;
if(sizey==8)size1=6;
else size1=(sizey/8+((sizey%8)?1:0))*(sizey/2);
chr1=chr-' ';//得到偏移后的值
for(i=0;i<size1;i++)
{
if(sizey==8)
{temp=asc2_0806[chr1][i];} //调用0806字体
else if(sizey==16)
{temp=asc2_1608[chr1][i];} //调用1608字体
else return;
for(m=0;m<8;m++)
{
if(temp&0x01)OLED_DrawPoint(x,y,mode);
else OLED_DrawPoint(x,y,!mode);
temp>>=1;
y++;
}
x++;
if((sizey!=8)&&((x-x0)==sizey/2))
{x=x0;y0=y0+8;}
y=y0;
}
}
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 size1,u8 mode)
{
while((*chr>=' ')&&(*chr<='~'))//判断是不是非法字符!
{
OLED_ShowChar(x,y,*chr,size1,mode);
if(size1==8)x+=6;
else x+=size1/2;
chr++;
}
}
//m^n函数
u32 OLED_Pow(u8 m,u8 n)
{
u32 result=1;
while(n--)result*=m;
return result;
}
//显示数字
//x,y :起点坐标
//num:要显示的数字
//len :数字的位数
//sizey:字体大小
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size1,u8 mode)
{
u8 t,temp,m=0;
if(size1==8)m=2;
for(t=0;t<len;t++)
{
temp=(num/OLED_Pow(10,len-t-1))%10;
if(temp==0)
{
OLED_ShowChar(x+(size1/2+m)*t,y,'0',size1,mode);
}
else
{
OLED_ShowChar(x+(size1/2+m)*t,y,temp+'0',size1,mode);
}
}
}
//显示汉字
void OLED_ShowChinese(u8 x,u8 y,u8 num,u8 size1,u8 mode)
{
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=Hzk[num][i];}//调用16*16字体
else return;
for(m=0;m<8;m++)
{
if(temp&0x01)OLED_DrawPoint(x,y,mode);
else OLED_DrawPoint(x,y,!mode);
temp>>=1;
y++;
}
x++;
if((x-x0)==size1)
{x=x0;y0=y0+8;}
y=y0;
}
}
//显示图片
//x,y显示坐标
//sizex,sizey,图片长宽
//BMP:要显示的图片
void OLED_ShowPicture(u8 x,u8 y,u8 sizex,u8 sizey,u8 BMP[],u8 mode)
{
u16 j=0;
u8 i,n,temp,m;
u8 x0=x,y0=y;
sizey=sizey/8+((sizey%8)?1:0);
for(n=0;n<sizey;n++)
{
for(i=0;i<sizex;i++)
{
temp=BMP[j];
j++;
for(m=0;m<8;m++)
{
if(temp&0x01)OLED_DrawPoint(x,y,mode);
else OLED_DrawPoint(x,y,!mode);
temp>>=1;
y++;
}
x++;
if((x-x0)==sizex)
{
x=x0;
y0=y0+8;
}
y=y0;
}
}
}
最后我们通过图片显示函数将大小为128*64的二维数组过渡打印到显示屏,到处,这个功能就实现啦。因为51单片机是8位单片机,很多时候处理起来会比较慢,而且flash空间也比较小,所以在使用stc15f2k60s2单片机和oled12864进行开发的时候推荐使用isp通信提高刷新率。