Chinaunix首页 | 论坛 | 博客
  • 博客访问: 810787
  • 博文数量: 118
  • 博客积分: 2067
  • 博客等级: 大尉
  • 技术积分: 1751
  • 用 户 组: 普通用户
  • 注册时间: 2009-07-17 14:27
文章存档

2016年(1)

2013年(1)

2012年(3)

2011年(26)

2010年(47)

2009年(40)

分类: LINUX

2011-10-12 15:03:43

摘要:

    在ARM7系统中,都不会有足够大的程序存储器来存放大容量的汉字库,因此当系统中要用到汉字库时,需要将其存储在外部的FLASH Memory,而ucgui的字符显示函数是直接从程序存储器取数据的,因此需要在原始代码里增加一个接口,来指向外部的FLASH Memory。

简介: 

   ucgui中,字符显示的底层函数是 GUICharP.c 中的 void GUIPROP_DispChar(U16P c) 函数,我们将这个函数修改如下:

/*********************************************************************
*
* GUIPROP_DispChar
*
* Purpose:
* This is the routine that displays a character. It is used by all
* other routines which display characters as a subroutine.
*/


void GUIPROP_DispChar(U16P c) {
int BytesPerLine;
U8 BytesPerFont;
//一个字的字节数
U32 base,oft; //字库的起始地址和偏移量

GUI_DRAWMODE DrawMode
= GUI_Context.TextMode;
const GUI_FONT_PROP GUI_UNI_PTR * pProp = GUIPROP_FindChar(GUI_Context.pAFont->p.pProp, c);
if (pProp) {
GUI_DRAWMODE OldDrawMode;
const GUI_CHARINFO GUI_UNI_PTR * pCharInfo;
//支持3种字体==
if((GUI_Context.pAFont == &GUI_FontHZ16)||(GUI_Context.pAFont == &GUI_FontHZ24)||(GUI_Context.pAFont == &GUI_FontHZ32))
{
     pCharInfo
= pProp->paCharInfo;

    
base = (U32)pProp->paCharInfo->pData;
     BytesPerFont
= GUI_Context.pAFont->YSize * pProp->paCharInfo->BytesPerLine; //每个字模的数据字节数
     if (BytesPerFont > BYTES_PER_FONT)
     {
         BytesPerFont
= BYTES_PER_FONT;
     }
    
if (c < 0x80) //英文字符地址偏移算法
     {
         oft
= base + (c - 0x20) * BytesPerFont; //计算出字码在flash中的偏移地址
     } else //中文字符地址偏移算法 {
         oft
= base + (((c>>8) - 0xa1) * 94 + ((c&0xff) - 0xa1)) * BytesPerFont;

     }
     LCD_ReadFlashBit(oft, GUI_FontDataBuf, BytesPerFont);
//取出字模数据

     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, /* Bits per Pixel */
     BytesPerLine,
     GUI_FontDataBuf,
    
&LCD_BKCOLORINDEX
     );
     }
//--
else
{
     pCharInfo
= pProp->paCharInfo+(c-pProp->First);
     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, /* Bits per Pixel */
     BytesPerLine,
     pCharInfo
->pData,
    
&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); /* Restore draw mode */
     GUI_Context.DispPosX += pCharInfo->XDist * GUI_Context.pAFont->XMag;
     }
}

然后再加入FLASH操作的底层驱动(这里用的是SPI FLASH)

/*********************************************************************
*
* Static code
*
**********************************************************************
*/
//字模数据的暂存数组,以单个字模的最大字节数为设定值
#define BYTES_PER_FONT 4*32 //最大支持32*32的汉字
static U8 GUI_FontDataBuf[BYTES_PER_FONT];


/*********************************************************************
*
* 读FLASH中的字库
*/
#include
"spi_flash.h"
#include
"ssp.h"

void LCD_ReadFlashBit(U32 addr,U8* buf,U8 Bytes)
{
U8 i;
SPI_FLASH_StartReadSequence(addr);
//设置起始地址
for(i=0;i<Bytes;i++)
{
buf[i]
= SPI_FLASH_SendByte(0xa5);
}
SPI_FLASH_CS_HIGH();
}

