【STM32+HAL】地表最强高刷OLED显示配置【I2C】

(超长代码预警,,,建议使用客户端浏览,,,)

一、前言

有关初级I2C版OLED配置,详见【STM32+HAL】OLED显示初始化配置

有关SPI版OLED配置,详见【STM32+HAL】七针OLED(SSD1306)配置(SPI版)

二、实现功能

开启DMA实现OLED超高刷新率超高速率传输

三、HAL库配置步骤

1、开启I2C

2、开启DMA

3、开启中断

至此,HAL库配置完毕

四、Keil填写代码

1、oled.c

/*
	此c文件用于画图和字符操作(高级操作)
	(主要)由打点为基础
	再 线 折线
	再画和填充 矩形 三角形 圆 椭圆 圆角矩形
	然后是 图片 字符 字符串
	最后是 汉字
*/

#include "oled_draw.h"
#include "stdlib.h"
#include "math.h"


//画图光标
static int  _pointx=0;
static int 	_pointy=0;


//以下4个函数是对当前光标的设置 供以下绘制函数调用 用户不直接使用
void MoveTo(int x,int y)
{
	_pointx=x;
	_pointy=y;
}
TypeXY GetXY(void)
{
	TypeXY m;
	m.x=_pointx;
	m.y=_pointy;
	return m;
}
int GetX(void)
{
	return _pointx;
}
int GetY(void)
{
	return _pointy;
}
void LineTo(int x,int y)
{
	DrawLine(_pointx,_pointy,x,y);
	_pointx=x;
	_pointy=y;
}


void OLED_Clean(void)//清屏
{
	extern unsigned char ScreenBuffer[SCREEN_PAGE_NUM][SCREEN_COLUMN];

    uint16_t i;
    for (i = 0; i < SCREEN_PAGE_NUM * SCREEN_COLUMN; ++i)
    {
        ScreenBuffer[0][i] = 0;
    }
	OLED_FILL(ScreenBuffer[0]);
}




//显示一个字符
//关于字体尺寸及使用请看SetFontSize()的注释
//当size=0时 x为第几行 y为第几列
void OLED_ShowChar(int x, int y, unsigned char c, unsigned int size)
{
	int i,j;
	unsigned char draw_background,bg,a,b,color;
	
	
//	size=GetFontSize();		//字体尺寸
	color=GetDrawColor();	//字体颜色 1白0黑
	bg=GetTextBkMode();		//写字的时候字的背景的颜色 1白0黑
	draw_background= bg != color;	//这两个颜色要不一样字才看得到

	if(!size)//默认字符大小
	{
		if((x>6) || (y>SCREEN_COLUMN-8))
			return;
		c=c-' ';			//得到偏移后的位置
		for(i=0;i<8;i++)
			WriteByteBuffer(x,y+i,F8X16[c*16+i]);
		for(i=0;i<8;i++)
			WriteByteBuffer(x+1,y+i,F8X16[c*16+i+8]);
	}
	else//使用原作粗体字符
	{
		//判断一个字符的上下左右是否超出边界范围
		if ((x >= SCREEN_COLUMN) ||         // Clip right
		(y >= SCREEN_ROW) ||        		// Clip bottom
		((x + 5 * size - 1) < 0) ||   		// Clip left
		((y + 8 * size - 1) < 0)    		// Clip top
		)
			return;

		for (i=0; i<6; i++)
		{
			int line;
			//一个字符在font5x7中由一行6个char表示
			//line为这个字符的第某行内容
			if (i == 5)
				line = 0x0;
			else
				line = pgm_read_byte(font5x7+(c*5)+i);

			for (j=0; j<8; j++)
			{
				unsigned char draw_color = (line & 0x1) ? color : bg;//目前需要填充的颜色是0 就是背景色 1就是字体色

				//不同号大小的字体只是最基础字体的放大倍数 这点要注意
				//比如基础字是1个像素 放大后就是4个像素 再就是9个像素 达到马赛克的放大效果
				if (draw_color || draw_background)
					for ( a = 0; a < size; a++ )
						for ( b = 0; b < size; b++ )
							SetPointBuffer(x + (i * size) + a, y + (j * size) + b, draw_color);

				line >>= 1;
			}
		}
	}
}





//显示字符串 就是显示多次显示字符
void OLED_ShowString(int x, int y,char *str, unsigned int size)
{
	unsigned char j=0,tempx=x,tempy=y;
//	unsigned char size=GetFontSize();

	if(!size)//默认字体
	{
		while (str[j]!='\0')
		{
			OLED_ShowChar(x,y,str[j],size);
			y+=8;
			if(y>120){y=0;x+=2;}
			j++;
		}
	}
	else//使用原作粗体字符
	{
		while (str[j]!='\0')
		{
			if(str[j]=='\n')
			{
				tempy+=8*size;
				tempx=x;
				j++;
				continue;
			}
			OLED_ShowChar(tempx,tempy,str[j],size);
			tempx+=size*6;
			j++;
		}
	}
}




//显示数字 就是多次显示数字的字符
void OLED_ShowNum(unsigned char x,unsigned char y,unsigned int num,unsigned char len, unsigned int size)
{
	unsigned char t,temp;
	unsigned char enshow=0;
//	unsigned char size=GetFontSize();

	if(!size)
	{
		for(t=0;t<len;t++)
		{
			temp=(num/oled_pow(10,len-t-1))%10;
			if(enshow==0&&t<(len-1))
			{
				if(temp==0)
				{
					OLED_ShowChar(x,y+8*t,' ',size);
					continue;
				}
				else
					enshow=1;
			}
			OLED_ShowChar(x,y+8*t,temp+'0',size);
		}
	}
	else
	{
		for(t=0;t<len;t++)
		{
			temp=(num/oled_pow(10,len-t-1))%10;
			if(enshow==0&&t<(len-1))
			{
				if(temp==0)
				{
					OLED_ShowChar(x+(size*6)*t,y,'0',size);
					continue;
				}else enshow=1;
			}
		 OLED_ShowChar(x+(size*6)*t,y,temp+'0',size);
		}
	}
}





//显示汉字
void OLED_ShowCHinese(uint8_t x,uint8_t y,uint8_t *cn)
{
	uint8_t j,wordNum;

	if((x > 7)||(y>128-16))
		return;

	while ( *cn != '\0')	 																	//在C语言中字符串结束以‘\0’结尾
	{
		for (wordNum=0; wordNum<NUM_OFCHINESE; wordNum++)
		{
			if ((CN16CHAR[wordNum].Index[0] == *cn)&&(CN16CHAR[wordNum].Index[1] == *(cn+1)))   //查询要写的字在字库中的位置
			{
				for (j=0; j<32; j++) 															//写一个字
				{
					if (j == 16)	 															//由于16X16用到两个Y坐标,当大于等于16时,切换坐标
					{
						x++;
					}
					WriteByteBuffer(x,y+(j%16),CN16CHAR[wordNum].Msk[j]);
				}
				y += 16;
				x--;
				if(y > (128-16))
				{x += 2;y = 0;}
			}
		}
		cn += 2;																																							//此处打完一个字,接下来寻找第二个字
	}
}





//绘制一个点
void DrawPixel(int x,int y)
{
	SetPointBuffer(x,y,GetDrawColor());
}



//得到某个点的颜色
Type_color GetPixel(int x,int y)
{
	if(GetPointBuffer(x,y))
		return pix_white;
	else
		return pix_black;
}



//划线
//参数:起点坐标 终点坐标
void DrawLine(int x1,int y1,int x2,int y2)
{
	unsigned short us;
	unsigned short usX_Current, usY_Current;

	int lError_X = 0, lError_Y = 0, lDelta_X, lDelta_Y, lDistance;
	int lIncrease_X, lIncrease_Y;

	lDelta_X = x2 - x1; //计算坐标增量
	lDelta_Y = y2 - y1;

	usX_Current = x1;
	usY_Current = y1;

	if ( lDelta_X > 0 )
		lIncrease_X = 1; 			//设置单步正方向
	else if ( lDelta_X == 0 )
		lIncrease_X = 0;			//垂直线
	else
	{
		lIncrease_X = -1;			//设置单步反方向
		lDelta_X = - lDelta_X;
	}

	//Y轴的处理方式与上图X轴的处理方式同理
	if ( lDelta_Y > 0 )
		lIncrease_Y = 1;
	else if ( lDelta_Y == 0 )
		lIncrease_Y = 0;			//水平线
	else
	{
		lIncrease_Y = -1;
		lDelta_Y = - lDelta_Y;
	}

	//选取不那么陡的方向依次画点
	if ( lDelta_X > lDelta_Y )
		lDistance = lDelta_X;
	else
		lDistance = lDelta_Y;

	//依次画点 进入缓存区 画好后再刷新缓冲区就好啦
	for ( us = 0; us <= lDistance + 1; us ++ )					//画线输出
	{
		SetPointBuffer(usX_Current,usY_Current,GetDrawColor());	//画点
		lError_X += lDelta_X ;
		lError_Y += lDelta_Y ;

		if ( lError_X > lDistance )
		{
			lError_X -= lDistance;
			usX_Current += lIncrease_X;
		}

		if ( lError_Y > lDistance )
		{
			lError_Y -= lDistance;
			usY_Current += lIncrease_Y;
		}
	}
}





//快速划线 专用于画横平的线 提高效率
void DrawFastHLine(int x, int y, unsigned char w)
{
	int end = x+w;
	int a;

	Type_color color =GetDrawColor();
	for ( a = MAX(0,x); a < MIN(end,SCREEN_COLUMN); a++)
	{
		SetPointBuffer(a,y,color);
	}
}




