本帖最后由 田裕中 于 2021-12-9 15:41 编辑
OLED的界面UI显示
本文主要总结OLED显示绘图及动画特效的相关功能函数,记录自己的开发过程或作为自己的开发笔记,以便不时之需! 本次OLED采用的SSD1306驱动,分辨率为128*32像素。项目编译环境使用KEIL5开发,由于调试发现,采用软件模拟IIC不能满足刷新帧率,故采用硬件IIC驱动。而显示功能部分不依赖于软件或者硬件IIC驱动,只需提供对应的读写IIC接口即可!
创建显示Buf,更新显存
创建128 * 32的像素点阵大小,任何显示功能特效都只需对该点阵进行填充操作,1Byte = 8bit,4 * 8 = 32,点阵填充完毕后调用该函数即可完成刷新显示。
unsigned char OLED_GRAM[4][128];
void OLED_Refresh_Gram(void)
{
unsigned char i,n;
for(i=0;i<4;i++)
{
WriteCmd(0xb0+i); //设置页地址(0~4)
WriteCmd(0x00); //设置显示位置—列低地址
WriteCmd(0x10); //设置显示位置—列高地址
WriteDat(OLED_GRAM[ i]);
}
清除屏幕显示 调用该函数后整个屏幕是黑色的,和没点亮一样! void OLED_Clear(void)
{
memset(OLED_GRAM,0,sizeof(OLED_GRAM));
OLED_Refresh_Gram();//更新显示
}
画点填充
在对应的坐标位置填充像素点颜色,该函数包含4个方向的显示,拓展了函数的可移植性,通过宏设置显示的方向。 #define TFT_ROT_NONE 1
#define TFT_ROT_RIGHT 0
#define TFT_ROT_LEFT 0
#define TFT_ROT_FLIP 0/*
@parameter:
x:横坐标
y:纵坐标
t:0 or 1
*/
void OLED_DrawPoint(unsigned char x,unsigned char y,unsigned char t)
{
unsigned char pos,bx,temp=0;
#if TFT_ROT_RIGHT
if(x>31||y>127)return;//超出范围了.
pos=x/8;
bx=x%8;
temp=1<<bx;
?
if(t)
{
OLED_GRAM[pos][127-y]|=temp;
}
else
{
OLED_GRAM[pos][127-y]&=~temp;
}
#elif TFT_ROT_LEFT
if(x>31||y>127)return;
pos=3-x/8;
bx=x%8;
temp=1<<(7-bx);
if(t)
{
OLED_GRAM[pos][y]|=temp;
}
else
{
OLED_GRAM[pos][y]&=~temp;
}
#elif TFT_ROT_FLIP
if(x>127||y>31)return;
pos=3-y/8;
bx=y%8;
temp=1<<(7-bx);
if(t)
{
OLED_GRAM[pos][127-x]|=temp;
}
else
{
OLED_GRAM[pos][127-x]&=~temp;
}
#else
if(x>127||y>31)return;//超出范围了.
pos=y/8;
bx=y%8;
temp=1<<bx;
?
if(t)
{
OLED_GRAM[pos][x]|=temp;
}
else
{
OLED_GRAM[pos][x]&=~temp;
}
#endif
}
画任意直线
由一点到另一点的直线!
/*
@parameter:
x1:初始点横坐标
y1:初始点纵坐标
x2:终点横坐标
y2:终点纵坐标
color:0 or 1
*/
void OLED_DrawLine(unsigned char x1,unsigned char y1,unsigned char x2,unsigned char y2,unsigned char color)
{
int dx,dy,e;
dx = x2 - x1;
dy = y2 - y1;
if(dx >= 0)
{
if(dy >= 0)
{
if(dx >= dy)
{
e = dy - dx/2;
while(x1<=x2)
{
OLED_DrawPoint(x1,y1,color);
if(e>0)
{
y1+=1;
e-=dx;
}
x1+=1;
e+=dy;
}
}
else
{
e=dx-dy/2;
while(y1<=y2)
{
OLED_DrawPoint(x1,y1,color);
if(e>0)
{
x1+=1;
e-=dy;
}
y1+=1;
e+=dx;
}
}
}
else
{
dy=-dy;
if(dx>=dy)
{
e=dy-dx/2;
while(x1<=x2)
{
OLED_DrawPoint(x1,y1,color);
if(e>0)
{
y1-=1;
e-=dx;
}
x1+=1;
e+=dy;
}
}
else
{
e=dx-dy/2;
while(y1>=y2)
{
OLED_DrawPoint(x1,y1,color);
if(e>0)
{
x1+=1;
e-=dy;
}
y1-=1;
e+=dx;
}
}
}
}
else
{
dx=-dx;
if(dy>=0)
{
if(dx>=dy)
{
e=dy-dx/2;
while(x1>=x2)
{
OLED_DrawPoint(x1,y1,color);
if(e>0)
{
y1+=1;
e-=dx;
}
x1-=1;
e+=dy;
}
}
else
{
e=dx-dy/2;
while(y1<=y2)
{
OLED_DrawPoint(x1,y1,color);
if(e>0)
{
x1-=1;
e-=dy;
}
y1+=1;
e+=dx;
}
}
}
else
{
dy = -dy;
if(dx>=dy)
{
e=dy-dx/2;
while(x1>=x2)
{
OLED_DrawPoint(x1,y1,color);
if(e>0)
{
y1-=1;
e-=dx;
}
x1-=1;
e+=dy;
}
}
else
{
e=dx-dy/2;
while(y1>=y2)
{
OLED_DrawPoint(x1,y1,color);
if(e>0)
{
x1-=1;
e-=dy;
}
y1-=1;
e+=dx;
}
}
}
}
}
画圆
画指定半径的圆,分为静止态和动态。 //-------------画圆函数。参数:圆心,半径,颜色----------
// 画1/8圆 然后其他7/8对称画
// ---------------->X
// |(0,0) 0
// | 7 1
// | 6 2
// | 5 3
// (Y)V 4
//
// L = x^2 + y^2 - r^2
void OLED_DrawCircle(unsigned char x,unsigned char y,unsigned char r,unsigned char color,unsigned char n)
{
#if 0 //画静止的圆
int a,b,num,i;
a=0;
b=r;
while(2*b>a)
{
OLED_DrawPoint(x+a,y-b,color);//0~1
OLED_DrawPoint(x-a,y-b,color);//0~7
OLED_DrawPoint(x-a,y+b,color);//4~5
OLED_DrawPoint(x+a,y+b,color);//4~3
OLED_DrawPoint(x+b,y+a,color);//2~3
OLED_DrawPoint(x+b,y-a,color);//2~1
OLED_DrawPoint(x-b,y-a,color);//6~7
OLED_DrawPoint(x-b,y+a,color);//6~5
a++;
num=(a*a+b*b)-r*r;//计算画的点离圆心的距离
if(num>0)
{
b--;
a--;
}
OLED_Refresh_Gram();
}
#elif 1
int di=0;
int con_r=r*r;
int a=0;
int b=r;
int bar=0;
int lvel=0;
lvel = n / 25;
bar = (n % 25) * (r*10/25) /10;
if(lvel==0)//第一象限
{
while(b)
{
if(b<(r-bar))
{
OLED_Clear();
return;
}
OLED_DrawPoint(x+a,y+b,color);
a++;
di=a*a+b*b-con_r;
if(di>0)
{
b--;
a--;
}
OLED_Refresh_Gram();
}
}
else if(lvel==1)//第二象限
{
while(b)
{
OLED_DrawPoint(x+a,y+b,color);
a++;
di=a*a+b*b-con_r;
if(di>0)
{
b--;
a--;
}
}
a=0;
b=r;
while(b)
{
if(b<(r-bar))
{
OLED_Clear();
return;
}
OLED_DrawPoint(x+b,y-a,color);
a++;
di=a*a+b*b-con_r;
if(di>0)
{
b--;
a--;
}
OLED_Refresh_Gram();
}
}
else if(lvel==2)//第三象限
{
while(b)
{
OLED_DrawPoint(x+a,y+b,color);
a++;
di=a*a+b*b-con_r;
if(di>0)
{
b--;
a--;
}
}
a=0;
b=r;
while(b)
{
OLED_DrawPoint(x+b,y-a,color);
a++;
di=a*a+b*b-con_r;
if(di>0)
{
b--;
a--;
}
}
a=0;
b=r;
while(b)
{
if(b<(r-bar))
{
OLED_Clear();
return;
}
OLED_DrawPoint(x-a,y-b,color);
a++;
di=a*a+b*b-con_r;
if(di>0)
{
b--;
a--;
}
OLED_Refresh_Gram();
}
}
else if(lvel==3)//第四象限
{
while(b)
{
OLED_DrawPoint(x+a,y+b,color);
a++;
di=a*a+b*b-con_r;
if(di>0)
{
b--;
a--;
}
}
a=0;
b=r;
while(b)
{
OLED_DrawPoint(x+b,y-a,color);
a++;
di=a*a+b*b-con_r;
if(di>0)
{
b--;
a--;
}
}
a=0;
b=r;
while(b)
{
OLED_DrawPoint(x-a,y-b,color);
a++;
di=a*a+b*b-con_r;
if(di>0)
{
b--;
a--;
}
}
a=0;
b=r;
while(b)
{
if(b<(r-bar))
{
OLED_Clear();
return;
}
OLED_DrawPoint(x-b,y+a,color);
a++;
di=a*a+b*b-con_r;
if(di>0)
{
b--;
a--;
}
OLED_Refresh_Gram();
}
}
#endif
}
开机动画
综上所述,制作开机动画。 void Boot_Animation(void)
{
unsigned char i,num=0;
for(i=64;i<64+20;i++)
{
OLED_DrawPoint(64-num,9+num,1);
OLED_DrawPoint(64-num,32-9-num,1);
num++;
OLED_Refresh_Gram();
delay_ms(1);
}
OLED_DrawLine(46,4,83,4,1);
OLED_DrawLine(83,28,46,28,1);
OLED_Refresh_Gram();//更新显示到OLED
}
总结
个人笔记总结,若有问题,欢迎留言、批评指正!!! 若有兴趣,欢迎关注公众号“瀚林创客”,内有资料提取链接。
|