我们知道,ucgui访问字库的时候,是根据字库文件的索引表来查找汉字数据地址的,因此汉字库文件中的索引也要修改,以汉字库32为例

/*
******************************************************


File Name : hzk32.C
Compiler :
Author : Liu_xf
Version : V1.0
Date : 2011-3-28 11:25:54
Description :
ucgui的中文字库,与uc工具生成的字库文件不同的是,可以将
大容量的汉字数组存入到外部的FALSH里
当然这个也是由uc工具生成的文件修改而来的。
*******************************************************
Structure :

History:

*******************************************************
*/

#include
"..\core\GUI.H"
#ifndef GUI_FLASH
#define GUI_FLASH
#endif
extern GUI_FLASH const GUI_FONT GUI_FontHZ32;

/*
GUI_FLASH const GUI_CHARINFO GUI_FontHZ32_CharInfo[] = {
{ 10, 10, 1, (void GUI_FLASH *)0}, // 字符在FLASH中的偏移量
{ 16, 16, 2, (void GUI_FLASH *)3840}, //汉字在FLASH中的偏移量
};
*/

GUI_FLASH
const GUI_CHARINFO GUI_FontHZ32_CharInfo[] = {
// Y X X_BYTE
{ 16, 8, 1, (void GUI_FLASH *)0}, // FLASH里没有存字符,这里为0
{ 32, 32, 4, (void GUI_FLASH *)GUI_FontHZ32_Flash_BaseAddr}, //GUI_FontHZ32_Flash_BaseAddr在GUI.h中定义
};

//汉字和字符索引表//////////////////////////////////

/*鳌--齄*/

GUI_FLASH
const GUI_FONT_PROP GUI_FontHZ32_Propf7a1= {
0xf7a1,
0xf7fe,
&GUI_FontHZ32_CharInfo[1],
(
void *)0
};

//.....这里省略若干,详见符件里的代码


/* --〓*/
GUI_FLASH
const GUI_FONT_PROP GUI_FontHZ32_Propa1a1= {
0xa1a1,
0xa1fe,
&GUI_FontHZ32_CharInfo[1],
(
void *)&GUI_FontHZ32_Propa2a1
};
//ASC字符
/*
--*/
GUI_FLASH
const GUI_FONT_PROP GUI_FontHZ32_Prop0020= {
0x0020,
0x007f,
&GUI_FontHZ32_CharInfo[0],
(
void *)&GUI_FontHZ32_Propa1a1
};
GUI_FLASH
const GUI_FONT GUI_FontHZ32 = {
GUI_FONTTYPE_PROP_SJIS,
32,
32,
1,
1,
(
void GUI_FLASH *)&GUI_FontHZ32_Prop0020
};

在GUI.H中添加汉字库在flash中的首地址,及字库声明

/*汉字*/
//汉字库在FLASH中的首地址
#define GUI_FontHZ16_Flash_BaseAddr 0x0
#define GUI_FontHZ24_Flash_BaseAddr 0x00045080
#define GUI_FontHZ32_Flash_BaseAddr 0x000E05A0

extern GUI_CONST_STORAGE GUI_FONT GUI_FontHZ16;
extern GUI_CONST_STORAGE GUI_FONT GUI_FontHZ24;
extern GUI_CONST_STORAGE GUI_FONT GUI_FontHZ32;

    然后将字库下载到SPI FLASH中,注意三个字库的起始地址与GUI.h中定义的应该是一样的。还有字库生成时,也应该是标准的汉字库,满足 oft = base + (((c>>8) - 0xa1) * 94 + ((c&0xff) - 0xa1)) * BytesPerFont; 的计算方式。

 

结语: 

   有了将汉字库定义到外部FLASH的方法,则可以定义任意汉字库,不受程序FLASH大小的限制了。

附件:

ucgui_hzk.rar