//快速划线 专用于画竖直的线 提高效率
void DrawFastVLine(int x, int y, unsigned char h)
{
	int end = y+h;
	int a;

	Type_color color =GetDrawColor();
	for (a = MAX(0,y); a < MIN(end,SCREEN_ROW); a++)
		SetPointBuffer(x,a,color);
}





//绘制折线 开始和转折点的坐标 总点个数
void DrawPolyLineTo(const TypeXY *points,int num)
{
	int i=0;
	MoveTo(points[0].x,points[0].y);
	for(i=1;i<num;i++)
		LineTo(points[i].x,points[i].y);
}





//使用对角点填充矩形
void DrawRect1(int left,int top,int right,int bottom)
{
	DrawLine ( left, top, right, top );
	DrawLine ( left, bottom , right , bottom );
	DrawLine ( left, top, left, bottom );
	DrawLine ( right , top, right , bottom );
}


//功能:使用对角点填充矩形
void DrawFillRect1(int left,int top,int right,int bottom)
{
	DrawRect1(left,top,right,bottom);
	FillRect(left+1,top+1,right-left-1,bottom-top-1);
}



//左上角坐标 矩形宽高
void DrawRect2(int left,int top,int width,int height)
{
	DrawLine ( left, top, left+width-1, top );
	DrawLine ( left, top+height-1 , left+width-1 , top+height-1 );
	DrawLine ( left, top, left, top+height-1);
	DrawLine ( left+width-1 , top, left+width-1 , top+height-1);
}



//填充矩形
void DrawFillRect2(int left,int top,int width,int height)
{
	//先用上面的函数画外框
	DrawRect2(left,top,width,height);
	//然后填充实心
	FillRect(left+1,top+1,width-1,height-1);
}





//画圆
void DrawCircle ( int usX_Center, int usY_Center, int usRadius)
{
	short sCurrentX, sCurrentY;
	short sError;
	sCurrentX = 0; sCurrentY = usRadius;
	sError = 3 - ( usRadius << 1 );     //判断下个点位置的标志

	while ( sCurrentX <= sCurrentY )
	{
		//此处画圆打点的方法和画圆角矩形的四分之一圆弧的函数有点像
		SetPointBuffer ( usX_Center + sCurrentX, usY_Center + sCurrentY	,GetDrawColor());             //1,研究对象
		SetPointBuffer ( usX_Center - sCurrentX, usY_Center + sCurrentY ,GetDrawColor());             //2
		SetPointBuffer ( usX_Center - sCurrentY, usY_Center + sCurrentX ,GetDrawColor());             //3
		SetPointBuffer ( usX_Center - sCurrentY, usY_Center - sCurrentX ,GetDrawColor());             //4
		SetPointBuffer ( usX_Center - sCurrentX, usY_Center - sCurrentY ,GetDrawColor());             //5
		SetPointBuffer ( usX_Center + sCurrentX, usY_Center - sCurrentY ,GetDrawColor());             //6
		SetPointBuffer ( usX_Center + sCurrentY, usY_Center - sCurrentX ,GetDrawColor());             //7
		SetPointBuffer ( usX_Center + sCurrentY, usY_Center + sCurrentX ,GetDrawColor());             //0
		sCurrentX ++;
		if ( sError < 0 )
			sError += 4 * sCurrentX + 6;
		else
		{
			sError += 10 + 4 * ( sCurrentX - sCurrentY );
			sCurrentY --;
		}
	}
}




//填充圆
void DrawFillCircle( int usX_Center, int usY_Center, int r)
{
	DrawFastVLine(usX_Center, usY_Center-r, 2*r+1);
	DrawFillCircleHelper(usX_Center,usY_Center, r, 3, 0);
}




//画部分圆
//圆心坐标 半径 4份圆要画哪一份或哪几份
void DrawCircleHelper(int x0, int y0, unsigned char r, unsigned char cornername)
{
	int f = 1 - r;
	int ddF_x = 1;
	int ddF_y = -2 * r;
	int x = 0;
	int y = r;

	Type_color color=GetDrawColor();
	while (x<y)
	{
		if (f >= 0)
		{
			y--;
			ddF_y += 2;
			f += ddF_y;
		}

		x++;
		ddF_x += 2;
		f += ddF_x;

		if (cornername & 0x4)//右上
		{
			//此处画圆的方式是交替打点 从2边打到中间 最终x<y就打完点跳出循环
			SetPointBuffer(x0 + x, y0 + y,color);
			SetPointBuffer(x0 + y, y0 + x,color);
		}
		if (cornername & 0x2)//右下
		{
			SetPointBuffer(x0 + x, y0 - y, color);
			SetPointBuffer(x0 + y, y0 - x, color);
		}
		if (cornername & 0x8)//左上
		{
			SetPointBuffer(x0 - y, y0 + x, color);
			SetPointBuffer(x0 - x, y0 + y, color);
		}
		if (cornername & 0x1)//左下
		{
			SetPointBuffer(x0 - y, y0 - x, color);
			SetPointBuffer(x0 - x, y0 - y, color);
		}
	}
}




//填充2个四分之一圆和中间的矩形
//此函数专用于画圆角矩形
//右上四分之一圆或左下四分之一圆的圆心 半径 中间矩形的高
void DrawFillCircleHelper(int x0, int y0, unsigned char r, unsigned char cornername, int delta)
{
	int f = 1 - r;
	int ddF_x = 1;
	int ddF_y = -2 * r;
	int x = 0;
	int y = r;

	Type_color color=GetDrawColor();
	while (x < y)
	{
		if (f >= 0)
		{
			y--;
			ddF_y += 2;
			f += ddF_y;
		}

		x++;
		ddF_x += 2;
		f += ddF_x;

		if (cornername & 0x1)//填充右边的2个四分之一圆和中间的矩形
		{
			DrawFastVLine(x0+x, y0-y, 2*y+1+delta);
			DrawFastVLine(x0+y, y0-x, 2*x+1+delta);
		}
		if (cornername & 0x2)//填充左边的2个四分之一圆和中间的矩形
		{
			DrawFastVLine(x0-x, y0-y, 2*y+1+delta);
			DrawFastVLine(x0-y, y0-x, 2*x+1+delta);
		}
	}
}




//绘制一个圆弧
//x,y:圆弧中心坐标
//r:圆弧的半径
//angle_start:圆弧起始角度
//angle_end:圆弧终止角度
//注意:慎用此方法,此方法还需优化。
void DrawArc(int x,int y,unsigned char r,int angle_start,int angle_end)
{
	float i=0;

	TypeXY m,temp;
	temp=GetXY();
	SetRotateCenter(x,y);
	SetAnggleDir(0);
	if(angle_end>360)
		angle_end=360;
	SetAngle(0);
	m=GetRotateXY(x,y+r);
	MoveTo(m.x,m.y);
	for(i=angle_start;i<angle_end;i+=5)
	{
		SetAngle(i);
		m=GetRotateXY(x,y+r);
		LineTo(m.x,m.y);
	}
	LineTo(x+r,y);
	MoveTo(temp.x,temp.y);
}


void DrawFillArc(int x,int y,unsigned char r,int angle_start,int angle_end)
{
	return;
}


//画圆角矩形
void DrawRoundRect(int x, int y, unsigned char w, unsigned char h, unsigned char r)
{
	//画出边缘 因为边缘是直线 所以专用高效率函数
	DrawFastHLine(x+r, y, w-2*r); 		// Top
	DrawFastHLine(x+r, y+h-1, w-2*r); 	// Bottom
	DrawFastVLine(x, y+r, h-2*r); 		// Left
	DrawFastVLine(x+w-1, y+r, h-2*r); 	// Right
	//画出四个圆角
	DrawCircleHelper(x+r, y+r, r, 1);
	DrawCircleHelper(x+w-r-1, y+r, r, 2);
	DrawCircleHelper(x+w-r-1, y+h-r-1, r, 4);
	DrawCircleHelper(x+r, y+h-r-1, r, 8);
}





//画实心圆角矩形
void DrawfillRoundRect(int x, int y, unsigned char w, unsigned char h, unsigned char r)
{
  //画实心矩形
  DrawFillRect2(x+r, y, w-2*r, h);

  //再填充左右两边
  DrawFillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1);	//右上角的圆心
  DrawFillCircleHelper(x+r, y+r, r, 2, h-2*r-1);		//左下角的圆心
}




//画椭圆
//圆心 2个轴长
void DrawEllipse(int xCenter,int yCenter,int Rx,int Ry)
{
	int Rx2=Rx*Rx;
	int Ry2=Ry*Ry;
	int twoRx2=2*Rx2;
	int twoRy2=2*Ry2;
	int p;
	int x=0;
	int y=Ry;
	int px = 0;
	int py = twoRx2*y;

	//椭圆最下面的点
	SetPointBuffer(xCenter+x,yCenter+y,GetDrawColor());//因为此时x=0 俩个点为同一个 原作这样写的 那就这样吧
	SetPointBuffer(xCenter-x,yCenter+y,GetDrawColor());
	//椭圆最上面的点
	SetPointBuffer(xCenter+x,yCenter-y,GetDrawColor());
	SetPointBuffer(xCenter-x,yCenter-y,GetDrawColor());

	//Region?1 画出上下的线条 说实话我也没看懂了 算法大佬
	p=(int)(Ry2-Rx2*Ry+0.25*Rx2);
	while(px<py)
	{
		x++;
		px+=twoRy2;
		if(p<0)
			p+=Ry2+px;
		else
		{
			y--;
			py-=twoRx2;
			p+=Ry2+px-py;
		}
		SetPointBuffer(xCenter+x,yCenter+y,GetDrawColor());
		SetPointBuffer(xCenter-x,yCenter+y,GetDrawColor());
		SetPointBuffer(xCenter+x,yCenter-y,GetDrawColor());
		SetPointBuffer(xCenter-x,yCenter-y,GetDrawColor());
	}

	//Region?2
	p=(int)(Ry2*(x+0.5)*(x+0.5)+Rx2*(y-1)*(y-1)-Rx2*Ry2);
	while(y>0)
	{
		y--;
		py-=twoRx2;
		if(p>0)
			p+=Rx2-py;
		else
		{
			x++;
			px+=twoRy2;
			p+=Rx2-py+px;
		}
		SetPointBuffer(xCenter+x,yCenter+y,GetDrawColor());
		SetPointBuffer(xCenter-x,yCenter+y,GetDrawColor());
		SetPointBuffer(xCenter+x,yCenter-y,GetDrawColor());
		SetPointBuffer(xCenter-x,yCenter-y,GetDrawColor());
	}
}




