【OLED】【算法小白】花了一天在51单片机上硬肝OLED的UI算法
特殊之处就是它把Y轴64个点划分为8页,X轴是128个点。
我们就是要想方设法做到能点亮这128*64个点的矩阵中的任意一个点。
所有的图形都是由点构成的,所以怎样精确的去画一个点就是实现一切UI算法的根源所在。
//X:0~128,Y:0~63
void Setpos(unsigned char x0,unsigned char y0)
{
unsigned char y,mod,pos;
if(y0%8==0){ //输入的y进行处理,如果能被8整除,值必然在0~7页
y=y0/8; //设它的点在对应值的第一个点。
pos = 0x01;
}
else{
y = y0/8; //如果不能被整除
mod = y0%8; //取余数,用把余数看成1~7个二进制位
//然后用16进制在那一页上设立对应的值
switch(mod)
{
case 1:
pos = 0x02;
break;
case 2:
pos = 0x04;
break;
case 3:
pos = 0x08;
break;
case 4:
pos = 0x10;
break;
case 5:
pos = 0x20;
break;
case 6:
pos = 0x40;
break;
case 7:
pos = 0x80;
break;
default:
break;
}
}
OLED_Set_Pos(x0,y); //OLED设置起始位置的函数
OLED_WR_Byte(pos,1); //在那个位置写数据,1表示那个点亮,0表示那个点灭
}
//x0:起始位置,x:结束位置,y0:设置纵坐标time:设置打点延时,最小单位1ms。
void Draw_Hline(unsigned char x0,unsigned char x,unsigned char y0,unsigned int time)
{
unsigned char y,mod,pos,i;
if(y0%8==0){
y=y0/8; //输入的y进行处理,如果能被8整除,值必然在0~7页
pos = 0x01; //设它的点在对应值的第一个点。
}
else{
y = y0/8; //如果不能被整除
mod = y0%8; //取余数,用把余数看成1~7个二进制位
//然后用16进制在那一页上设立对应的值。
switch(mod)
{
case 1:
pos = 0x02;
break;
case 2:
pos = 0x04;
break;
case 3:
pos = 0x08;
break;
case 4:
pos = 0x10;
break;
case 5:
pos = 0x20;
break;
case 6:
pos = 0x40;
break;
case 7:
pos = 0x80;
break;
default:
break;
}
}
OLED_Set_Pos(x0,y); //设置起始坐标
for(i=x0;i<x+1;i++) //依次在对应的页上打点,形成横线。
{
Delay_1ms(time); //控制时间
OLED_WR_Byte(pos,1);//写数据
}
}
//y0:起始位置,y:结束位置,x0:设置横坐标 time:设置打点延时,最小单位1ms。
void Draw_Vline(unsigned char y0,unsigned char y,unsigned char x0,unsigned int time)
{
unsigned char y1,y2,pos,pos1,mod0,mod1,i;
if(y0%8==0){
y1=y0/8;
pos = 0xff;
}
else{
y1 = y0/8;
mod0 = y0%8; //对竖线首页值的设置
switch(mod0)
{
case 1:
pos = 0xfe;
break;
case 2:
pos = 0xfc;
break;
case 3:
pos = 0xf8;
break;
case 4:
pos = 0x10;
break;
case 5:
pos = 0xe0;
break;
case 6:
pos = 0xc0;
break;
case 7:
pos = 0x80;
break;
default:
break;
}
}
if(y%8==0){
y2=y/8;
pos1 = 0x01;
}
else{
y2 = y/8;
mod1 = y%8;
switch(mod1) //对竖线尾页值的设置
{
case 1:
pos1 = 0x03;
break;
case 2:
pos1 = 0x07;
break;
case 3:
pos1 = 0x0f;
break;
case 4:
pos1 = 0x1f;
break;
case 5:
pos1 = 0x3f;
break;
case 6:
pos1 = 0x7f;
break;
case 7:
pos1 = 0xff;
break;
default:
break;
}
}
OLED_Set_Pos(x0,y1); //打首页值的点
OLED_WR_Byte(pos,1);
Delay_1ms(time);
OLED_Set_Pos(x0,y1+1);
for(i=y1+1;i<y2;i++) //中间的的点全部设为亮
{
Delay_1ms(time);
OLED_Set_Pos(x0,i);
OLED_WR_Byte(0xff,1);
}
OLED_Set_Pos(x0,y2); //打尾页值的点
Delay_1ms(time);
OLED_WR_Byte(pos1,1);
}
跟竖线画法差不多,反过来画而已
void Draw_VlineF(unsigned char y0,unsigned char y,unsigned char x0,unsigned int time)
{
unsigned char y1,y2,pos,pos1,mod0,mod1,i;
if(y0%8==0){
y1=y0/8;
pos = 0xff;
}
else{
y1 = y0/8;
mod0 = y0%8;
switch(mod0)
{
case 1:
pos = 0xfe;
break;
case 2:
pos = 0xfc;
break;
case 3:
pos = 0xf8;
break;
case 4:
pos = 0x10;
break;
case 5:
pos = 0xe0;
break;
case 6:
pos = 0xc0;
break;
case 7:
pos = 0x80;
break;
default:
break;
}
}
if(y%8==0){
y2=y/8;
pos1 = 0x01;
}
else{
y2 = y/8;
mod1 = y%8;
switch(mod1)
{
case 1:
pos1 = 0x03;
break;
case 2:
pos1 = 0x07;
break;
case 3:
pos1 = 0x0f;
break;
case 4:
pos1 = 0x1f;
break;
case 5:
pos1 = 0x3f;
break;
case 6:
pos1 = 0x7f;
break;
case 7:
pos1 = 0xff;
break;
default:
break;
}
}
OLED_Set_Pos(x0,y2);
OLED_WR_Byte(pos1,1);
Delay_1ms(time);
OLED_Set_Pos(x0,y1+1);
for(i=y2-1;i>y1;i--)
{
Delay_1ms(time);
OLED_Set_Pos(x0,i);
OLED_WR_Byte(0xff,1);
}
OLED_Set_Pos(x0,y1);
Delay_1ms(time);
OLED_WR_Byte(pos,1);
}
void OLED_DrawLine(int x1,int y1,int x2,int y2)
{
int dx,dy,e;
dx=x2-x1;
dy=y2-y1;
if(dx>=0)
{
if(dy >= 0) // dy>=0
{
if(dx>=dy) // 1/8 octant
{
e=dy-dx/2;
while(x1<=x2)
{
Setpos(x1,y1);
if(e>0){y1+=1;e-=dx;}
x1+=1;
e+=dy;
}
}
else // 2/8 octant
{
e=dx-dy/2;
while(y1<=y2)
{
Setpos(x1,y1);
if(e>0){x1+=1;e-=dy;}
y1+=1;
e+=dx;
}
}
}
else // dy<0
{
dy=-dy; // dy=abs(dy)
if(dx>=dy) // 8/8 octant
{
e=dy-dx/2;
while(x1<=x2)
{
Setpos(x1,y1);
if(e>0){y1-=1;e-=dx;}
x1+=1;
e+=dy;
}
}
else // 7/8 octant
{
e=dx-dy/2;
while(y1>=y2)
{
Setpos(x1,y1);
if(e>0){x1+=1;e-=dy;}
y1-=1;
e+=dx;
}
}
}
}
else //dx<0
{
dx=-dx; //dx=abs(dx)
if(dy >= 0) // dy>=0
{
if(dx>=dy) // 4/8 octant
{
e=dy-dx/2;
while(x1>=x2)
{
Setpos(x1,y1);
if(e>0){y1+=1;e-=dx;}
x1-=1;
e+=dy;
}
}
else // 3/8 octant
{
e=dx-dy/2;
while(y1<=y2)
{
Setpos(x1,y1);
if(e>0){x1-=1;e-=dy;}
y1+=1;
e+=dx;
}
}
}
else // dy<0
{
dy=-dy; // dy=abs(dy)
if(dx>=dy) // 5/8 octant
{
e=dy-dx/2;
while(x1>=x2)
{
Setpos(x1,y1);
if(e>0){y1-=1;e-=dx;}
x1-=1;
e+=dy;
}
}
else // 6/8 octant
{
e=dx-dy/2;
while(y1>=y2)
{
Setpos(x1,y1);
if(e>0){x1-=1;e-=dy;}
y1-=1;
e+=dx;
}
}
}
}
}
图形函数其实就是由点线构成的
void Draw_Rectangle(unsigned char x0,unsigned char y0,unsigned char x,unsigned char y,unsigned int time)
{
Draw_Hline(x0,x-1,y0,time);
Draw_Vline(y0,y,x,time*8);
Draw_Hline(x0+1,x-1,y,time);
Draw_VlineF(y0,y,x0,time*8);
}
void Draw_dimond(unsigned char x0,unsigned char y0,unsigned char R)
{
unsigned char xi,yi,di;
di = 0-(R>>1);
xi = 0;
yi = R;
while(yi>=xi)
{
Setpos(x0+xi-1,y0+yi-1);
Setpos(x0+yi-1,y0+xi-1);
Setpos(x0-xi,y0+yi-1);
Setpos(x0-yi,y0+xi-1);
Setpos(x0-xi,y0-yi);
Setpos(x0-yi,y0-xi);
Setpos(x0+xi-1,y0-yi);
Setpos(x0+yi-1,y0-xi);
xi++;
if(di<0)
{
di+=xi;
}
else {
yi--;
di+=xi-yi;
}
}
}
原理如下:
//核心代码
while(1)
{
for(l=28;l<128;l+=5) //设置横坐标区域
{
if(l>=128) //当数据打印满一页时开始刷新
{
FLAG = 1; //刷新标志位
}
if(FLAG ==1)
{
//刷新
for(n=l-3;n<l+1;n++) //一行一行的刷新,刷新后打上新数据
{
Clear(0,50,n,0); //刷新纵坐标
}
}
num = rand()%48; //产生0~48的随机数
OLED_ShowNum(0,0,num,2,16); //显示随机数
OLED_DrawLine(l-3,lasty,l,num); //前一次打的数跟这一次打的数都连上线
lasty = num; //更新数据
Delay_50ms(1);
}
}