【第3版emWin教程】第32章 emWin6.x的矢量字體(支持漢字全字庫,Unicode編碼,QSPI Flash方案)


教程不斷更新中:http://www.armbbs.cn/forum.php?mod=viewthread&tid=98429

第32章       emWin6.x的矢量字體(支持漢字全字庫,Unicode編碼,QSPI Flash方案)

本期教程跟大家講解矢量字體的相關知識,矢量字體最大的好處就是可以任意放大或者縮小字體,而且字體的顯示效果不失真。矢量字體也有缺點,即非常消耗內存。但是本教程配套開發板的STM32H7是支持外接SDRAM和支持內存映射方式的QSPI Flash,這樣就有大容量的空間供矢量字體使用了。

32.1 初學者重要提示

32.2 下載算法存放位置(操作前必看)

32.3 矢量字體介紹

32.4 emWin對矢量字體的支持

32.5 矢量字體庫的移植方法

32.6 矢量字體庫的使用方法

32.7 內部Flash和QSPI Flash程序調試下載配置(重要必看)

32.8 實驗例程說明(RTOS)

32.9 實驗例程說明(裸機)

32.10 總結

 

 

32.1 初學者重要提示

1、  使用STM32H7+大容量的SDRAM或者內存映射方式QSPI Flash來實現矢量字體具有一定的實戰意義,可用於實際項目。

2、  實驗中發現了以下三個問題,給大家分享下:

  • 不是所有電腦端的矢量字體都可以顯示,測試發現有些無法正常顯示,估計是emWin庫不支持。
  • 不能顯示太大的字體,測試發現130點陣之后就無法顯示了。
  • 顯示比較大的字體,STM32H7的圖形性能完全跟的上。

3、  矢量字體也是用的Unicode編碼,這點要特別注意。

4、  矢量字體所有API函數在emWin手冊中都有講解,下圖是中文版手冊里面API函數的位置

 

下圖是英文版手冊里面API函數的位置:

 

32.2 下載算法存放位置(操作前必看)