//填充一个椭圆 参数同上
void DrawFillEllipse(int x0, int y0,int rx,int ry)
{
	int x, y;
	int xchg, ychg;
	int err;
	int rxrx2;
	int ryry2;
	int stopx, stopy;

	rxrx2 = rx;
	rxrx2 *= rx;
	rxrx2 *= 2;

	ryry2 = ry;
	ryry2 *= ry;
	ryry2 *= 2;

	x = rx;
	y = 0;

	xchg = 1;
	xchg -= rx;
	xchg -= rx;
	xchg *= ry;
	xchg *= ry;

	ychg = rx;
	ychg *= rx;

	err = 0;

	stopx = ryry2;
	stopx *= rx;
	stopy = 0;

	while( stopx >= stopy )
	{
		DrawFastVLine( x0+x, y0-y, y+1);
		DrawFastVLine( x0-x, y0-y, y+1);
		DrawFastVLine( x0+x, y0, y+1);
		DrawFastVLine( x0-x, y0, y+1);
		y++;
		stopy += rxrx2;
		err += ychg;
		ychg += rxrx2;
		if ( 2*err+xchg > 0 )
		{
			x--;
			stopx -= ryry2;
			err += xchg;
			xchg += ryry2;
		}
	}

	x = 0;
	y = ry;

	xchg = ry;
	xchg *= ry;

	ychg = 1;
	ychg -= ry;
	ychg -= ry;
	ychg *= rx;
	ychg *= rx;

	err = 0;
	stopx = 0;
	stopy = rxrx2;
	stopy *= ry;

	while( stopx <= stopy )
	{
		DrawFastVLine( x0+x, y0-y, y+1);
		DrawFastVLine( x0-x, y0-y, y+1);
		DrawFastVLine( x0+x, y0, y+1);
		DrawFastVLine( x0-x, y0, y+1);

		x++;
		stopx += ryry2;
		err += xchg;
		xchg += ryry2;
		if ( 2*err+ychg > 0 )
		{
			y--;
			stopy -= rxrx2;
			err += ychg;
			ychg += rxrx2;
		}
	}
}





//功能:绘制一个矩形内切椭圆
//x0,y0:矩形左上角坐标
//x1,y1:矩形右下角坐标
void DrawEllipseRect( int x0, int y0, int x1, int y1)
{
	int a = abs(x1 - x0);
	int b = abs(y1 - y0);	//get diameters
	int b1 = b&1;
	long dx = 4*(1-a)*b*b;
	long dy = 4*(b1+1)*a*a;
	long err = dx+dy+b1*a*a;
	long e2;

	if (x0 > x1) { x0 = x1; x1 += a; }
	if (y0 > y1) { y0 = y1; }
	y0 += (b+1)/2;
	y1 = y0-b1;
	a *= 8*a;
	b1 = 8*b*b;

	do {
		DrawPixel( x1, y0);
		DrawPixel( x0, y0);
		DrawPixel( x0, y1);
		DrawPixel( x1, y1);
		e2 = 2*err;
		if (e2 >= dx) {
			x0++;
			x1--;
			err += dx += b1;
		}
		if (e2 <= dy) {
			y0++;
			y1--;
			err += dy += a;
		}
	} while (x0 <= x1);

	while (y0-y1 < b) {
		DrawPixel( x0-1, y0);
		DrawPixel( x1+1, y0++);
		DrawPixel( x0-1, y1);
		DrawPixel( x1+1, y1--);
	}
}





//画三角形
void DrawTriangle(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2)
{
	//很简单  就是画3条任意线
	DrawLine(x0, y0, x1, y1);
	DrawLine(x1, y1, x2, y2);
	DrawLine(x2, y2, x0, y0);
}



//填充三角形
void DrawFillTriangle(int x0, int y0, int x1, int y1, int x2, int y2)
{
	int a, b, y, last;
	int dx01, dy01,dx02,dy02,dx12,dy12,sa = 0,sb = 0;

	Type_color tmpcolor;
	tmpcolor =GetDrawColor();
	SetDrawColor(GetFillColor());
	if (y0 > y1)
	{
		SWAP(y0, y1); SWAP(x0, x1);
	}
	if (y1 > y2)
	{
		SWAP(y2, y1); SWAP(x2, x1);
	}
	if (y0 > y1)
	{
		SWAP(y0, y1); SWAP(x0, x1);
	}
	if(y0 == y2)
	{
		a = b = x0;
		if(x1 < a)
		{
			a = x1;
		}
		else if(x1 > b)
		{
			b = x1;
		}
		if(x2 < a)
		{
			a = x2;
		}
		else if(x2 > b)
		{
			b = x2;
		}
		DrawFastHLine(a, y0, b-a+1);
		return;
	}
	dx01 = x1 - x0,
	dy01 = y1 - y0,
	dx02 = x2 - x0,
	dy02 = y2 - y0,
	dx12 = x2 - x1,
	dy12 = y2 - y1,
	sa = 0,
	sb = 0;
	if (y1 == y2)
	{
		last = y1;   // Include y1 scanline
	}
	else
	{
		last = y1-1; // Skip it
	}

	for(y = y0; y <= last; y++)
	{
		a   = x0 + sa / dy01;
		b   = x0 + sb / dy02;
		sa += dx01;
		sb += dx02;

		if(a > b)
		{
			SWAP(a,b);
		}
		DrawFastHLine(a, y, b-a+1);
	}
	sa = dx12 * (y - y1);
	sb = dx02 * (y - y0);
	for(; y <= y2; y++)
	{
		a   = x1 + sa / dy12;
		b   = x0 + sb / dy02;
		sa += dx12;
		sb += dx02;
		if(a > b)
		{
			SWAP(a,b);
		}
		DrawFastHLine(a, y, b-a+1);
	}
	SetDrawColor(tmpcolor);
}






//画一幅画,PCtoLCD2002参数请选择[阴码 列行式 逆向]
//起点坐标x y 图像取模数组 图像宽高w h
void DrawBitmap(int x, int y, const unsigned char *bitmap, unsigned char w, unsigned char h)
{
	int iCol,a;
	int yOffset = abs(y) % 8;
	int sRow = y / 8;
	int rows = h/8;

	if(x+w < 0 || x > SCREEN_COLUMN-1 || y+h < 0 || y > SCREEN_ROW-1)
		return;
	if(y < 0)
	{
		sRow--;
		yOffset = 8 - yOffset;
	}

	if(h%8!=0) rows++;
	for(a = 0; a < rows; a++)
	{
		int bRow = sRow + a;
		if(bRow > (SCREEN_ROW/8)-1) break;
		if(bRow > -2)
		{
			for (iCol = 0; iCol<w; iCol++)
			{
				if (iCol + x > (SCREEN_COLUMN-1)) break;
				if (iCol + x >= 0)
				{
					if (bRow >= 0)
					{
						if(GetDrawColor() == pix_white)
						{
							unsigned char temp = ReadByteBuffer(bRow,x + iCol);
							temp|=pgm_read_byte(bitmap+(a*w)+iCol) << yOffset;
							WriteByteBuffer(bRow,x + iCol,temp);
						}
						else if(GetDrawColor() == pix_black)
						{
							unsigned char temp = ReadByteBuffer(bRow,x + iCol);
							temp&=~(pgm_read_byte(bitmap+(a*w)+iCol) << yOffset);
							WriteByteBuffer(bRow,x + iCol,temp);
						}
						else
						{
							unsigned char temp = ReadByteBuffer(bRow,x + iCol);
							temp^=(pgm_read_byte(bitmap+(a*w)+iCol) << yOffset);
							WriteByteBuffer(bRow,x + iCol,temp);
						}
					}
					if (yOffset && bRow<(SCREEN_ROW/8)-1 && bRow > -2)
					{
						if(GetDrawColor() == pix_white)
						{
							unsigned char temp = ReadByteBuffer(bRow+1,x + iCol);
							temp|=pgm_read_byte(bitmap+(a*w)+iCol) >> (8-yOffset);
							WriteByteBuffer(bRow+1,x + iCol,temp);
						}
						else if (GetDrawColor() == pix_black)
						{
							unsigned char temp = ReadByteBuffer(bRow+1,x + iCol);
							temp&=~(pgm_read_byte(bitmap+(a*w)+iCol) >> (8-yOffset));
							WriteByteBuffer(bRow+1,x + iCol,temp);
						}
						else
						{
							unsigned char temp = ReadByteBuffer(bRow+1,x + iCol);
							temp^=pgm_read_byte(bitmap+(a*w)+iCol) >> (8-yOffset);
							WriteByteBuffer( bRow+1,x + iCol,temp);
						}
					}
				}
			}
		}
	}
}





