你的位置:首页 > 操作系统

[操作系统]基于stm32f4的ucGUI通过外部flash存储汉字库显示任意英文字符和汉字组合(控件可用)


  在做一个用到ucGUI的项目的时候要用到不定的汉字和英文字符,但是ucGUI本身又不支持读取芯片外部flash的字库来显示,于是查了下资料,如下:

  http://www.cnblogs.com/hiker-blogs/archive/2013/01/04/2843538.html

  站在巨人的肩膀上,我找到了将汉字库写进flash后,通过ucGUI的控件显示出来的方法,但是至此,并不能在一个字符串里添加汉字和英文,用于同时显示,因为flash里面没有英文字符的模。

  为了让一个控件同时显示汉字和英文,我们还是将目标瞄准ucGUI_Core文件夹中的GUICharP.c文件:

将函数void GUIPROP_DispChar(U16P c)修改成:

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;
        //支持2种字体,flash空间有限,放不下第三种字体
    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)//BYTES_PER_FONT是一个汉字所占最大字节数,我这里最大显示点阵24x24的汉字,所以BYTES_PER_FONT大小是3x24
        {
            BytesPerFont = BYTES_PER_FONT;
        }
        if (c < 0x80) //英文字符显示部分
        {
            const GUI_FONT *EnglishFont;//定义一个字库指针,方便以后操作
            if(GUI_Context.pAFont == &GUI_FontHZ16)//根据所用字库来给EnglishFont赋值,因为flash里面没有英文字符模,于是用ucGUI自带的
                EnglishFont=&GUI_Font16_ASCII;
            else
                EnglishFont=&GUI_Font24_ASCII;
            //BytesPerLine = GUI_Font24_ASCII.p.pProp->paCharInfo[c-0x20].BytesPerLine*GUI_Font24_ASCII.YSize;
            //在这里,BytesPerLine就是所要显示的字符的模位数,就是GUI_CHARINFO结构体的BytesPerLine
            BytesPerLine = EnglishFont->p.pProp->paCharInfo[c-0x20].BytesPerLine;
            OldDrawMode  = LCD_SetDrawMode(DrawMode);//写入新的模式,并保存旧的模式    
            //注:pCharInfo->  =  EnglishFont.p.pProp->paCharInfo[c-0x20].
            //    GUI_Context.pAFont->  =    当前字体,比如   EnglishFont.
            LCD_DrawBitmap( GUI_Context.DispPosX,
                            GUI_Context.DispPosY,
                            EnglishFont->p.pProp->paCharInfo[c-0x20].XSize,//GUI_CHARINFO的XSize,EnglishFont->p.pProp->paCharInfo[c-0x20]即相当于字库文件F16_ASCII.c中的GUI_CharInfo_Font16ASCII[c-0x20]
                            EnglishFont->YSize,//字库的参数
                            EnglishFont->XMag,
                            EnglishFont->YMag,
                            1,     /* Bits per Pixel */
                            BytesPerLine,
                            EnglishFont->p.pProp->paCharInfo[c-0x20].pData,
                            &LCD_BKCOLORINDEX
                          );
            /* Fill empty pixel lines */
            if (EnglishFont->YDist > EnglishFont->YSize) {  //用于字符对齐,删掉这里的if到return就可以指到效果了
              int YMag = EnglishFont->YMag;
              int YDist = EnglishFont->YDist * YMag;
              int YSize = EnglishFont->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 += EnglishFont->p.pProp->paCharInfo[c-0x20].XDist * EnglishFont->XMag;
            return;
        }
        else //中文字符地址偏移算法
        {
            oft = base + (((c>>8) - 0xa1) * 94 + ((c&0xff) - 0xa1)) * BytesPerFont;
            ucGUI_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;
  }
}

void GUIPROP_DispChar(U16P c)函数只是用来显示数据的,为了让数据显示在控件中间,还要修改int GUIPROP_GetCharDistX(U16P c)为:

int GUIPROP_GetCharDistX(U16P c) {
 if(c<0x80)//是英文
 {
    const GUI_FONT_PROP GUI_UNI_PTR * pProp;
    if(GUI_Context.pAFont == &GUI_FontHZ16)//在GUI_FontHZ16中找到字符间距,用于控件字符水平对齐,防止英文字符宽度被认为跟汉字一样
    {
        pProp = GUIPROP_FindChar(GUI_Font16_ASCII.p.pProp, c);//在GUI_Font16_ASCII字库里面找字符c
        return (pProp) ? (pProp->paCharInfo+(c-pProp->First))->XSize * GUI_Font16_ASCII.XMag : 0;//返回字符c的横坐标大小
    }
    else
    {
        pProp = GUIPROP_FindChar(GUI_Font24_ASCII.p.pProp, c);
        return (pProp) ? (pProp->paCharInfo+(c-pProp->First))->XSize * GUI_Font24_ASCII.XMag : 0;
    }
   
  }
  else
  {
    const GUI_FONT_PROP GUI_UNI_PTR * pProp = GUIPROP_FindChar(GUI_Context.pAFont->p.pProp, c);
    return (pProp) ? (pProp->paCharInfo+(c-pProp->First))->XSize * GUI_Context.pAFont->XMag : 0;
  }
 
}

当这两个函数修改完毕,并且做好上面大牛的链接内容后,字体数据就放在外部flash中,显示器可以在控件上同时显示汉字和英文了。

http://pan.baidu.com/s/1pLFA739

这是我的工程源码,里面有将字体文件复制进SD卡的函数。我用的开发板是stm32f407,环境是keil5,在stm32f407板子上集成2M的flash,板子上面的SDIO接口连接了一个1G的SD卡,sd卡有font目录,里面放16HZK.bin和24HZK_B.bin文件,液晶驱动是ili9341.在这里感谢正点原子,很多驱动程序是他们提供的。