辅助舍友做毕业设计中的显示部分,优化了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);//技
一个字:太呆了!
首先,汉字显示是靠其在字库内的索引位置来得到点阵数据然后显示,索引必须自己去弄,无法直接在程序中直观地看出到底显示了什么汉字;
其次,中文英文显示函数是独立的,要是中英文混显动态长度显示怕不是要折腾死人。
用户体验极差。
为了解决上面临两个问题,笔者优化了汉字字库的结构和汉字显示函数,并实现了中英文混合现实并自动换行。
先来看看调用方式:
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 软件取字模,
软件设置如下
其他的操作就不谈了,很简单的,要是觉得用的不习惯,改天出个做简单的取字模软件教程哈哈,滑稽
再然后呢,按照如下的组织方式放到字库里面
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可就跳出去了,不会执行到写字符的程序的
那么,这么好的程序在哪里呢?↓←→↖↗↙↘↕
↓
- ←(看见了吗?滑稽)
↑
1ots