//画一幅画,PCtoLCD2002参数请选择[阴码 逐行式 逆向],具体描述参见[draw_api.h]
//起点坐标x y 图像取模数组 图像宽高w h
void DrawXBitmap(int x, int y, const unsigned char *bitmap, unsigned char w, unsigned char h)
{
  // no need to dar at all of we're offscreen
  int xi, yi, byteWidth = (w + 7) / 8;
  if (x + w < 0 || x > SCREEN_COLUMN - 1 || y + h < 0 || y > SCREEN_ROW - 1)
    return;
  for (yi = 0; yi < h; yi++) {
    for (xi = 0; xi < w; xi++ ) {
      if (pgm_read_byte(bitmap + yi * byteWidth + xi / 8) & (1 << (xi & 7))) {
        SetPointBuffer(x + xi, y + yi, GetDrawColor());
      }
    }
  }
}






2、oled_drive.c

/*
	图形库原理:其实就是对一个数组进行操作,数组操作完成之后,直接将整个
	数组刷新到屏幕上
	因此此c文件用于配置oled底层 用于单片机与oled的直接且唯一通信

	移植此图形库主要完善单片机与OLED的通信:
	SPI_Configuration() 	配置通信引脚
	WriteCmd()      		写命令
	WriteDat()      		写数据
	OledTimeMsFunc()  oled_config中的函数 为系统提供时基
	此例程仅演示SPI通信方式 需要更改其他通信方式请在[oled_config.h]修改
*/


#include "oled_driver.h"
#include "math.h"
#include "string.h"

#if (TRANSFER_METHOD == HW_IIC)	//1.硬件IIC

	void I2C_Configuration(void)
	{
	}

	/**
		 @brief  I2C_WriteByte,向OLED寄存器地址写一个byte的数据
		 @param  addr:寄存器地址
						 data:要写入的数据
		 @retval 无
	*/
void I2C_WriteByte(uint8_t addr, uint8_t data)
{
	extern I2C_HandleTypeDef hi2c1;
	HAL_I2C_Mem_Write(&hi2c1, OLED_ADDRESS, addr, I2C_MEMADD_SIZE_8BIT, &data, 1, 10);
}

void WriteCmd(unsigned char cmd)//写命令
{
	I2C_WriteByte(0x00, cmd);
}

void WriteDat(unsigned char dat)//写数据
{
	I2C_WriteByte(0x40, dat);
}

#endif //(TRANSFER_METHOD ==HW_IIC)


void OLED_Init(void)
{
	WriteCmd(0xAE); //display off

	WriteCmd(0x20); //Set Memory Addressing Mode
//	WriteCmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
	WriteCmd(0x00); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid

	WriteCmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7
	WriteCmd(0xc8); //Set COM Output Scan Direction
	WriteCmd(0x00); //---set low column address
	WriteCmd(0x10); //---set high column address
	WriteCmd(0x40); //--set start line address
	WriteCmd(0x81); //--set contrast control register
	WriteCmd(0xff); //亮度调节 0x00~0xff
	WriteCmd(0xa1); //--set segment re-map 0 to 127
	WriteCmd(0xa6); //--set normal display
	WriteCmd(0xa8); //--set multiplex ratio(1 to 64)
	WriteCmd(0x3F); //
	WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
	WriteCmd(0xd3); //-set display offset
	WriteCmd(0x00); //-not offset
	WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency
	WriteCmd(0xf0); //--set divide ratio
	WriteCmd(0xd9); //--set pre-charge period
	WriteCmd(0x22); //
	WriteCmd(0xda); //--set com pins hardware configuration
	WriteCmd(0x12);
	WriteCmd(0xdb); //--set vcomh
	WriteCmd(0x20); //0x20,0.77xVcc
	WriteCmd(0x8d); //--set DC-DC enable
	WriteCmd(0x14); //
	WriteCmd(0xaf); //--turn on oled panel
	OLED_Clean();
}


void OLED_ON(void)
{
	WriteCmd(0X8D);  //设置电荷泵
	WriteCmd(0X14);  //开启电荷泵
	WriteCmd(0XAF);  //OLED唤醒
}

void OLED_OFF(void)
{
	WriteCmd(0X8D);  //设置电荷泵
	WriteCmd(0X10);  //关闭电荷泵
	WriteCmd(0XAE);  //OLED休眠
}

void OLED_FILL(unsigned char BMP[])
{
	unsigned char *p;
	p = BMP;

	extern I2C_HandleTypeDef hi2c1;
    while(hi2c1.State != HAL_I2C_STATE_READY);
    HAL_I2C_Mem_Write_DMA(&hi2c1, OLED_ADDRESS, 0x40, I2C_MEMADD_SIZE_8BIT, p, SCREEN_PAGE_NUM * SCREEN_PAGEDATA_NUM);
}






/*
	此c文件(原oled_config.c)用于配置oled
	例如初始化oled引脚 刷新oled
	注意!!!
	如需演示动画效果 OledTimeMsFunc()需放入1ms中断等中1ms调用一次为库提供时间基准 原作是放入滴答定时器中
*/

extern unsigned char ScreenBuffer[SCREEN_PAGE_NUM][SCREEN_COLUMN];
extern unsigned char TempBuffer[SCREEN_PAGE_NUM][SCREEN_COLUMN];
unsigned int OledTimeMs=0;												//时间基准


//将ScreenBuffer屏幕缓存的内容显示到屏幕上
void UpdateScreenBuffer(void)
{
	OLED_FILL(ScreenBuffer[0]);
}
//将TempBuffer临时缓存的内容显示到屏幕上
void UpdateTempBuffer(void)
{
	OLED_FILL(TempBuffer[0]);
}

//
//请将此函数放入1ms中断里,为图形提供时基
//系统时间基准主要用于FrameRateUpdateScreen()中固定帧率刷新屏幕
void OledTimeMsFunc(void)
{
	if(OledTimeMs != 0x00)
	{
		OledTimeMs--;
	}
}







/*
	此c文件用于画图的底层操作(基础操作)
	全屏操作包括 初始化 清屏 更新数组到屏幕
	画线 点 旋转 封闭图形的填充 时间的基准更新
*/

//#include "oled_basic.h"
//#include "oled_driver.h"
//#include "math.h"
//#include "string.h"

TypeRoate _RoateValue={{0,0},0,1};
static unsigned char _BitTableS[8]={0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f,0xff};
static void Rotate(int x0,int y0,int*x,int*y,double angle,int direction);
extern unsigned int OledTimeMs;


/*
	此c文件用于对颜色进行操作
	在这里主要是画线线条(一般为白)和填充(一般为白)的颜色
	(在oled.font中还有一个字体背景的颜色(一般为黑))
	在划线画图和打点时都会访问此文件函数获取打点的颜色
*/

//如有需要还可以自己迭代字体颜色 文字背景颜色等
static Type_color _Draw=pix_white;
static Type_color _fill=pix_white;


void SetDrawColor(Type_color value)	//就是划线 线条的颜色
{
	_Draw=value;
}
Type_color GetDrawColor(void)
{
	return _Draw;
}

void SetFillcolor(Type_color value)	//就是填充 实心图形内的颜色
{
	_fill=value;
}
Type_color GetFillColor(void)
{
	return _fill;
}




//清屏
void ClearScreen(void)
{
	ClearScreenBuffer(0);
}
//更新屏幕 注意此处特指刷新屏幕数组而不是临时数组
void UpdateScreen(void)
{
	UpdateScreenDisplay();
}

///
//给选择的缓冲区写入8位数据
void FillByte(int page,int x,unsigned  char byte)
{
	if(GetFillColor())
		WriteByteBuffer(page,x,ReadByteBuffer(page,x)|byte);
	else
		WriteByteBuffer(page,x,ReadByteBuffer(page,x)&(~byte));
}
//给选择的缓冲区填充一个矩形
void FillRect(int x,int y,int width,int height)
{
	int i,j;
	int temp =(y+height-1)/8-y/8;	//需要填充的矩形在屏幕中所占的行数 屏幕被分为8大行
	if(x>SCREEN_COLUMN ||y>SCREEN_ROW)
			return;
	for(i=x; i<x+width&&i<128; i++)
	{
		if( temp==0 )
		{
			FillByte(y/8,i,_BitTableS[height-1]<<(y%8));
		}
		else
		{
			//从左往右 竖向填充
			FillByte(y/8,i,_BitTableS[(8-y%8)-1]<<(y%8));
			for(j=1;j<temp;j++)
			{
				FillByte(y/8+j,i,0xff);
			}
			FillByte(y/8+temp,i,_BitTableS[(height-1+y)%8]);
		}
	}
}
//画一条起点坐标为x,y 长度为height的竖线 (与DrawFastHLine()类似 不过后者是使用打点实现)
void FillVerticalLine(int x,int y,int height,int value)
{
	int temp =(y+height-1)/8-y/8,j;

	if( temp==0 )
	{
		FillByte(y/8,x,_BitTableS[height-1]<<(y%8));
	}
	else
	{
		FillByte(y/8,x,_BitTableS[(8-y%8)-1]<<(y%8));
		for(j=1;j<temp;j++)
		{
			FillByte(y/8+j,x,0xff);
		}
		FillByte(y/8+temp,x,_BitTableS[(height-1+y)%8]);
	}
}

//——————————————————————————————————————————————————————————————————————————————————————————————————————————
//版权声明:本文为CSDN博主「xtlisk」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
//原文链接:https://blog.csdn.net/xtlisk/article/details/51249371

