一个显示函数实现不同字体在LCD上的显示
转自 http://blog.163.com/zhaojun_xf/blog/static/300505802015728144168/
有一点LCD显示基础的读者都知道,我们在提前任何字体的字库时,实际上字符都是按照一点的点阵方块构成,常见的英文字符有8x8,8x16等,而比较常见的中文字符有12x12,16x16等,不管是多大点阵的字符,其存储模式基本都是以一定的点阵模式进行存储。在我们取字摸的时候,根据显示的方向,可以有自上而下,从左往右等等。不管是那种取摸方式,只要写点的顺序和取摸的方向一致就可以正确显示了。
例如:下面一个是“1”,一个是“中”,采用比较直观的取摸方式获得:
那么下面我们对这两种不同的字库数据进行显示
________,
___X____,
_XXX____,
___X____,
___X____,
___X____,
___X____,
___X____,
___X____,
_XXXXX__,
________
_____X__,________,
_____X__,________,
_____X__,________,
_XXXXXXX,XX______,
_X___X__,_X______,
_X___X__,_X______,
_X___X__,_X______,
_XXXXXXX,XX______,
_X___X__,_X______,
_____X__,________,
_____X__,________,
_____X__,________
![【原创】不同字体在LCD上的显示 - 我心永恒 - ARM嵌入式研发](http://img1.ph.126.net/Oa9E2TPQvh0HxkAl6Qj10g==/6630667543468295293.jpg)
总结:
从上面的描述不难发现一点,不管什么字体,什么字符,只要按照顺序把通过字摸软件获取的字摸数据,按照顺序一行一行的显示出来就可以实现任何字符的显示了。而不同字体不同的只是其行的像素点和款的像素点以及其字摸数据的不同而已。
实现:
既然不同字符或字体的显示都有共性,那么我们进行高度提炼,把它们的不同的地方用一个结构图进行定义,在生成不同的字摸时进行定义就可以了。
typedef struct
{
U8 Width; // 字体宽度
U8 Height; // 高度
U8 FstChr; // 起始字符
UC8 *Dat; // 字库起始地址
} TFT_FNT;
例如:定义16x32的字库【可以是上面那种直观的数据,也可以是下面这中十六进制数据】
const u8 ST16x32[] = {
/* @0 (16x32,H)@ [suki software]*/
0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00,
0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00,
0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00,
0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00,
0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00,
0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00,
0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00,
0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00,
。。。
};
TFT_FNT FNT16x32 =
{
16, // 宽为16
32, // 高为32
0x20, // 从0x20开始,表示0x20的特色字符我们没有取字摸
ST16x32, // 点阵数据
};
例如:定义16x32的字库48x64
const u8 AB48x64[] = {
/* @0 0(48x64,H)@ [suki software]*/
0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x1F,0xF8,0x00,0x00, 0x00,0x00,0xFF,0xFE,0x00,0x00,
0x00,0x03,0xFF,0xFF,0x80,0x00, 0x00,0x07,0xFF,0xFF,0xE0,0x00, 0x00,0x0F,0xFF,0xFF,0xF0,0x00, 0x00,0x1F,0xFF,0xFF,0xF8,0x00,
0x00,0x3F,0xFF,0xFF,0xF8,0x00, 0x00,0x7F,0xF8,0x3F,0xFC,0x00, 0x00,0x7F,0xE0,0x0F,0xFE,0x00, 0x00,0xFF,0xC0,0x03,0xFE,0x00,
0x00,0xFF,0x80,0x01,0xFF,0x00, 0x01,0xFF,0x00,0x01,0xFF,0x00, 0x01,0xFE,0x00,0x00,0xFF,0x00, 0x01,0xFE,0x00,0x00,0x7F,0x80,
0x03,0xFE,0x00,0x00,0x7F,0x80, 0x03,0xFC,0x00,0x00,0x7F,0x80, 0x03,0xFC,0x00,0x00,0x3F,0xC0, 0x03,0xFC,0x00,0x00,0x3F,0xC0,
0x07,0xF8,0x00,0x00,0x3F,0xC0, 0x07,0xF8,0x00,0x00,0x3F,0xC0, 0x07,0xF8,0x00,0x00,0x3F,0xC0, 0x07,0xF8,0x00,0x00,0x3F,0xC0,
0x07,0xF8,0x00,0x00,0x3F,0xE0, 0x07,0xF8,0x00,0x00,0x3F,0xE0, 0x07,0xF8,0x00,0x00,0x1F,0xE0, 0x07,0xF8,0x00,0x00,0x1F,0xE0,
0x07,0xF8,0x00,0x00,0x1F,0xE0, 0x07,0xF8,0x00,0x00,0x1F,0xE0, 0x07,0xF8,0x00,0x00,0x1F,0xE0, 0x07,0xF8,0x00,0x00,0x1F,0xE0,
0x07,0xF8,0x00,0x00,0x1F,0xE0, 0x07,0xF8,0x00,0x00,0x1F,0xE0, 0x07,0xF8,0x00,0x00,0x1F,0xE0, 0x07,0xF8,0x00,0x00,0x1F,0xE0,
0x07,0xF8,0x00,0x00,0x1F,0xE0, 0x07,0xF8,0x00,0x00,0x3F,0xE0, 0x07,0xF8,0x00,0x00,0x3F,0xC0, 0x07,0xF8,0x00,0x00,0x3F,0xC0,
0x07,0xF8,0x00,0x00,0x3F,0xC0, 0x07,0xF8,0x00,0x00,0x3F,0xC0, 0x07,0xF8,0x00,0x00,0x3F,0xC0, 0x03,0xFC,0x00,0x00,0x3F,0xC0,
0x03,0xFC,0x00,0x00,0x7F,0xC0, 0x03,0xFC,0x00,0x00,0x7F,0x80, 0x03,0xFC,0x00,0x00,0x7F,0x80, 0x01,0xFE,0x00,0x00,0x7F,0x80,
0x01,0xFE,0x00,0x00,0xFF,0x80, 0x01,0xFF,0x00,0x01,0xFF,0x00, 0x00,0xFF,0x80,0x01,0xFF,0x00, 0x00,0xFF,0xC0,0x03,0xFE,0x00,
0x00,0x7F,0xE0,0x0F,0xFE,0x00, 0x00,0x7F,0xF8,0x3F,0xFC,0x00, 0x00,0x3F,0xFF,0xFF,0xF8,0x00, 0x00,0x1F,0xFF,0xFF,0xF8,0x00,
0x00,0x0F,0xFF,0xFF,0xF0,0x00, 0x00,0x07,0xFF,0xFF,0xE0,0x00, 0x00,0x03,0xFF,0xFF,0x80,0x00, 0x00,0x00,0xFF,0xFE,0x00,0x00,
0x00,0x00,0x1F,0xF8,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,
}
TFT_FNT FNT48x64 =
{
48, // 宽为48
64, // 高为64
0x30, // 从0x30开始,表示0x30的特色字符我们没有取字摸
AB48x64, // 点阵数据
};
那么下面我们对这两种不同的字库数据进行显示
/**************************************************************************************
* FunctionName : TFTSetFont()
* Description : 设置字体
* EntryParameter : None
* ReturnValue : None
**************************************************************************************/
void TFTSetFont(TFT_FNT *pFnt)
{
memcpy(&TFTFnt, pFnt, sizeof(TFT_FNT));
}
先告诉显示函数,我们现在要显示的字库是那种,以便于采用不同的参数进行显示:
/**************************************************************************************
* FunctionName : TFTDisCharAt()
* Description : 在指定座标显示字符
* EntryParameter : x - 行坐标;y - 列坐标;chClr - 字符的颜色;bkClr - 字符背景颜色
* ReturnValue : None
**************************************************************************************/
void TFTDisCharAt(u16 x, u16 y, u8 chr, u16 chClr, u16 bkClr)
{
u8 font;
u16 tmpLen;
tmpLen = (TFTFnt.Width/8) * TFTFnt.Height; // 单个字符的字节数
TFTSetWindow(x, y, x+TFTFnt.Width-1, y+TFTFnt.Height-1); // 设置窗口大小
for (u16 i=0; i<tmpLen; i++)
{
font = TFTFnt.Dat[((chr-TFTFnt.FstChr)*tmpLen) + i]; // 对以字节点阵数据
for (u8 n=0; n<8; n++)
{
TFT_WR_DAT(((font << n) & 0x80) ? chClr : bkClr); // 一点一点的显示
}
}
}
显示原来其实非常简单,我们先定义一个显示字符的窗口,告诉LCD屏接下来需要显示的窗口。完成后,只要取窗口刚好能够显示的点阵数据发给LCD即可。这样显示是效率是非常高的,利用了LCD的地址自加功能,而不需要每次都告诉LCD的显示地址。当然,如果提前字库的方向与LCD的自加方向是不同的,这时就只能使用写点函数进行一个点一个点的写了。
接下来就简单了,显示哪一种字库,只需要在显示之前进行一些说明就可以了:
TFTSetFont(&FNT48x64);
TFTDisCharAt(0, 0, ’1‘, TFT_BLACK, TFT_WHITE);
怎么样,是不是非常简单,我们不需要为不同的字体,不同的字符编写每一种显示函数了,就一个显示函数就可以显示所以点阵字符。