0.96吋 OLED 12864 汉字 显示 优化

时间:2024-04-02 15:52:59

辅助舍友做毕业设计中的显示部分,优化了OLED的汉字显示,简化了函数的调用方式,略有小得,留做记录


未经授权,不得转载!_(:з)∠)_


前言

中景园的给的例程中的汉字显示函数调用方式是这样的:

OLED_ShowCHinese(0,0,0);//中
OLED_ShowCHinese(18,0,1);//景
OLED_ShowCHinese(36,0,2);//园
OLED_ShowCHinese(54,0,3);//电
OLED_ShowCHinese(72,0,4);//子
OLED_ShowCHinese(90,0,5);//科
OLED_ShowCHinese(108,0,6);//技

0.96吋 OLED 12864 汉字 显示 优化
一个字:太呆了!
首先,汉字显示是靠其在字库内的索引位置来得到点阵数据然后显示,索引必须自己去弄,无法直接在程序中直观地看出到底显示了什么汉字;
其次,中文英文显示函数是独立的,要是中英文混显动态长度显示怕不是要折腾死人。
用户体验极差。
为了解决上面临两个问题,笔者优化了汉字字库的结构和汉字显示函数,并实现了中英文混合现实并自动换行。
先来看看调用方式:

OLED_ShowText(0,0,"苍穹1234",1);//中英文混显

sprintf(temparr,"苍穹%d",i);
OLED_ShowText(20,4,temparr,0);//动态显示

一、汉字字库

先介绍一点前置知识:
为了方便计算机辨认、接收和处理汉字,为每个汉字编一个唯一的代码,这就是汉字编码。
几乎所有的软件中文显示都是用的都是信息交换用汉字编码字符集GB2312(VSC也是可修改为GB2312的),GB2312共收入汉字6763个和非汉字图形字符682个。整个字符集分成94个区,每区有94个位。每个区位上只有一个字符,因此可用所在的区和位来对汉字进行编码,称为区位码。

为了方便查找汉字,我们也将使用到汉字的区位码。

在制作字库之前,先定义一个结构体类型:

typedef struct
{
	char name[3];
	char dat[32];
}chinese;

结构体的第一个成员name[3] 用来存放汉字的区码和位码以及一个字符串结束符 ‘\0’ ,这里的 ‘\0’ 并不是必要的。
结构体的第二个成员dat[32] 用来存放汉字点阵数据,这里采用的是16*16的汉字,16*16/8=32,故单个汉字的点阵数据为32字节。
拥有了此结构体类型后,我们就可以开始制作字库了QwQ
首先声明一个结构体数组,长度不用填写

chinese Hzk[]={};

然后用 PCtoLCD2002.exe 软件取字模,
软件设置如下
0.96吋 OLED 12864 汉字 显示 优化
其他的操作就不谈了,很简单的,要是觉得用的不习惯,改天出个做简单的取字模软件教程哈哈,滑稽
再然后呢,按照如下的组织方式放到字库里面

chinese Hzk[]={
"中",
{0x00,0x00,0xF0,0x10,0x10,0x10,0x10,0xFF,0x10,0x10,0x10,0x10,0xF0,0x00,0x00,0x00,0x00,0x00,0x0F,0x04,0x04,0x04,0x04,0xFF,0x04,0x04,0x04,0x04,0x0F,0x00,0x00,0x00},
"景",
{0x40,0x40,0x40,0x5F,0x55,0x55,0x55,0x75,0x55,0x55,0x55,0x5F,0x40,0x40,0x40,0x00,0x00,0x40,0x20,0x0F,0x09,0x49,0x89,0x79,0x09,0x09,0x09,0x0F,0x20,0x40,0x00,0x00},
"园",
{0x00,0xFE,0x02,0x42,0x4A,0xCA,0x4A,0x4A,0xCA,0x4A,0x4A,0x42,0x02,0xFE,0x00,0x00,0x00,0xFF,0x40,0x50,0x4C,0x43,0x40,0x40,0x4F,0x50,0x50,0x5C,0x40,0xFF,0x00,0x00},
};

顺序是无所谓的。

二、汉字显示函数