//点x,y绕x0,y0旋转angle弧度
float mySqrt(float x)
{
	float a = x;
	unsigned int i = *(unsigned int *)&x;
	i = (i + 0x3f76cf62) >> 1;
	x = *(float *)&i;
	x = (x + a / x) * 0.5;
	return x;
}
//开平方根函数
unsigned int sqrt_16(unsigned long M)
{
    unsigned int N, i;
    unsigned long tmp, ttp;   // 结果、循环计数
    if (M == 0)               // 被开方数,开方结果也为0
        return 0;
    N = 0;
    tmp = (M >> 30);          // 获取最高位:B[m-1]
    M <<= 2;
    if (tmp > 1)              // 最高位为1
    {
        N ++;                 // 结果当前位为1,否则为默认的0
        tmp -= N;
    }
    for (i=15; i>0; i--)      // 求剩余的15位
    {
        N <<= 1;              // 左移一位

        tmp <<= 2;
        tmp += (M >> 30);     // 假设

        ttp = N;
        ttp = (ttp<<1)+1;

        M <<= 2;
        if (tmp >= ttp)       // 假设成立
        {
            tmp -= ttp;
            N ++;
        }
    }
    return N;
}

//需要优化atant2 cos sin算法
static void Rotate(int x0,int y0,int*x,int*y,double angle,int direction)
{
	int temp=(*y-y0)*(*y-y0)+(*x-x0)*(*x-x0);
	double r=mySqrt(temp);
	double a0=atan2(*x-x0,*y-y0);
	if(direction)
	{
		*x=x0+r*cos(a0+angle);
		*y=y0+r*sin(a0+angle);
	}
	else
	{
		*x=x0+r*cos(a0-angle);
		*y=y0+r*sin(a0-angle);
	}
}

//功能:设置旋转角度
void SetAngle(float angle)
{
	_RoateValue.angle=RADIAN(angle);
}
//功能:设置旋转方向 1为逆时针,0为顺时针
void SetAnggleDir(int direction)
{
	_RoateValue.direct=direction;
}
//功能:设置旋转中心点
void SetRotateCenter(int x0,int y0)
{
	_RoateValue.center.x=x0;
	_RoateValue.center.y=y0;
}
//功能:设置角度、旋转方向、旋转中心
void SetRotateValue(int x,int y,float angle,int direct)
{
	SetRotateCenter(x,y);
	SetAnggleDir(direct);
	SetAngle(angle);
}
//功能:将一个坐标旋转一定角度
//x,y:需要旋转的坐标
//return:旋转后的坐标
TypeXY GetRotateXY(int x,int y)
{
	TypeXY temp;
	int m=x,n=y;

	Rotate(_RoateValue.center.x,_RoateValue.center.y,&m,&n, _RoateValue.angle ,_RoateValue.direct);
	temp.x=m;
	temp.y=n;
	return temp;
}

/
//由某一点开始 获取向上方向同颜色的像素点的个数
unsigned char GetLengthUp(unsigned char x,unsigned char y,unsigned char value)
{
	if(GetPointBuffer(x,y)==value)
	{
		if(y==0)
			return 0;
		return 1+GetLengthUp(x,y-1,value);
	}
	return 0;
}
//和上面函数同理 获取向下方向
unsigned char GetLengthDown(unsigned char x,unsigned char y,unsigned char value)
{
	if(GetPointBuffer(x,y)==value)
	{
		if(y==63)
			return 0;
		return 1+GetLengthUp(x,y+1,value);
	}
	return 0;
}
/
//由一个点开始填充一个封闭图形
//亲测此函数可能有问题 可能是套娃太多 内存不够用
//测试效果是套娃几十个点后花屏
void FloodFill(unsigned char x,unsigned char y,int oldcolor,int newcolor)
{
	UpdateScreen();
	if(GetPointBuffer(x,y)==oldcolor)//这个点的颜色不对
	{
		SetPointBuffer(x,y,newcolor);//把这个点的颜色改为新颜色
		//开始套娃
		FloodFill(x-1,y,oldcolor,newcolor);//修改这个点周围的4个点的颜色
		FloodFill(x+1,y,oldcolor,newcolor);//用这个方法逐渐扩散 填完范围内所有颜色
		FloodFill(x,y+1,oldcolor,newcolor);
		FloodFill(x,y-1,oldcolor,newcolor);
	}
}
//功能:可用于填充一个封闭图形
//x,y:在封闭图形任意一点坐标
//oldcolor:封闭图形中旧的颜色
//newcolor:填充的新颜色
void FloodFill2(unsigned char x,unsigned char y,int oldcolor,int newcolor)
{
	unsigned char h1=0,h2=0;
	short tempx=x;
	while(GetPointBuffer(tempx,y)==oldcolor && tempx<128)
	{
		h1=GetLengthDown(tempx,y,oldcolor);
		h2=GetLengthUp(tempx,y,oldcolor);
		FillVerticalLine(tempx,y-h2,h1+h2,newcolor);
		tempx++;
	}
	tempx=x-1;
	while(GetPointBuffer(tempx,y)==oldcolor&&tempx>0)
	{
		h1=GetLengthDown(tempx,y,oldcolor);
		h2=GetLengthUp(tempx,y,oldcolor);
		FillVerticalLine(tempx,y-h2,h1+h2,newcolor);
		tempx--;
	}
}

/
unsigned char pgm_read_byte(const unsigned char * addr)
{
	return *addr;
}
unsigned int oled_pow(unsigned char m,unsigned char n)
{
	unsigned int result=1;
	while(n--)result*=m;
	return result;
}
//功能:固定帧刷新
//OledTimeMs在OledTimeMsFunc()中被1ms中断持续调用 减到0位置
//此函数放在while循环中 符合条件时刷新屏幕
unsigned char FrameRateUpdateScreen(int value)
{
	if(OledTimeMs==0)
	{
		UpdateScreen();
		ClearScreen();
		OledTimeMs=1000/value;
		return 1;
	}
	return 0;
}







/* 原 oled_buffer.c 文件*/

//定义缓冲 屏幕缓冲区和临时缓冲区
unsigned char ScreenBuffer[SCREEN_PAGE_NUM][SCREEN_COLUMN]={0};	//屏幕缓冲
unsigned char TempBuffer[SCREEN_PAGE_NUM][SCREEN_COLUMN]={0};	//临时操作缓冲
static _Bool _SelectedBuffer=SCREEN_BUFFER;						//当前选择的缓冲区

#define BUFFERSIZE  sizeof(ScreenBuffer)
extern void UpdateTempBuffer(void);
extern void UpdateScreenBuffer(void);

///
//设置选择 屏幕缓冲
void SetScreenBuffer(void)
{
	_SelectedBuffer=SCREEN_BUFFER;
}
//设置选择 临时缓冲
void SetTempBuffer(void)
{
	_SelectedBuffer=TEMP_BUFFER;
}
//获取程序目前选择的缓冲区
unsigned char GetSelectedBuffer(void)
{
	return _SelectedBuffer;
}
//功能:清除屏幕缓冲数据
void ClearScreenBuffer(unsigned char val)
{
	memset(ScreenBuffer,val,sizeof(ScreenBuffer));
}
//功能:清除临时缓冲数据
void ClearTempBuffer(void)
{
	memset(TempBuffer,0,sizeof(TempBuffer));
}

//对临时缓冲进行一些操作
//func:执行的功能可选择的参数如下
/*
	TEMPBUFF_COPY_TO_SCREEN, 		 将temp缓冲复制到屏幕缓冲
	TEMPBUFF_CLEAN,					 清楚掉temp缓冲数据
	TEMPBUFF_COVER_L,				 将temp缓冲的数据取反再覆盖掉屏幕上的数据
	TEMPBUFF_COVER_H				 将temp缓冲的数据覆盖掉屏幕上的数据 */
void TempBufferFunc(int func)
{
	int i,j;
	switch (func)
	{
		case TEMPBUFF_COPY_TO_SCREEN:
			memcpy(ScreenBuffer,TempBuffer,BUFFERSIZE);
			break;
		case TEMPBUFF_CLEAN:
			ClearTempBuffer();
			break;
		case TEMPBUFF_COVER_H:
				for(i=0;i<8;i++)
					for(j=0;j<128;j++)
						ScreenBuffer[i][j] |=TempBuffer[i][j];
				break;
		case TEMPBUFF_COVER_L:
				for(i=0;i<8;i++)
					for(j=0;j<128;j++)
						ScreenBuffer[i][j] &=~TempBuffer[i][j];
				break;
		default:
			break;
	}
}

///
//读取选择的缓冲区的8位数据
unsigned char ReadByteBuffer(int page,int x)
{
	return _SelectedBuffer? ScreenBuffer[page][x] :TempBuffer[page][x];
}
//写入读取选择的缓冲区8位数据
void WriteByteBuffer(int page,int x,unsigned char byte)
{
	if(_SelectedBuffer)
	{
		ScreenBuffer[page][x] =byte;
	}
	else
	{
		TempBuffer[page][x] =byte;
	}
}

