1、在需要程序支持全部中文字库时,CPU内部FLASH往往不够用,这时候需要采用外部存储空间来存放字库数据。可以选用的外部存储空间有 外部FLASH、EEPROM、SD卡等。
2、汉字的编码方式有很多种,常用的为GBK或者GB2312。GB2312支持了全部的简体汉字约6000个,兼容ASCII码、
数学符号、罗马希腊的字母、日文的假名等,全部字体有7000多个,可以满足大部分情况下使用;
GBK在GB2312基础上增加了两万多个汉字(包括繁体字、生僻字等),涵盖了所有可能用的汉字。在这里采用的是GB2312编码方式。
3、字库数据通常是以二进制方式放在存储空间里,制作二进制字库的工具可以从网上下载到很多种,这里采用的是 “字模III 增强版 V3.91”,还有个“汉字字模点阵数据批量生成工具 V5.3”。这里我生成的是微软雅黑16号字体,文件名称为“
wryh16号 21x28 GB2312全.bin”,每个字大小为21x28,在UCGUI里字体名称为“
GUI_FontWRYH28”。
4、外部存储采用的是K9F2808U0C,16M*8 bits NAND FLASH。
5、准备工作完成后
第一步、编一个STM32的小程序,完成的功能是:将串口收到的数据按顺序存放入FLASH中。
第二步、用串口助手将二进制字库文件通过串口发送给STM32,STM32将字库存入FLASH。这里要知道每个字库数据的起始位置。(另外需要注意:网络上很多串口工具的功能都不太完善,质量参差不齐,有些有缺陷且没有提示,例如常用的一个SSCOM32,这个软件最多只能发送512K大小的二进制文件,在发送的文件超过512K时,512K后边的数据会丢失,并且没有提示;同时,这个工具无法在检验方式下发送数据。这里我用的是SSCOM4.2,可以满足使用要求。
)
第三步、UCGUI的显示字符函数并不能直接支持外部字库这种形式,需要修改两个文件,增加两个文件。外部字库是通过定义一种新的字体的方式加入到UCGUI中。
A、修改 GUI.h
增加一句,声明新增加的字体:
/*extern fonts*/
extern GUI_CONST_STORAGE GUI_FONT GUI_FontWRYH28;
B、修改
GUI_UC_EncodeNone.c
修改的地方比较多,
#include "GUI_Protected.h"
/*********************************************************************
*
* Static code
*
**********************************************************************
*/
/*********************************************************************
*
* _GetCharCode
*
* Purpose:
* Return the UNICODE character code of the current character.
*/
static U16 _GetCharCode(const char GUI_UNI_PTR * s) {
// return *(const U8 GUI_UNI_PTR *)s;
if((*s) > 0xa0)
{
return *(const U16 GUI_UNI_PTR *)s;
}else{
return *(const U8 GUI_UNI_PTR *)s;
}
}
/*********************************************************************
*
* _GetCharSize
*
* Purpose:
* Return the number of bytes of the current character.
*/
static int _GetCharSize(const char GUI_UNI_PTR * s) {
// GUI_USE_PARA(s);
// return 1;
if((*s) > 0xa0)
{
return 2;
}else{
return 1;
}
}
/*********************************************************************
*
* _CalcSizeOfChar
*
* Purpose:
* Return the number of bytes needed for the given character.
*/
static int _CalcSizeOfChar(U16 Char) {
// GUI_USE_PARA(Char);
// return 1;
if(Char > 0xa0a0)
{
return 2;
}else{
return 1;
}
}
/*********************************************************************
*
* _Encode
*
* Purpose:
* Encode character into 1/2/3 bytes.
*/
static int _Encode(char *s, U16 Char) {
// *s = (U8)(Char);
// return 1;
if(Char > 0xa0a0)
{
*((U16 *)s) = (U16)(Char);
return 2;
}else{
*s = (U8)(Char);
return 1;
}
}
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
/*********************************************************************
*
* _API_Table
*/
const GUI_UC_ENC_APILIST GUI__API_TableNone = {
_GetCharCode, /* return character code as U16 */
_GetCharSize, /* return size of character: 1 */
_CalcSizeOfChar, /* return size of character: 1 */
_Encode /* Encode character */
};
/*********************************************************************
*
* Exported code
*
**********************************************************************
*/
/*********************************************************************
*
* GUI_UC_SetEncodeNone
*/
void GUI_UC_SetEncodeNone(void) {
GUI_LOCK();
GUI_Context.pUC_API = &GUI__API_TableNone;
GUI_UNLOCK();
}
C、增加字体文件:FWRYH21x28.c
#include "GUI.h"
#include "GUIType.h"
#include "fsmc_nand.h"
extern int GUIPROP_X_GetCharDistX(U16P c);
extern void GUIPROP_X_DispChar(U16P c);
extern GUI_CONST_STORAGE GUI_CHARINFO GUI_Font24_ASCII_CharInfo[95];
GUI_CONST_STORAGE GUI_CHARINFO GUI_FontWRYH28_CharInfo[3] =
{
{21, 21, 3, (void *) Bank_NAND_ADDR } //GB2312±àÂë×Ö·ûÆðʼλÖã¬0XA0A0
,{17, 17, 3, (void *)(Bank_NAND_ADDR)} //GB2312ÄÚASCIIÂëÆðʼλÖÃ
,{21, 21, 3, (void *) Bank_NAND_ADDR } //GB2312ÄÚASCIIÂëÖ®ºóµÄ×Ö·û
};
GUI_CONST_STORAGE GUI_FONT_PROP GUI_FontWRYH28_Prop3 = {
0xa4A1,
0xF7FE,
&GUI_FontWRYH28_CharInfo[2],
(void *)0
};
GUI_CONST_STORAGE GUI_FONT_PROP GUI_FontWRYH28_Prop2 = {
0xa3A1,
0xA3FE,
&GUI_FontWRYH28_CharInfo[1],
(void *)&GUI_FontWRYH28_Prop3
};
GUI_CONST_STORAGE GUI_FONT_PROP GUI_FontWRYH28_Prop1 = {
0xa1a1,
0xA2FC,
&GUI_FontWRYH28_CharInfo[0],
(void *)&GUI_FontWRYH28_Prop2
};
GUI_CONST_STORAGE GUI_FONT_PROP GUI_FontWRYH28_PropASCII = {
0x0020 /* first character */
,0x007E /* last character */
,&GUI_Font24_ASCII_CharInfo[0] /* address of first character */
,(const GUI_FONT_PROP*)&GUI_FontWRYH28_Prop1 /* pointer to next GUI_FONT_PROP */
};
GUI_CONST_STORAGE GUI_FONT GUI_FontWRYH28 =
{
GUI_FONTTYPE_PROP_X,
28, //xsize
28, //ysize
1, //x·½Ïò·Å´ó±¶Êý
1, //y·½Ïò·Å´ó±¶Êý
(void GUI_CONST_STORAGE *)&GUI_FontWRYH28_PropASCII
};
D、增加字体显示程序文件:GUICharPEx.c
#include /* needed for definition of NULL */
#include "GUI_Private.h"
#include "fsmc_nand.h"
#define BYTES_PER_FONT 84
extern GUI_CONST_STORAGE GUI_CHARINFO GUI_Font24_ASCII_CharInfo[95];
static U8 GUI_FontDataBuf[BYTES_PER_FONT];
/* ×Ö¿âÍⲿº¯Êý²¿·Ö */
U8 GUI_X_GetFontData(char* font, U32 oft, U8 *ptr, U8 bytes)
{
U32 status;
status = FSMC_NAND_ReadToBuffer(ptr, (U32)font + oft, bytes);
if((status & 0x40) != NAND_READY)
{
return (1);
}
return (0);
}
static void GUI_GetDataFromMemory(const GUI_FONT_PROP GUI_UNI_PTR *pProp, U16P c)
{
I16 BytesPerFont;
U32 oft;
char *font = (char *)pProp->paCharInfo->pData;
BytesPerFont = GUI_Context.pAFont->YSize * pProp->paCharInfo->BytesPerLine;//ÿ¸ö×ÖÄ£µÄÊý¾Ý×Ö½Ú¸öÊý
if(BytesPerFont > BYTES_PER_FONT)
{
BytesPerFont = BYTES_PER_FONT;
}
if(c < 0x80)
{
// oft = (c - 0x20) * BytesPerFont;
if(0x20 == c)
{
for(oft = 0; oft < BytesPerFont; oft++)
{
GUI_FontDataBuf[oft] = 0;
}
}
}
else
{
oft = (((c>>8) - 0xa1)*94 + ((c&0xff) - 0xA1)) * BytesPerFont;//ÖÐÎÄ×Ö·ûµØÖ·Æ«ÒÆËã·¨
GUI_X_GetFontData(font, oft, GUI_FontDataBuf, BytesPerFont);
}
}
void GUIPROP_X_DispChar(U16P c)
{
int BytesPerLine;
GUI_DRAWMODE DrawMode = GUI_Context.TextMode;
const GUI_FONT_PROP GUI_UNI_PTR *pProp = GUI_Context.pAFont->p.pProp;
if((c < 0x80) && (c > 0x20)) c = (c<<8) + 0x80a3;
if(0x20 != c) c = (c>>8) + (c<<8);
//ËÑË÷¶¨Î»×Ö¿âÐÅÏ¢
for(; pProp; pProp = pProp->pNext)
{
if((c >= pProp->First) && (c <= pProp->Last)) break;
}
if(pProp)
{
GUI_DRAWMODE OldDrawMode;
const GUI_CHARINFO GUI_UNI_PTR *pCharInfo = pProp->paCharInfo;
GUI_GetDataFromMemory(pProp, c);
BytesPerLine = pCharInfo->BytesPerLine;
OldDrawMode = LCD_SetDrawMode(DrawMode);
LCD_DrawBitmap(GUI_Context.DispPosX, GUI_Context.DispPosY,
pCharInfo->XSize, GUI_Context.pAFont->YSize,
GUI_Context.pAFont->XMag, GUI_Context.pAFont->YMag,
1,
BytesPerLine,
&GUI_FontDataBuf[0],
&LCD_BKCOLORINDEX
);
/* Fill empty pixel lines*/
if(GUI_Context.pAFont->YDist > GUI_Context.pAFont->YSize)
{
int YMag = GUI_Context.pAFont->YMag;
int YDist = GUI_Context.pAFont->YDist * YMag;
int YSize = GUI_Context.pAFont->YSize * YMag;
if(DrawMode != LCD_DRAWMODE_TRANS)
{
LCD_COLOR OldColor = GUI_GetColor();
GUI_SetColor(GUI_GetBkColor());
LCD_FillRect(GUI_Context.DispPosX, GUI_Context.DispPosY + YSize,
GUI_Context.DispPosX + pCharInfo->XSize,
GUI_Context.DispPosY + YDist
);
GUI_SetColor(OldColor);
}
}
LCD_SetDrawMode(OldDrawMode);
GUI_Context.DispPosX += pCharInfo->XDist * GUI_Context.pAFont->XMag;
}
}
int GUIPROP_X_GetCharDistX(U16P c)
{
const GUI_FONT_PROP GUI_UNI_PTR *pProp = GUI_Context.pAFont->p.pProp;
if((c < 0x80) && (c > 0x20)) c = (c<<8) + 0x80a3;
if(0x20 != c) c = (c>>8) + (c<<8);
for(; pProp; pProp = pProp->pNext)
{
if((c >= pProp->First) && (c <= pProp->Last)) break;
}
return (pProp)?(pProp->paCharInfo->XSize * GUI_Context.pAFont->XMag) : 0;
}
E、修改GUIType.h
在此文件里增加:
#define GUI_FONTTYPE_PROP_X \
GUIPROP_X_DispChar,\
GUIPROP_X_GetCharDistX,\
GUIMONO_GetFontInfo, \
GUIMONO_IsInFont, \
(tGUI_ENC_APIList*)0
按以上修改方式即可以用GUI_DispString("欢迎来到汉字的世界")来显示汉字。可以用同样的方法再增加一种或多种字体。使用中注意几个问题:
1、每种字库数据在存储空间里的起始地址
2、STM32内存里的数据是 低字节在前,高字节在后,而字库制作工具生成的二进制文件有高字节在前的,也有高字节在前的,程序编写时需要按实际情况修改。