/********************************************************************************
* @函数名:         OLED_ShowCHineseWord
* @函数描述:       在指定位置显示占宽16*16的单个 汉字
* @函数作者:       矛盾聚合体
* @输入参数:
                    参数名    参数类型  参数描述  
                    @x:      u8         列坐标,0~127
                    @y:      u8         行坐标,0~7
                    @str:    u8*        要显示的汉字
                    @flag:   u8         反白标志,非0时反白显示
* @返回值:         void
* @其他:           
********************************************************************************/
void OLED_ShowCHineseWord(u8 x,u8 y,u8* str,u8 flag)
{
	u8 t=0;
	u16 index;
	for(index=0; index<sizeof(Hzk)/35; index++)
	{
		if(Hzk[index].name[0] == str[0]&&Hzk[index].name[1] == str[1])//对比汉字区码位码
		{
			OLED_Set_Pos(x,y);	//设置OLED光标位置
			for(t=0; t<16; t++)//先写汉字上半部分数据
			{
				if(flag==0)OLED_WR_Byte(Hzk[index].dat[t],OLED_DATA);
				else OLED_WR_Byte(~Hzk[index].dat[t],OLED_DATA);
			 }
			OLED_Set_Pos(x,y+1);//设置OLED光标位置
			for(t=0; t<16; t++)	//再写汉字下半部分数据
			{
				if(flag==0)OLED_WR_Byte(Hzk[index].dat[t+16],OLED_DATA);
				else OLED_WR_Byte(~Hzk[index].dat[t+16],OLED_DATA);
			 }
		} 
	} 
}

调用方式:

OLED_ShowCHineseWord(0,6,"中",1);// 在6行0列反白(即高亮)显示“中”字

额,代码贴出来好像就没啥好说的了_(:з)∠)_

三、中英文混合显示函数

首先,要对例程给的ASCII字符显示函数做一定的修改:

/********************************************************************************
* @函数名:         OLED_ShowChar
* @函数描述:       在指定位置显示占宽8*16的单个ASCII字符
* @函数作者:       矛盾聚合体
* @输入参数:
                    参数名    参数类型  参数描述  
                    @x:      u8         列坐标,0~127
                    @y:      u8         行坐标,0~7
                    @chr:    u8         要显示的ASCII字符
                    @flag:   u8         反白标志,非0时反白显示
* @返回值:         void
* @其他:           
********************************************************************************/
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 flag)
{      	
	unsigned char c=0,i=0;	
	c=chr-' ';//得到偏移后的值			
	if(x>Max_Column-1){x=0;y=y+2;}
	OLED_Set_Pos(x,y);	
	for(i=0;i<8;i++)
	{
		if(flag==1)OLED_WR_Byte(~F8X16[c*16+i],OLED_DATA);
		else OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
	}
	
	OLED_Set_Pos(x,y+1);
	for(i=0;i<8;i++)
	{
		if(flag==1)OLED_WR_Byte(~F8X16[c*16+i+8],OLED_DATA);
		else OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
	}
}

然后。。。直接上代码吧,尽在不言中

/********************************************************************************
* @函数名:         OLED_ShowText
* @函数描述:       在指定位置显示中英文字符串
* @函数作者:       矛盾聚合体
* @输入参数:
                    参数名    参数类型  参数描述  
                    @x:      u8         列坐标,0~127
                    @y:      u8         行坐标,0~7
                    @str:    u8*        要显示的字符串
                    @flag:   u8         反白标志,非0时反白显示
* @返回值:         void
* @其他:           
********************************************************************************/
void OLED_ShowText(u8 x,u8 y,u8* str,u8 flag)
{
	u8 tempstr[3] = {'\0'};
	while(*str!='\0')
	{
		if(*str&0x80)
		{
			tempstr[0]=*str++;
			tempstr[1]=*str++;
			OLED_ShowCHineseWord(x,y,tempstr,flag);
			x+=16;
			if(*str&0x80)//判断下一个字符是中文还是英文
			{
				if(x>=112){y++;y++;x=0;}//修改地址 
			}
			else
			{
				if(x>=120){y++;y++;x=0;}//修改地址
			}

		}
		else
		{
			OLED_ShowChar(x,y,*str++,flag);
			x+=8;
			if(*str&0x80)
			{
				if(x>=112){y++;y++;x=0;}//修改地址 
			}
			else
			{
				if(x>=120){y++;y++;x=0;}//修改地址
			}
		}
	}
}

汉字和ASCII码的最大的区别就是,汉字的区码和位码最高为都是1,而ASCII码最高位为0,依据此,将汉字和ASCII字符区分开来。
为了实现自动换行,这里做了一点小处理,每次写字符后,光标位置移动,并根据下一个字符的类型判断是否换行:

if(*str&0x80)
{
	if(x>=112){y++;y++;x=0;}//修改地址 
}
else
{
	if(x>=120){y++;y++;x=0;}//修改地址
}

有读者可能就要问了,要是下一个字符是结束符怎么办?你没做处理鸭?
笑话!再到 while可就跳出去了,不会执行到写字符的程序的
0.96吋 OLED 12864 汉字 显示 优化
那么,这么好的程序在哪里呢?↓←→↖↗↙↘↕


- ←(看见了吗?滑稽)

1ots