//设置当前选择的缓冲区 的 某一个点的亮灭
void SetPointBuffer(int x,int y,int value)
{
	if(x>SCREEN_COLUMN-1 ||y>SCREEN_ROW-1)   //超出范围
		return;
	if(_SelectedBuffer)
	{
		if(value)
			ScreenBuffer[y/SCREEN_PAGE_NUM][x] |= 1<<(y%SCREEN_PAGE_NUM);
		else
			ScreenBuffer[y/SCREEN_PAGE_NUM][x] &= ~(1<<(y%SCREEN_PAGE_NUM));
	}
	else
	{
		if(value)
			TempBuffer[y/SCREEN_PAGE_NUM][x] |= 1<<(y%SCREEN_PAGE_NUM);
		else
			TempBuffer[y/SCREEN_PAGE_NUM][x] &= ~(1<<(y%SCREEN_PAGE_NUM));
	}
}
//获取当前选择的缓冲区 的 某一点的颜色
unsigned char GetPointBuffer(int x,int y)
{
	if(x>SCREEN_COLUMN-1 ||y>SCREEN_ROW-1)   //超出范围
		return 0;
	if(_SelectedBuffer)
		return (ScreenBuffer[y/SCREEN_PAGE_NUM][x]>>(y%SCREEN_PAGE_NUM))&0x01;
	else
		return (TempBuffer[y/SCREEN_PAGE_NUM][x]>>(y%SCREEN_PAGE_NUM))&0x01;
}
//刷新屏幕显示
void UpdateScreenDisplay(void)
{
	UpdateScreenBuffer();
}





3、oled_font.c

/*
	Copyright (c) [2019] [一只程序缘 jiezhuo]
	[https://gitee.com/jiezhuonew/oledlib] is licensed under the Mulan PSL v1.
	You can use this software according to the terms and conditions of the Mulan PSL v1.
	You may obtain a copy of Mulan PSL v1 at:
		http://license.coscl.org.cn/MulanPSL
	THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
	PURPOSE.
	See the Mulan PSL v1 for more details.
	
	此c文件用于对字体进行操作 在oled.draw中被DrawChar()等函数被调用
	主要有设置字体背景颜色 
	(字体颜色同划线线条颜色GetDrawColor())
	字体尺寸
	基础字符字库(取模方式见字库顶部)
	汉字字库(取模方式见字库顶部)
*/

#include "oled_font.h"

static Type_textbk _TextBk=TEXT_BK_NULL;
static unsigned char _FontSize=0;			//默认字体尺寸 为8x6

/
//设置字体填充的背景颜色
//1白0黑 
//TEXT_BK_NULL:无背景,TEXT_BK_NOT_NULL:有背景
void SetTextBkMode(Type_textbk value)
{
	_TextBk=value;
}
Type_textbk GetTextBkMode(void)
{
	return _TextBk;
}

//在显示字体前先设置需要显示的字体的尺寸
//尺寸有 0 1 2 3
//对应像素是 0 8 16 24
//0是默认字体 		也就是F8X16[]		大小8x16
//1是原作者字体 	也就是font5x7[]		大小6x8
//2是1的2倍放大							大小12x16
//3是1的3倍放大							大小18x24
void SetFontSize(unsigned char value)
{
	_FontSize=value;
}
unsigned char GetFontSize(void)
{
	return _FontSize;
}