(注:例子下載地址 http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980

編譯例子:V7-060_QSPI Flash的MDK下載算法制作,生成的算法文件位於此路徑下:

 

生成算法文件后,需要大家將其存到到MDK安裝目錄,有兩個位置可以存放,任選其一,推薦第2種:

  •   第1種:存放到MDK的STM32H7軟包安裝目錄里面:\Keil\STM32H7xx_DFP\2.6.0\CMSIS\Flash(軟包版本不同,數值2.6.0不同)。
  •   第2種:MDK的安裝目錄 \ARM\Flash里面。

 

32.3 矢量字體介紹

下面的內容來中文版wiki百科,講的非常好,特此轉載過來:https://zh.wikipedia.org/wiki/%E7%9F%A2%E9%87%8F%E5%AD%97%E4%BD%93

目前主流的矢量字體格式有3種:Type1,TrueType和OpenType,這三種格式都是與平台無關的。

Type1全稱PostScript Type1,是1985年由Adobe公司提出的一套矢量字體標准,由於這個標准是基於PostScript Description Language(PDL),而PDL又是高端打印機首選的打印描述語言,所以Type1迅速流行起來。但是Type1是非開放字體,Adobe對使用Type1的公司征收高額的使用費。

TrueType是1991年由Apple公司與Microsoft公司聯合提出另一套矢量字標准。

Type1使用三次貝塞爾曲線來描述字形,TrueType則使用二次貝塞爾曲線來描述字形。所以Type1的字體比TrueType字體更加精確美觀。一個誤解是,Type1字體比TrueType字體占用空間多。這是因為同樣描述一個圓形,二次貝塞爾曲線只需要8個關鍵點和7段二次曲線;而三次貝塞爾曲線則需要12個關鍵點和11段三次曲線。然而實際情況是一般來說 Type1比TrueType要小10%左右。這是因為對於稍微復雜的字形,為了保持平滑,TrueType必須使用更多的關鍵點。由於現代大部分打印機都是使用PDL作為打印描述語言,所以Type1字體打印的時候不會產生形變,速度快;而TrueType則需要翻譯成PDL,由於曲線方程的變化,還會產生一定的形變,不如Type1美觀。

這么說來,Type1應該比TrueType更具有優勢,為什么如今的計算機上TrueType反而比Type1使用更廣泛呢?這是因為第一:Type1由於字體方程的復雜,所以在屏幕上渲染的時候,花費的時間多,解決方案是大部分Type1字體嵌入了點陣字體,這樣渲染快,但是邊緣不光滑,比較難看。很多ps文檔和ps轉換的pdf文檔都是這樣,在計算機上瀏覽的時候字體很難看,但是打印出來很美觀。TrueType則渲染比較快,可以平滑的顯示在屏幕上,看上去很美觀。

第二個原因是Type1的高額使用費,使得Type1沒有被所有的操作系統所支持。Windows家族只有OS/2和windows 2000及之后的版本從操作系統級別開始支持Type1。由於這個問題,Adobe只好在其所有的產品中嵌入Adobe Type Manager(ATM)作為渲染引擎。

OpenType則是Type1與TrueType之爭的最終產物。1995年,Adobe公司和Microsoft公司開始聯手開發一種兼容Type1和TrueType,並且真正支持Unicode的字體,后來在發布的時候,正式命名為OpenType。OpenType可以嵌入Type1和TrueType,這樣就兼有了二者的特點,無論是在屏幕上察看還是打印,質量都非常優秀。可以說OpenType是一個三贏的結局,無論是Adobe、Microsoft還是最終用戶,都從OpenType中得到了好處。Windows家族從Windows 2000開始,正式支持OpenType。打開系統的字體目錄(一般是C:\Windows\Fonts\或C:\Winnt\Fonts),可以看到:一個紅色A的圖標的是點陣字體,兩個重疊的T的圖標是TrueType字體,一個O的圖標就是OpenType字體。

下面是XP系統中字體的部分截圖,其中矢量字體擴展名ttf,點陣字體的擴展名是fon。

 

Win7系統中已經變成如下這種樣子:

 

32.4 emWin對矢量字體的支持

emWin對矢量字體庫的支持是基於David Turner、Robert Wilhelm和Werner Lembergr的FreeType字體庫,該庫可在www.freetype.org下免費獲得。emWin對該庫的使用符GUI\TrueType\FTL. txt下的FreeType授權許可。emWin對該庫進行了少許改編,添加了帶有GUI函數的應用層。emWin軟件包中也是沒有矢量字體庫的,需要大家在SEGEER官網地址https://www.segger.com/downloads/emwin/emWin_FreeType 下載。

矢量字體基於矢量圖形,矢量的優勢在於可以無損的放縮。而點陣字體雖然也可以放縮,但不是矢量的,放縮后鋸齒很明顯。並且項目中需要多種字體大小支持的話,需要幾種字體支持,就需要生成幾種點陣字庫,非常占空間,而矢量字體僅需要一個字體庫就可以了。特別是顯示大字體,矢量字體庫的優勢更明顯。

通過矢量字體帶來無損放縮的同時,也是有缺點的。使用矢量字體的話,每個字符在繪制前需要光柵化為位圖,為避免每次繪制字符時都進行光柵化,通常用字體引擎緩存點陣數據。這要求CPU速度快、RAM足夠。當前emWin對矢量字體的支持是以總線方式尋址的,與第30章講解的SIF格式字體是類似的。

TrueType矢量字體的硬件要求如下:

32.5 矢量字體庫的移植方法

跟第23章講解的PNG庫一樣,emWin的庫中也是不含有矢量庫的,需要用戶自行添加,添加也比較簡單,只需用戶把源碼文件添加到工程里面就可以使用了。

矢量庫的下載地址:https://www.segger.com/downloads/emwin/emWin_FreeType 。下載軟件包后進行解壓,當前這個版本的庫已經被存到本章節配套例子的Doc文件夾:

 

32.5.1   MDK版本移植說明

  • 第1步:在 emWin工程-->emWin文件夾-->新建一個TrueType文件夾,將矢量字體庫里面的源碼文件全部復制到此文件夾里面(其它任意文件夾都是可以的,不限制)。

 

  • 第2步:將矢量庫的所有.C格式的源碼文件添加到MDK工程里面,下面是部分源碼文件的截圖。

 

  • 第3步:添加矢量庫的頭文件路徑,添加完畢后別忘了點擊OK。

 

  • 第4步:修改系統堆(heap)大小,這一步非常關鍵。因為矢量庫要用到函數malloc和free,而這種函數是從系統堆空間里面申請內存的,鑒於矢量庫非常的消耗動態內存,這里將32MB SDRAM的最后1MB空間給系統堆使用,設置如下:

 

Heap_Size:表示堆大小設置為1MB。

_heap_base:表示堆起始地址為0xC1F00000,即32MB SDRAM最后1MB空間的起始地址。

_heap_linmit:表示堆結束地址0xC1FFFFFF,即32MB SDRAM最后1MB空間的結束地址。

除了malloc和free要用到堆空間,部分C標准庫的其它函數也要用到堆空間,所以一定要及時初始化SDRAM,防止用到堆空間的時候,SDRAM還沒有初始化,將導致系統崩潰。當前是將SDRAM的初始化放在了bsp.c文件的bsp_Init函數開始的地方,之前執行的程序都沒有用到C標准庫,所以可以放在這里。

  • 第5步:最后一步,添加好庫文件並且修改完畢后,驗證是否已經添加成功,可以進行一次全編譯,全編譯后MDK會有幾個警告和兩個錯誤。

 

解決辦法是將下面兩個函數形參的void刪掉即可

 

至此,矢量字體庫就添加成功了。剩下就可以調用矢量庫的API函數了。

32.6 矢量字體庫的使用方法

矢量字體的使用通過下面四步就可以實現:

第1步:定義16點陣大小,24點陣大小,32點陣大小,48點陣大小,72點陣大小和120點陣大小的格式字體。

/*
*********************************************************************************************************
*                                      定義矢量字體
*********************************************************************************************************
*/
GUI_TTF_CS Cs0, Cs1, Cs2, Cs3, Cs4, Cs5;
GUI_TTF_DATA Data;
GUI_FONT Font16, Font24, Font32, Font48, Font72, Font120;

這里對定義矢量字體用到的兩個結構體變量做如下介紹。

GUI_TTF_CS結構體變量:

GUI_TTF_DATA結構體變量:


第2步:創建16點陣大小,24點陣大小,32點陣大小,48點陣大小,72點陣大小和120點陣大小的格式字體。

創建前要先將矢量字體庫存到SD卡中,然后將其加載到SDRAM里面,這個矢量字體是來自電腦系統自帶,電腦系統是WIN7 64bit,路徑:C:\Windows\Fonts(已經將這個字體存到本章節配套例子的Doc文件夾下)。


 

大小是10MB,其它類型的矢量字體也是可以的,只要不超過QSPI Flash的32MB容量即可:

/*
*********************************************************************************************************
*    函 數 名: LoadFontTTF
*    功能說明: 初始化
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
void LoadFontTTF() 
{
#if 1
    char *_acBuffer;
    GUI_HMEM hMem;
    
    /* 申請一塊內存空間 並且將其清零 */
    hMem = GUI_ALLOC_AllocZero(sizeof(_acsong));
    
    /* 將申請到內存的句柄轉換成指針類型 */
    _acBuffer = GUI_ALLOC_h2p(hMem);

    memcpy(_acBuffer, _acsong, sizeof(_acsong));
    
    /* 設置參數 */
    Data.pData = _acBuffer; 
    Data.NumBytes = sizeof(_acsong); 
#else
    /* 設置參數 */
    Data.pData = _acsong; 
    Data.NumBytes = sizeof(_acsong); 
#endif

    /* 設置第1種字體顯示方式 */
    Cs0.pTTF = &Data;       /* 矢量字體數據地址 */
    Cs0.PixelHeight = 16;   /* 字體高度 */
    Cs0.FaceIndex = 0;
    
    /* 設置第2種字體顯示方式 */
    Cs1.pTTF = &Data;       /* 矢量字體數據地址 */
    Cs1.PixelHeight = 24;   /* 字體高度 */
    Cs1.FaceIndex = 0;
    
    
    /* 設置第3種字體顯示方式 */
    Cs2.pTTF = &Data;       /* 矢量字體數據地址 */
    Cs2.PixelHeight = 32;   /* 字體高度 */
    Cs2.FaceIndex = 0;
    
    /* 設置第4種字體顯示方式 */
    Cs3.pTTF = &Data;      /* 矢量字體數據地址 */
    Cs3.PixelHeight = 48;  /* 字體高度 */
    Cs3.FaceIndex = 0;
    
    
    /* 設置第5種字體顯示方式 */
    Cs4.pTTF = &Data;      /* 矢量字體數據地址 */
    Cs4.PixelHeight = 72;  /* 字體高度 */
    Cs4.FaceIndex = 0; 
    
    /* 設置第6種字體顯示方式 */
    Cs5.pTTF = &Data;        /* 矢量字體數據地址 */
    Cs5.PixelHeight = 120; /* 字體高度 */
    Cs5.FaceIndex = 0;
    

    /* 創建6種字體 */
    GUI_TTF_CreateFontAA(&Font16, &Cs0);
    GUI_TTF_CreateFontAA(&Font24, &Cs1);
    GUI_TTF_CreateFontAA(&Font32, &Cs2);
    GUI_TTF_CreateFontAA(&Font48, &Cs3);
    GUI_TTF_CreateFontAA(&Font72, &Cs4);
    GUI_TTF_CreateFontAA(&Font120, &Cs5);
    
    f_close(&file);
}

