STM32 + UCGUI+外扩NAND FLASH 中文字库支持方法

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 <stddef.h>           /* 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内存里的数据是 低字节在前,高字节在后,而字库制作工具生成的二进制文件有高字节在前的,也有高字节在前的,程序编写时需要按实际情况修改。 
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页