//基础图形英文字符字库
//若要显示更大的字符按照此字符比例放大即可
//详情见DrawChar()
const unsigned char font5x7[] =
{
    0x00, 0x00, 0x00, 0x00, 0x00,
    0x3E, 0x5B, 0x4F, 0x5B, 0x3E,
    0x3E, 0x6B, 0x4F, 0x6B, 0x3E,
    0x1C, 0x3E, 0x7C, 0x3E, 0x1C,
    0x18, 0x3C, 0x7E, 0x3C, 0x18,
    0x1C, 0x57, 0x7D, 0x57, 0x1C,
    0x1C, 0x5E, 0x7F, 0x5E, 0x1C,
    0x00, 0x18, 0x3C, 0x18, 0x00,
    0xFF, 0xE7, 0xC3, 0xE7, 0xFF,
    0x00, 0x18, 0x24, 0x18, 0x00,
    0xFF, 0xE7, 0xDB, 0xE7, 0xFF,
    0x30, 0x48, 0x3A, 0x06, 0x0E,
    0x26, 0x29, 0x79, 0x29, 0x26,
    0x40, 0x7F, 0x05, 0x05, 0x07,
    0x40, 0x7F, 0x05, 0x25, 0x3F,
    0x5A, 0x3C, 0xE7, 0x3C, 0x5A,
    0x7F, 0x3E, 0x1C, 0x1C, 0x08,
    0x08, 0x1C, 0x1C, 0x3E, 0x7F,
    0x14, 0x22, 0x7F, 0x22, 0x14,
    0x5F, 0x5F, 0x00, 0x5F, 0x5F,
    0x06, 0x09, 0x7F, 0x01, 0x7F,
    0x00, 0x66, 0x89, 0x95, 0x6A,
    0x60, 0x60, 0x60, 0x60, 0x60,
    0x94, 0xA2, 0xFF, 0xA2, 0x94,
    0x08, 0x04, 0x7E, 0x04, 0x08,
    0x10, 0x20, 0x7E, 0x20, 0x10,
    0x08, 0x08, 0x2A, 0x1C, 0x08,
    0x08, 0x1C, 0x2A, 0x08, 0x08,
    0x1E, 0x10, 0x10, 0x10, 0x10,
    0x0C, 0x1E, 0x0C, 0x1E, 0x0C,
    0x30, 0x38, 0x3E, 0x38, 0x30,
    0x06, 0x0E, 0x3E, 0x0E, 0x06,
    0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x5F, 0x00, 0x00,
    0x00, 0x07, 0x00, 0x07, 0x00,
    0x14, 0x7F, 0x14, 0x7F, 0x14,
    0x24, 0x2A, 0x7F, 0x2A, 0x12,
    0x23, 0x13, 0x08, 0x64, 0x62,
    0x36, 0x49, 0x56, 0x20, 0x50,
    0x00, 0x08, 0x07, 0x03, 0x00,
    0x00, 0x1C, 0x22, 0x41, 0x00,
    0x00, 0x41, 0x22, 0x1C, 0x00,
    0x2A, 0x1C, 0x7F, 0x1C, 0x2A,
    0x08, 0x08, 0x3E, 0x08, 0x08,
    0x00, 0x80, 0x70, 0x30, 0x00,
    0x08, 0x08, 0x08, 0x08, 0x08,
    0x00, 0x00, 0x60, 0x60, 0x00,
    0x20, 0x10, 0x08, 0x04, 0x02,
    0x3E, 0x51, 0x49, 0x45, 0x3E,
    0x00, 0x42, 0x7F, 0x40, 0x00,
    0x72, 0x49, 0x49, 0x49, 0x46,
    0x21, 0x41, 0x49, 0x4D, 0x33,
    0x18, 0x14, 0x12, 0x7F, 0x10,
    0x27, 0x45, 0x45, 0x45, 0x39,
    0x3C, 0x4A, 0x49, 0x49, 0x31,
    0x41, 0x21, 0x11, 0x09, 0x07,
    0x36, 0x49, 0x49, 0x49, 0x36,
    0x46, 0x49, 0x49, 0x29, 0x1E,
    0x00, 0x00, 0x14, 0x00, 0x00,
    0x00, 0x40, 0x34, 0x00, 0x00,
    0x00, 0x08, 0x14, 0x22, 0x41,
    0x14, 0x14, 0x14, 0x14, 0x14,
    0x00, 0x41, 0x22, 0x14, 0x08,
    0x02, 0x01, 0x59, 0x09, 0x06,
    0x3E, 0x41, 0x5D, 0x59, 0x4E,
    0x7C, 0x12, 0x11, 0x12, 0x7C,
    0x7F, 0x49, 0x49, 0x49, 0x36,
    0x3E, 0x41, 0x41, 0x41, 0x22,
    0x7F, 0x41, 0x41, 0x41, 0x3E,
    0x7F, 0x49, 0x49, 0x49, 0x41,
    0x7F, 0x09, 0x09, 0x09, 0x01,
    0x3E, 0x41, 0x41, 0x51, 0x73,
    0x7F, 0x08, 0x08, 0x08, 0x7F,
    0x00, 0x41, 0x7F, 0x41, 0x00,
    0x20, 0x40, 0x41, 0x3F, 0x01,
    0x7F, 0x08, 0x14, 0x22, 0x41,
    0x7F, 0x40, 0x40, 0x40, 0x40,
    0x7F, 0x02, 0x1C, 0x02, 0x7F,
    0x7F, 0x04, 0x08, 0x10, 0x7F,
    0x3E, 0x41, 0x41, 0x41, 0x3E,
    0x7F, 0x09, 0x09, 0x09, 0x06,
    0x3E, 0x41, 0x51, 0x21, 0x5E,
    0x7F, 0x09, 0x19, 0x29, 0x46,
    0x26, 0x49, 0x49, 0x49, 0x32,
    0x03, 0x01, 0x7F, 0x01, 0x03,
    0x3F, 0x40, 0x40, 0x40, 0x3F,
    0x1F, 0x20, 0x40, 0x20, 0x1F,
    0x3F, 0x40, 0x38, 0x40, 0x3F,
    0x63, 0x14, 0x08, 0x14, 0x63,
    0x03, 0x04, 0x78, 0x04, 0x03,
    0x61, 0x59, 0x49, 0x4D, 0x43,
    0x00, 0x7F, 0x41, 0x41, 0x41,
    0x02, 0x04, 0x08, 0x10, 0x20,
    0x00, 0x41, 0x41, 0x41, 0x7F,
    0x04, 0x02, 0x01, 0x02, 0x04,
    0x40, 0x40, 0x40, 0x40, 0x40,
    0x00, 0x03, 0x07, 0x08, 0x00,
    0x20, 0x54, 0x54, 0x78, 0x40,
    0x7F, 0x28, 0x44, 0x44, 0x38,
    0x38, 0x44, 0x44, 0x44, 0x28,
    0x38, 0x44, 0x44, 0x28, 0x7F,
    0x38, 0x54, 0x54, 0x54, 0x18,
    0x00, 0x08, 0x7E, 0x09, 0x02,
    0x18, 0xA4, 0xA4, 0x9C, 0x78,
    0x7F, 0x08, 0x04, 0x04, 0x78,
    0x00, 0x44, 0x7D, 0x40, 0x00,
    0x20, 0x40, 0x40, 0x3D, 0x00,
    0x7F, 0x10, 0x28, 0x44, 0x00,
    0x00, 0x41, 0x7F, 0x40, 0x00,
    0x7C, 0x04, 0x78, 0x04, 0x78,
    0x7C, 0x08, 0x04, 0x04, 0x78,
    0x38, 0x44, 0x44, 0x44, 0x38,
    0xFC, 0x18, 0x24, 0x24, 0x18,
    0x18, 0x24, 0x24, 0x18, 0xFC,
    0x7C, 0x08, 0x04, 0x04, 0x08,
    0x48, 0x54, 0x54, 0x54, 0x24,
    0x04, 0x04, 0x3F, 0x44, 0x24,
    0x3C, 0x40, 0x40, 0x20, 0x7C,
    0x1C, 0x20, 0x40, 0x20, 0x1C,
    0x3C, 0x40, 0x30, 0x40, 0x3C,
    0x44, 0x28, 0x10, 0x28, 0x44,
    0x4C, 0x90, 0x90, 0x90, 0x7C,
    0x44, 0x64, 0x54, 0x4C, 0x44,
    0x00, 0x08, 0x36, 0x41, 0x00,
    0x00, 0x00, 0x77, 0x00, 0x00,
    0x00, 0x41, 0x36, 0x08, 0x00,
    0x02, 0x01, 0x02, 0x04, 0x02,
    0x3C, 0x26, 0x23, 0x26, 0x3C,
    0x1E, 0xA1, 0xA1, 0x61, 0x12,
    0x3A, 0x40, 0x40, 0x20, 0x7A,
    0x38, 0x54, 0x54, 0x55, 0x59,
    0x21, 0x55, 0x55, 0x79, 0x41,
    0x21, 0x54, 0x54, 0x78, 0x41,
    0x21, 0x55, 0x54, 0x78, 0x40,
    0x20, 0x54, 0x55, 0x79, 0x40,
    0x0C, 0x1E, 0x52, 0x72, 0x12,
    0x39, 0x55, 0x55, 0x55, 0x59,
    0x39, 0x54, 0x54, 0x54, 0x59,
    0x39, 0x55, 0x54, 0x54, 0x58,
    0x00, 0x00, 0x45, 0x7C, 0x41,
    0x00, 0x02, 0x45, 0x7D, 0x42,
    0x00, 0x01, 0x45, 0x7C, 0x40,
    0xF0, 0x29, 0x24, 0x29, 0xF0,
    0xF0, 0x28, 0x25, 0x28, 0xF0,
    0x7C, 0x54, 0x55, 0x45, 0x00,
    0x20, 0x54, 0x54, 0x7C, 0x54,
    0x7C, 0x0A, 0x09, 0x7F, 0x49,
    0x32, 0x49, 0x49, 0x49, 0x32,
    0x32, 0x48, 0x48, 0x48, 0x32,
    0x32, 0x4A, 0x48, 0x48, 0x30,
    0x3A, 0x41, 0x41, 0x21, 0x7A,
    0x3A, 0x42, 0x40, 0x20, 0x78,
    0x00, 0x9D, 0xA0, 0xA0, 0x7D,
    0x39, 0x44, 0x44, 0x44, 0x39,
    0x3D, 0x40, 0x40, 0x40, 0x3D,
    0x3C, 0x24, 0xFF, 0x24, 0x24,
    0x48, 0x7E, 0x49, 0x43, 0x66,
    0x2B, 0x2F, 0xFC, 0x2F, 0x2B,
    0xFF, 0x09, 0x29, 0xF6, 0x20,
    0xC0, 0x88, 0x7E, 0x09, 0x03,
    0x20, 0x54, 0x54, 0x79, 0x41,
    0x00, 0x00, 0x44, 0x7D, 0x41,
    0x30, 0x48, 0x48, 0x4A, 0x32,
    0x38, 0x40, 0x40, 0x22, 0x7A,
    0x00, 0x7A, 0x0A, 0x0A, 0x72,
    0x7D, 0x0D, 0x19, 0x31, 0x7D,
    0x26, 0x29, 0x29, 0x2F, 0x28,
    0x26, 0x29, 0x29, 0x29, 0x26,
    0x30, 0x48, 0x4D, 0x40, 0x20,
    0x38, 0x08, 0x08, 0x08, 0x08,
    0x08, 0x08, 0x08, 0x08, 0x38,
    0x2F, 0x10, 0xC8, 0xAC, 0xBA,
    0x2F, 0x10, 0x28, 0x34, 0xFA,
    0x00, 0x00, 0x7B, 0x00, 0x00,
    0x08, 0x14, 0x2A, 0x14, 0x22,
    0x22, 0x14, 0x2A, 0x14, 0x08,
    0x95, 0x00, 0x22, 0x00, 0x95,
    0xAA, 0x00, 0x55, 0x00, 0xAA,
    0xAA, 0x55, 0xAA, 0x55, 0xAA,
    0x00, 0x00, 0x00, 0xFF, 0x00,
    0x10, 0x10, 0x10, 0xFF, 0x00,
    0x14, 0x14, 0x14, 0xFF, 0x00,
    0x10, 0x10, 0xFF, 0x00, 0xFF,
    0x10, 0x10, 0xF0, 0x10, 0xF0,
    0x14, 0x14, 0x14, 0xFC, 0x00,
    0x14, 0x14, 0xF7, 0x00, 0xFF,
    0x00, 0x00, 0xFF, 0x00, 0xFF,
    0x14, 0x14, 0xF4, 0x04, 0xFC,
    0x14, 0x14, 0x17, 0x10, 0x1F,
    0x10, 0x10, 0x1F, 0x10, 0x1F,
    0x14, 0x14, 0x14, 0x1F, 0x00,
    0x10, 0x10, 0x10, 0xF0, 0x00,
    0x00, 0x00, 0x00, 0x1F, 0x10,
    0x10, 0x10, 0x10, 0x1F, 0x10,
    0x10, 0x10, 0x10, 0xF0, 0x10,
    0x00, 0x00, 0x00, 0xFF, 0x10,
    0x10, 0x10, 0x10, 0x10, 0x10,
    0x10, 0x10, 0x10, 0xFF, 0x10,
    0x00, 0x00, 0x00, 0xFF, 0x14,
    0x00, 0x00, 0xFF, 0x00, 0xFF,
    0x00, 0x00, 0x1F, 0x10, 0x17,
    0x00, 0x00, 0xFC, 0x04, 0xF4,
    0x14, 0x14, 0x17, 0x10, 0x17,
    0x14, 0x14, 0xF4, 0x04, 0xF4,
    0x00, 0x00, 0xFF, 0x00, 0xF7,
    0x14, 0x14, 0x14, 0x14, 0x14,
    0x14, 0x14, 0xF7, 0x00, 0xF7,
    0x14, 0x14, 0x14, 0x17, 0x14,
    0x10, 0x10, 0x1F, 0x10, 0x1F,
    0x14, 0x14, 0x14, 0xF4, 0x14,
    0x10, 0x10, 0xF0, 0x10, 0xF0,
    0x00, 0x00, 0x1F, 0x10, 0x1F,
    0x00, 0x00, 0x00, 0x1F, 0x14,
    0x00, 0x00, 0x00, 0xFC, 0x14,
    0x00, 0x00, 0xF0, 0x10, 0xF0,
    0x10, 0x10, 0xFF, 0x10, 0xFF,
    0x14, 0x14, 0x14, 0xFF, 0x14,
    0x10, 0x10, 0x10, 0x1F, 0x00,
    0x00, 0x00, 0x00, 0xF0, 0x10,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
    0xFF, 0xFF, 0xFF, 0x00, 0x00,
    0x00, 0x00, 0x00, 0xFF, 0xFF,
    0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
    0x38, 0x44, 0x44, 0x38, 0x44,
    0x7C, 0x2A, 0x2A, 0x3E, 0x14,
    0x7E, 0x02, 0x02, 0x06, 0x06,
    0x02, 0x7E, 0x02, 0x7E, 0x02,
    0x63, 0x55, 0x49, 0x41, 0x63,
    0x38, 0x44, 0x44, 0x3C, 0x04,
    0x40, 0x7E, 0x20, 0x1E, 0x20,
    0x06, 0x02, 0x7E, 0x02, 0x02,
    0x99, 0xA5, 0xE7, 0xA5, 0x99,
    0x1C, 0x2A, 0x49, 0x2A, 0x1C,
    0x4C, 0x72, 0x01, 0x72, 0x4C,
    0x30, 0x4A, 0x4D, 0x4D, 0x30,
    0x30, 0x48, 0x78, 0x48, 0x30,
    0xBC, 0x62, 0x5A, 0x46, 0x3D,
    0x3E, 0x49, 0x49, 0x49, 0x00,
    0x7E, 0x01, 0x01, 0x01, 0x7E,
    0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
    0x44, 0x44, 0x5F, 0x44, 0x44,
    0x40, 0x51, 0x4A, 0x44, 0x40,
    0x40, 0x44, 0x4A, 0x51, 0x40,
    0x00, 0x00, 0xFF, 0x01, 0x03,
    0xE0, 0x80, 0xFF, 0x00, 0x00,
    0x08, 0x08, 0x6B, 0x6B, 0x08,
    0x36, 0x12, 0x36, 0x24, 0x36,
    0x06, 0x0F, 0x09, 0x0F, 0x06,
    0x00, 0x00, 0x18, 0x18, 0x00,
    0x00, 0x00, 0x10, 0x10, 0x00,
    0x30, 0x40, 0xFF, 0x01, 0x01,
    0x00, 0x1F, 0x01, 0x01, 0x1E,
    0x00, 0x19, 0x1D, 0x17, 0x12,
    0x00, 0x3C, 0x3C, 0x3C, 0x3C,
    0x00, 0x00, 0x00, 0x00, 0x00,
};