第3步:加載到SDRAM后,使用就比較簡單了。

用戶只需調用函數GUI_UC_SetEncodeUTF8()使能UTF-8編碼就可以使用矢量字體了,比如設置按鈕的字體,調用如下設置函數即可。

BUTTON_SetFont(hWin,  &Font32);  /* hWin是按鈕的句柄 */

第4步:最后一步切不可忘記設置漢字顯示所在源文件的編碼類型,具體MDK和IAR的設置方法請看第28章22.4小節(本章節配套的例子也是設置的MainTask,c文件),這一步絕對不可以省略,因為我們使用的矢量字體庫也是Unicode編碼。

通過這4步就實現矢量字體的顯示了。另外注意,如果系統運行中不需要矢量字體了,可以通過函數GUI_TTF_DestroyCache 釋放矢量字體所消耗的內存資源,通過函數GUI_ALLOC_AllocZero申請的空間,可以使用函數GUI_ALLOC_Free來釋放。

32.7 內部Flash和QSPI Flash程序調試下載配置(重要必看)

將下面兩個地方配置后,就可以像使用內部Flash一樣使用QSPI Flash進行調試了。並且這種方式可以方便的調試程序,內部Flash和外部Flash都做調試。

32.7.1        將字庫文件轉換為C數組格式文件