-----------------------------------------------------------------------

手头的一个项目需要用到uCGUI看了hzk12.c,hzk16.c由于全部编译进stm32的flash,根本够用,于是查了一下资料,并参考了一些代码,实现了自定义字库的方法。该方法可以扩展任意字体。
需要修改的地方有三个:
1、GUItype.h

在该文件加入以下内容
DECLARE_FONT(PROP_X);
#define GUI_FONTTYPE_PROP_USER       \
  GUIPROP_X_DispChar,             \
GUIPROP_X_GetCharDistX,         \
GUIMONO_GetFontInfo,          \
GUIMONO_IsInFont,             \
  (tGUI_ENC_APIList*)0


2、GUI_UC_EncodeNone.c

该文件修改为以下内容
/*
*********************************************************************************************************
*                                                uC/GUI
*                        Universal graphic software for embedded applications
*
*                       (c) Copyright 2002, Micrium Inc., Weston, FL
*                       (c) Copyright 2002, SEGGER Microcontroller Systeme GmbH
*
*              礐/GUI is protected by international copyright laws. Knowledge of the
*              source code may not be used to write a similar product. This file may
*              only be used in accordance with a license and should not be redistributed
*              in any way. We appreciate your understanding and fairness.
*
----------------------------------------------------------------------
File        : GUI_UC_EncodeNone.c
Purpose     : Encoding routines for non unicode systems (default)
---------------------------END-OF-HEADER------------------------------
*/

#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) {
  if((*s) > 0xA0)
  {
    return *(const U16 GUI_UNI_PTR *)s; 
  }
  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); 
  if((*s) > 0xA0)
  {
    return 2; 
  }
  return 1;
}

/*********************************************************************
*
*       _CalcSizeOfChar
*
* Purpose:
*   Return the number of bytes needed for the given character.
*/
static int _CalcSizeOfChar(U16 Char) {
  GUI_USE_PARA(Char);
  if(Char > 0xA0A0)
  {
    return 2;
  }
  return 1;
}

/*********************************************************************
*
*       _Encode
*
* Purpose:
*   Encode character into 1/2/3 bytes.
*/
static int _Encode(char *s, U16 Char) {
  if(Char > 0xA0A0)
  {
    *((U16 *)s) = (U16)(Char);
    return 2;
  }
  *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();
}

/*************************** End of file ****************************/


3、新建文件“GUICharPEx.c”,并加入工程

内容如下

#include            /* needed for definition of NULL */
#include "GUI_Private.h"
#include "ff.h" 
/*********************************************************************
*
*       Static code
*
**********************************************************************
*/
//字模数据的暂存数组,以单个字模的最大字节数为设定值
#define BYTES_PER_FONT      128
static U8 GUI_FontDataBuf[BYTES_PER_FONT];
extern void GUI_X_GetFontData(char *font, U32 oft, U8 *ptr, U8 bytes);
//从外部存储器取得字模数据 
static void GUI_GetDataFromMemory(const GUI_FONT_PROP GUI_UNI_PTR *pProp, U16P c)
{
    U8 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 * BytesPerFont;
    }
    else                                                                          
    {
 oft = ((((c >> 8)-0xA1)) + ((c & 0xFF)-0xA1) * 94)* BytesPerFont; //中文字符地址偏移算法包括符号
    }
    GUI_X_GetFontData(font, oft, GUI_FontDataBuf, BytesPerFont);
}
/*********************************************************************
*
*       Public code
*
**********************************************************************
*/
/*********************************************************************
*
*       GUIPROP_DispChar
*
* Purpose:
*   This is the routine that displays a character. It is used by all
*   other routines which display characters as a subroutine.
*/
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;
    //搜索定位字库数据信息 
    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,     /* Bits per Pixel */
                       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); /* Restore draw mode */
        GUI_Context.DispPosX += pCharInfo->XDist * GUI_Context.pAFont->XMag;
    }
}
/*********************************************************************
*
*       GUIPROP_GetCharDistX
*/
int GUIPROP_X_GetCharDistX(U16P c) 
{
    const GUI_FONT_PROP GUI_UNI_PTR * pProp = GUI_Context.pAFont->p.pProp;  
    for (; pProp; pProp = pProp->pNext)                                         
    {
        if ((c >= pProp->First) && (c <= pProp->Last))break;
    }
    return (pProp) ? (pProp->paCharInfo)->XSize * GUI_Context.pAFont->XMag : 0;
}
GUI_CONST_STORAGE GUI_CHARINFO GUI_FontHZ16_CharInfo[2] = 
{    
    {  8,    8,  1, (void *)"sys/font/en12.dzk"   },      //&ASC_ROM_8X16
    {  16,  16,  2, (void *)"sys/font/st12.dzk"},         //&HZ_ROM_16X16      
};
GUI_CONST_STORAGE GUI_FONT_PROP GUI_FontHZ16_PropHZ= {
      0xA1A1, 
      0xF7FE, 
      &GUI_FontHZ16_CharInfo[1],
      (void *)0, 
};
GUI_CONST_STORAGE  GUI_FONT_PROP GUI_FontHZ16_PropASC= {
      0x0000, 
      0x007F, 
      &GUI_FontHZ16_CharInfo[0],
      (void GUI_CONST_STORAGE *)&GUI_FontHZ16_PropHZ, 
};
GUI_CONST_STORAGE  GUI_FONT GUI_FontHZ16 = 
{
      GUI_FONTTYPE_PROP_USER, 
      16, 
      16, 
      1,  
      1,  
      (void GUI_CONST_STORAGE *)&GUI_FontHZ16_PropASC
};
GUI_CONST_STORAGE  GUI_FONT GUI_FontHZ16x2 = 
{
      GUI_FONTTYPE_PROP_USER, 
      16, 
      16, 
      2,  
      2,  
      (void GUI_CONST_STORAGE *)&GUI_FontHZ16_PropASC
};
 
/*---------------------------------------------------------------------------*/
/*字库外部函数部分-----------------------------------------------------------*/
void GUI_X_GetFontData(char* font, U32 oft, U8 *ptr, U8 bytes)
{
    FIL fsrc;        // 定义文件操作类 
    FRESULT res;  // 定义操作结果变量 
    UINT br;         // 定义读写数量变量
 
    res = f_open(&fsrc, font, FA_OPEN_EXISTING | FA_READ);   //打开字库文件  
    if(res != FR_OK)  
    {  
               //打开失败显示问号           
    }
     
    res = f_lseek(&fsrc,oft); //找到首地址 
    res = f_read(&fsrc, ptr, bytes, &br); //读取32个字库点阵数据
res = f_close(&fsrc); //关闭字体  
}

这样以后就可以设置新建的字体“GUI_FontHZ16”来显示汉字或英文或混合显示了

注意事项SD卡用的文件系统——fatFS,所以“FF.h”是文件系统的头文件,可以扩展自己的方法来获取字模。
适当的修改或添加内容就可以实现不同字体,不同的大小的字体了。
上传用到的字库,来自UCDOS,金山的DOS系统里面的。要注意的是,这两个字体是完整的,也就是说,“en12.dzk”偏移是重0开始
“st12.dzk”偏移是从"0xA1A1"开始,包含符号区和未使用区。
注意计算偏移地址时要正确,可以参考上面代码的这里:

if (c < 0x80)                                                               //英文字符地址偏移算法
    {
     oft = c * BytesPerFont;
    }
    else                                                                          
    {
 oft = ((((c >> 8)-0xA1)) + ((c & 0xFF)-0xA1) * 94)* BytesPerFont; //中文字符地址偏移算法包括符号
    }

其中“BytesPerFont”是uCGUI计算出来的每个字所需要的字节数,这里英文是16,中文是32。

所使用的字库文件:
点击此处下载 ourdev_622779PG8Y3X.rar(文件大小:139K) (原文件名:zk12.rar) 



阅读(13876) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~