/****************************************8*16的点阵************************************/
const unsigned char F8X16[]=	  
{
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 0
  0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
  0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
  0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
  0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
  0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% 5
  0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& 6
  0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' 7
  0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( 8
  0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) 9
  0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* 10
  0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ 11
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, 12
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 13
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 14
  0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// 15
  0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 16
  0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 17
  0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 18
  0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 19
  0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 20
  0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 21
  0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 22
  0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 23
  0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 24
  0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 25
  0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: 26
  0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; 27
  0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< 28
  0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= 29
  0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> 30
  0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? 31
  0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@ 32
  0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 33
  0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 34
  0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 35
  0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 36
  0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 37
  0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 38
  0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 39
  0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H 40
  0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 41
  0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 42
  0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 43
  0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 44
  0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 45
  0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 46
  0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 47
  0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 48
  0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 49
  0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 50
  0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 51
  0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 52
  0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 53
  0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 54
  0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 55
  0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 56
  0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 57
  0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 58
  0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ 59
  0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ 60
  0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] 61
  0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ 62
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ 63
  0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` 64
  0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a 65
  0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b 66
  0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c 67
  0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d 68
  0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e 69
  0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f 70
  0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g 71
  0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72
  0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i 73
  0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j 74
  0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k 75
  0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l 76
  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m 77
  0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n 78
  0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o 79
  0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p 80
  0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q 81
  0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r 82
  0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s 83
  0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t 84
  0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u 85
  0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v 86
  0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w 87
  0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x 88
  0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y 89
  0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z 90
  0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ 91
  0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//| 92
  0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} 93
  0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
};
//使用常用取模软件 PCtoLCD2002
//汉字采用 16x16 阴码 列行式 逆向
//中文字库
struct Cn16CharTypeDef const CN16CHAR[NUM_OFCHINESE]=
{
"一",0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"一",0*/
"只",0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,
0x00,0x80,0x40,0x23,0x19,0x01,0x01,0x01,0x01,0x01,0x09,0x13,0x20,0xC0,0x00,0x00,/*"只",1*/
"程",0x24,0x24,0xA4,0xFE,0x23,0x22,0x00,0x3E,0x22,0x22,0x22,0x22,0x22,0x3E,0x00,0x00,
0x08,0x06,0x01,0xFF,0x01,0x06,0x40,0x49,0x49,0x49,0x7F,0x49,0x49,0x49,0x41,0x00,/*"程",2*/
"序",0x00,0x00,0xFC,0x04,0x04,0x04,0x14,0x15,0x56,0x94,0x54,0x34,0x14,0x04,0x04,0x00,
0x40,0x30,0x0F,0x00,0x01,0x01,0x01,0x41,0x81,0x7F,0x01,0x01,0x01,0x05,0x03,0x00,/*"序",3*/
"缘",0x20,0x30,0xAC,0x63,0x30,0x00,0x20,0x2C,0xAB,0x6A,0xAA,0x2A,0x3A,0x26,0xA0,0x00,
0x22,0x67,0x22,0x12,0x12,0x00,0x49,0x49,0x24,0x52,0x89,0x7F,0x02,0x0D,0x10,0x00,/*"缘",4*/


};

五、使用教程

1、使用前需先初始化OLED_Init();

2、显示完毕需添加代码UpdateScreen();

3、字体大小范围:0-3

六、巨人之肩

STM32 HAL 硬件IIC+DMA+简单图形库控制OLED

STM32 OLED动画显示DMA+IIC刷新(理论可达42+帧率)

七、源码提供

资源【STM32+HAL】地表最强高刷OLED显示配置

  • 10
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要在STM32上使用OLED屏幕显示,需要进行以下I2C配置: 1. 首先,需要在STM32上启用I2C总线。可以使用STM32CubeMX工具来配置I2C总线。 2. 然后,需要连接OLED屏幕到STM32I2C总线上。通常,OLED屏幕会有一个I2C接口,需要将其连接到STM32I2C引脚上。 3. 接下来,需要编写代码来初始化I2C总线和OLED屏幕。可以使用STM32 HAL库来编写代码。 4. 在初始化完成后,就可以开始向OLED屏幕发送数据了。可以使用OLED屏幕的数据手册来了解如何发送数据。 总的来说,STM32 OLED屏幕显示需要进行I2C配置,包括启用I2C总线、连接OLED屏幕、初始化I2C总线和OLED屏幕,以及发送数据。 ### 回答2: 对于stm32oled屏幕的i2c通讯配置而言,我们需要先确认两个非常重要的参数: 1. I2C时钟频率 在STM32中,I2C的时钟频率是由APB1总线时钟来决定的,其频率一般为48MHz,因此我们需要在代码中设置I2C的时钟速率。根据规范,I2C的最高速率为400Khz,但是要求我们对于电路噪声等因素进行实际测试而定。 2. I2C从机地址 若要让stm32OLED屏幕进行通讯,则需要知道OLED屏幕的I2C从机地址。可以在OLED屏幕的数据手册中获得该地址。OLED屏幕的I2C从机地址由八位组成,通常为0x3C或者0x3D。 I2C配置过程需要我们完成以下步骤: 1. GPIO配置 首先,我们需要配置I2C所使用的GPIO引脚,一般选择SCL时钟线和SDA数据线。对于这两条线,需要选择AF复用模式,然后将GPIO的处理模式配置成推挽输出。代码示例如下: ``` GPIO_InitTypeDef GPIO_InitStruct; // 配置SCL时钟线预设信息 GPIO_InitStruct.Pin = GPIO_PIN_6; //SCL GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;//推挽输出 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); // 配置SDA数据线预设信息 GPIO_InitStruct.Pin = GPIO_PIN_7; //SDA GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;//推挽输出 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); ``` 2. I2C配置 在GPIO配置好后,我们还需要对I2C进行配置。主要需要设置I2C时钟频率、I2C从机地址以及ACK检测功能。以下是代码示例: ``` I2C_HandleTypeDef I2C_handle; I2C_handle.Instance = I2C1; I2C_handle.Init.ClockSpeed = 100000; //在这里设置I2C时钟速率 I2C_handle.Init.DutyCycle = I2C_DUTYCYCLE_2; I2C_handle.Init.OwnAddress1 = 0x00; //设置I2C的从机地址 I2C_handle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; I2C_handle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; I2C_handle.Init.OwnAddress2 = 0x00; I2C_handle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; I2C_handle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; HAL_I2C_Init(&I2C_handle); // 开启I2C ACK检测功能 HAL_I2CEx_EnableFastModePlus(I2C_handle.Instance); ``` 3. I2C读写操作 I2C的读写操作需要我们调用HAL库提供的函数,还需要一个OLED屏幕的I2C从机地址以及命令与数据内容,以下是代码示例: `HAL_I2C_Mem_Write(&I2C_handle, OLED_ADDR, cmd_addr, cmd_count, cmd_data, data_count, 10);` 其中,OLED_ADDR是OLED屏幕的I2C从机地址,cmd_count和data_count是命令和数据的字节数量,cmd_data是命令数组的指针,cmd_addr是命令指针的地址。 到此,I2C配置就完成了。我们可以使用I2C的读写功能,与OLED屏幕进行通讯,实现屏幕的显示和控制。 ### 回答3: STM32OLED屏幕是一种基于I2C协议的128x64 OLED显示屏,使用STM32单片机良好而且非常适合低功耗的应用。在使用STM32OLED屏幕之前,需要进行I2C配置。 首先,在STM32CubeMX中需要开启I2C1外设,然后在Pinout & Configuration选项卡中查找对应串行数据(SDA)和时钟(SCL)引脚,将其映射到正确的引脚上。 接下来,设置I2C1外设参数,包括时钟频率,地址模式等等。在Configuration选项卡中,找到I2C1设置,并且将时钟频率调整到具体的应用需求,根据需要调整I2C地址模式(7位或10位)。 完成了I2C1的主要配置,接下来,需要借助硬件库或者HAL库,来实现屏幕显示。在各种库中,每个函数和形式都差异很大,具体实现方式也不同,但基本原理是相似的。 首先,代码需要初始化I2C1。这包括初始化GPIO引脚、I2C1、时钟和其他特色设置,以便正确控制OLED显示屏。在创建初始化函数时,必须检查I2C返回状态,以确保没有发生错误。如果发生错误,调试过程建议在应用程序中添加错误处理代码来确保能够捕捉到错误和失误。 接着,代码需要实现I2C数据发送和显示屏写入过程。根据所选库,实现过程将有所不同。最常见的方法是创建写入函数并使用数据缓冲区,以将数据发送到OLED显示屏。 在使用STM32OLED屏幕进行I2C配置时,务必使用正确的引脚、正确的时钟频率,并输入正确的地址模式,以确保它能正常工作。需要检查I2C返回状态,确保没有发生错误,使用正确的库并实现正确的I2C数据发送和显示屏写入过程,以保障正确的使用STM32OLED屏幕。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值