為了方便將bin文件添加到MDK工程中,我們這里使用小軟件B2C.exe將其轉換為C格式文件(此軟件已經放到本章配套例子V7-540_emWin6.x實驗_矢量全字庫,支持中文,Unicode編碼(QSPI Flash RTOS)的Doc文件里面。

 

轉換后生成的文件命名為song.c :

const unsigned char _acsong[10576012UL + 1] = {
  0x00, 0x01, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x04, 0x00, 0x20, 0x44, 0x53, 0x49, 0x47, 0x28, 0x0C, 0xE3, 0x96, 0x00, 0xA1, 0x45, 0x40, 0x00, 0x00, 0x1B, 0x4C, 0x47, 0x53, 0x55, 0x42, 0xBB, 0xCF, 0xB8, 0xF7, 0x00, 0xA0, 0x64, 0xF4,
  0x00, 0x00, 0x00, 0xFC, 0x4F, 0x53, 0x2F, 0x32, 0xD3, 0x94, 0x1D, 0x16, 0x00, 0x00, 0x01, 0xA8, 0x00, 0x00, 0x00, 0x60, 0x63, 0x6D, 0x61, 0x70, 0x3D, 0xE8, 0x75, 0xB8, 0x00, 0x00, 0xE7, 0xDC, 0x00, 0x00, 0x05, 0x5C, 0x63, 0x76, 0x74, 0x20,
  0x07, 0x29, 0x03, 0xF0, 
  省略未寫

}

32.7.2        設置字庫文件到外部QSPI Flash。

下面將流位圖文件下載到QSPI Flash,需要大家先在這里添加QSPI Flash地址范圍:

 

然后設置資源文件到外部QSPI Flash:鼠標右擊文件分組GUI/Font,選擇Options。

 

32.7.3 下載配置

注意這里一定要夠大,否則會提示算法文件無法加載:

 

我們這里是將其加到DTCM中,即首地址為0x20000000,大家也可以存儲到任意其它RAM地址,只要空間還夠加載算法文件即可。推薦使用AXI SRAM(地址0x24000000),因為這塊RAM空間足夠大。

如果要下載程序到內部Flash和外部QSPI Flash里面,需要做如下配置,兩個下載算法都要添加進來:

 

32.7.4 調試配置

注意這里一定要夠大,否則會提示算法文件無法加載:

 

我們這里是將其加到DTCM中,即首地址為0x20000000,大家也可以存儲到任意其它RAM地址,只要空間還夠加載算法文件即可。

如果要做調試下載,需要做如下配置:

 

32.8 實驗例程說明(RTOS)

配套例子:

V7-540_emWin6.x實驗_矢量全字庫,支持中文,Unicode編碼(QSPI Flash RTOS)

實驗目的:

  1. 學習emWin矢量字體庫的使用方法,Unicode編碼
  2. emWin功能的實現在MainTask.c文件里面。

實驗內容:

1、K1按鍵按下,串口或者RTT打印任務執行情況(串口波特率115200,數據位8,奇偶校驗位無,停止位1)。

2、(1) 凡是用到printf函數的全部通過函數App_Printf實現。

    (2) App_Printf函數做了信號量的互斥操作,解決資源共享問題。

3、默認上電是通過串口打印信息,如果使用RTT打印信息:

MDK AC5,MDK AC6或IAR通過使能bsp.h文件中的宏定義為1即可

#define Enable_RTTViewer  1

4、各個任務實現的功能如下:

App Task Start   任務 :啟動任務,這里用作BSP驅動包處理。

App Task MspPro任務 :消息處理,這里用作LED閃爍。

App Task UserIF  任務 :按鍵消息處理。

App Task COM   任務 :暫未使用。

App Task GUI    任務 :GUI任務。

μCOS-III任務調試信息(按K1按鍵,串口打印):

 

RTT 打印信息方式:

 

程序設計:

  任務棧大小分配:

μCOS-III任務棧大小在app_cfg.h文件中配置:

#define  APP_CFG_TASK_START_STK_SIZE                      512u

#define  APP_CFG_TASK_MsgPro_STK_SIZE                     2048u

#define  APP_CFG_TASK_COM_STK_SIZE                        512u

#define  APP_CFG_TASK_USER_IF_STK_SIZE                    512u

#define  APP_CFG_TASK_GUI_STK_SIZE                        2048u

任務棧大小的單位是4字節,那么每個任務的棧大小如下:

App Task Start   任務 :2048字節。

App Task MspPro任務 :8192字節。

App Task UserIF  任務 :2048字節。

App Task COM   任務 :2048字節。

App Task GUI    任務 :8192字節。

  系統棧大小分配:

μCOS-III的系統棧大小在os_cfg_app.h文件中配置:

#define  OS_CFG_ISR_STK_SIZE                      512u     

系統棧大小的單位是4字節,那么這里就是配置系統棧大小為2KB

emWin動態內存配置:

GUIConf.c文件中的配置如下:

#define EX_SRAM   1/*1 used extern sram, 0 used internal sram */

#if EX_SRAM
#define GUI_NUMBYTES  (1024*1024*24)
#else
#define GUI_NUMBYTES  (100*1024)
#endif

通過宏定義來配置使用內部SRAM還是外部的SDRAM做為emWin的動態內存,當配置:

#define  EX_SRAM     1 表示使用外部SDRAM作為emWin動態內存,大小24MB。

#define  EX_SRAM     0 表示使用內部SRAM作為emWin動態內存,大小100KB。

默認情況下,本教程配套的所有emWin例子都是用外部SDRAM作為emWin動態內存。

emWin界面顯示效果:

800*480分辨率界面效果。

 

32.9 實驗例程說明(裸機)

配套例子:

V7-539_emWin6.x實驗_矢量全字庫,支持中文,Unicode編碼(QSPI Flash裸機)

實驗目的:

  1. 學習emWin矢量字體庫的使用方法,Unicode編碼
  2. emWin功能的實現在MainTask.c文件里面。

emWin界面顯示效果:

800*480分辨率界面效果。

 

emWin動態內存配置:

GUIConf.c文件中的配置如下:

#define EX_SRAM   1/*1 used extern sram, 0 used internal sram */

#if EX_SRAM
#define GUI_NUMBYTES  (1024*1024*24)
#else
#define GUI_NUMBYTES  (100*1024)
#endif

通過宏定義來配置使用內部SRAM還是外部的SDRAM做為emWin的動態內存,當配置:

#define  EX_SRAM     1 表示使用外部SDRAM作為emWin動態內存,大小24MB。

#define  EX_SRAM     0 表示使用內部SRAM作為emWin動態內存,大小100KB。

默認情況下,本教程配套的所有emWin例子都是用外部SDRAM作為emWin動態內存。

32.10  總結

本章節為大家講解的矢量字體是可以用於項目實戰的,實際項目中建議使用大容量的SDRAM或者內存映射方式的QSPI Flash,這樣即使加載矢量字庫后,還有大量空間供emWin動態內存使用。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM