今天在写智能灯光的界面,用的是STM32和3.2寸TFT 彩屏。
我们在设计一个显示界面时,常常需要考虑一下汉字字体的大小,常见的字体有像素值为16*16、24*24、32*32的,而有时候我们界面用的汉字也不是很多,或者没有SD卡,没有保存相应的汉字字库,这时候就可以自己用取模软件,取相应的几个汉字即可,我用的下面这款取模软件
下面就是各个大小字体对应的参数:
16*16:宋体12,即小四,实际大小16*16,刚刚好
24*24:宋体18,即小二,实际大小24*24,刚刚好
32*32:宋体24,即小一,实际大小32*33,所以多出来32个二进制,即四个字节,删去最后面四个字节即可(因为一般都是零,影响不大)
注意:选择横向取模,C51方式取模。
接下来就是相关底层驱动函数的编写,我们需要将汉字及相应而二进制编码存到一个头文件中,我是分别命名了以下三个头文件,用来存储不同字体,hz16x16.h、hz16x16.h、hz16x16.h
具体代码如下:
#ifndef HZ16x16_H
#define HZ16x16_H
// ------------------ 汉字字模的数据结构定义 ------------------------ //
struct typFNT_HZ16 // 汉字字模数据结构
{
unsigned char Index[3]; // 汉字内码索引 存放内码 如"硕" 但是一个字要两个字节表示
unsigned char Msk[32]; // 点阵码数据 存放内码后对应的 点阵序列 每个字需要32个字节的点阵序列
};
/////////////////////////////////////////////////////////////////////////
// 汉字字模表 //
// 汉字库: 宋体16.dot,横向取模左高位,数据排列:从左到右从上到下 //
/////////////////////////////////////////////////////////////////////////
/*这个结构,很简单的:一个是内码,一个点阵序列,
以前的点阵库是按内码顺序放的,不需要内码索引的,
如果只放部分汉字,就需要内码索引了。
一般内码两个字节就行了,多用1个字节是加了个尾0而已,
这样,汉字内码处直接放汉字字符淳涂桑? */
struct typFNT_HZ16 codeHZ_16[] = // 数据表
{
/*-- 文字: 云 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
"云",0x00,0x00,0x00,0x30,0x3F,0xF8,0x00,0x00,0x00,0x00,0x00,0x0C,0xFF,0xFE,0x03,0x00,
0x07,0x00,0x06,0x40,0x0C,0x20,0x18,0x10,0x31,0xF8,0x7F,0x0C,0x20,0x08,0x00,0x00,
};
#endif
程序很简单,可见汉字及相关二进制编码是用的结构体来存储的,
成员如下:
unsigned char Index[3]; // 汉字内码索引, 存放内码 如”硕” 但是一个字要两个字节表示,这里多了一个,就是加了零
unsigned char Msk[32]; // // 点阵码数据 存放内码后对应的 点阵序列 每个字需要32个字节的点阵序列(24*24字体和32*32字体,有所区别,自己算出即可)
接下来就是在TFT彩屏显示的程序编写,代码如下:
//写入单个汉字 16*16
//x,y:起点坐标
// c[2] 汉字
//dcolor 字体颜色
//bgcolor 背景颜色
void PutHZ1616(unsigned short x, unsigned short y, unsigned char c[2], unsigned int dcolor,unsigned int bgcolor)
{
unsigned int i,j,k;
//c[2] 把要显示的字 以两个字节的形式放入 数组c中
LCD_Set_Window(x,y,16,16);
LCD_SetCursor(x,y);
LCD_WriteRAM_Prepare();
for (k=0;k<64;k++)
{ //64标示自建汉字库中的个数,循环查询内码 一个汉字需要两个字节
if ((codeHZ_16[k].Index[0]==c[0])&&(codeHZ_16[k].Index[1]==c[1])) //寻找对应汉字
{
for(i=0;i<32;i++)
{
unsigned short m=codeHZ_16[k].Msk[i];
for(j=0;j<8;j++)
{
if((m&0x80)==0x80)
{
LCD_WR_DATA(dcolor);
}
else
{
LCD_WR_DATA(bgcolor);
}
m<<=1;
}
}
}
}
}
关键代码分析:
第一个for循环,就是查询自己编写的字库里的汉字,可以根据自己汉字多少改写。
if ((codeHZ_16[k].Index[0]==c[0])&&(codeHZ_16[k].Index[1]==c[1])) 这句代码意思就是对应于前面头文件里的编码,寻找对应汉字
再接下来一个循环——for(i=0;i<32;i++) ,总共32个char型数据,即32个字节,循环。
for(j=0;j<8;j++) ——这句代码以后,就是将1处写前景色,0处写背景色。
还有就是显示多个汉字函数
//显示多个汉字或字符 16*16
//在指定位置显示一个字符大小16*16)
//dcolor为内容颜色,gbcolor为背静颜色 !='\0'
void showhz16str(unsigned int x1,unsigned int y1,unsigned char *str,unsigned int dcolor,unsigned int bgcolor)
{
unsigned char l=0;
while(*str)
{
if(*str<0x80)
{
LCD_ShowString1(x1,y1,16,(unsigned char*)str);
x1+=7;
str++;
}
else
{
PutHZ1616(x1+l*8,y1,(unsigned char*)str,dcolor, bgcolor);
str+=2;l+=2;
}
}
}