本帖最后由 田裕中 于 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
}
總結
個人筆記總結,若有問題,歡迎留言、批評指正!!! 若有興趣,歡迎關注公眾號“瀚林創客”,內有資料提取鏈接。
|