【算法初体验】【白嫖福利】花了一天写了个基于51单片机的OLED图形库——即拿即用

文章目录

  • 前言
        • 我发现关于51使用OLED的UI算法并不多,其实可以去开源项目找。但是开源项目的代码复杂化了,也比较难以理解。所以我专程花了一天研究OLED的图形算法并且写了这篇博客来总结。
  • b站视频演示:[入口](https://www.bilibili.com/video/BV1u54y1L7Sc)
  • 一、OLED显示原理
  • 二、UI源函数———画点函数
        • 画点函数
  • 三、画线函数
        • 1.画横线(速度可调,适合做动画)
        • 2.画竖线(速度可调,适合做动画)
        • 3.反向竖线(速度可调,适合做动画)
        • 4. 画任意方向的直线(参考,不能改变速度)
  • 四、图形函数
        • 1.画矩形
        • 4.画棱形
  • 动态曲线绘制
  • 总结
      • 完整代码:[此博客的完整项目代码](https://download.csdn.net/download/linfengXBB/18625238)

前言

我发现关于51使用OLED的UI算法并不多,其实可以去开源项目找。但是开源项目的代码复杂化了,也比较难以理解。所以我专程花了一天研究OLED的图形算法并且写了这篇博客来总结。

b站视频演示:入口

【OLED】【算法小白】花了一天在51单片机上硬肝OLED的UI算法

一、OLED显示原理

【算法初体验】【白嫖福利】花了一天写了个基于51单片机的OLED图形库——即拿即用_第1张图片
特殊之处就是它把Y轴64个点划分为8页,X轴是128个点。
我们就是要想方设法做到能点亮这128*64个点的矩阵中的任意一个点。

二、UI源函数———画点函数

所有的图形都是由点构成的,所以怎样精确的去画一个点就是实现一切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表示那个点灭

}

三、画线函数

1.画横线(速度可调,适合做动画)

//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);//写数据	
	}

}

2.画竖线(速度可调,适合做动画)

//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);
}

3.反向竖线(速度可调,适合做动画)

跟竖线画法差不多,反过来画而已

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);


}

4. 画任意方向的直线(参考,不能改变速度)

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;
                }
            }
        }   
    }
}

四、图形函数

图形函数其实就是由点线构成的

1.画矩形


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);


}

4.画棱形

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);

		 
	}
	}

总结

完整代码:此博客的完整项目代码

你可能感兴趣的:(白嫖福利,速成,单片机)