關於UCGUI的配製文件的說明(轉)

轉http://www.cnblogs.com/xilentz/archive/2010/06/01/1749493.htm 

UCGUI與大家熟悉的UCOS一樣, 也提供了大量的可配製功能選項, 採用的方式也是在頭文件中進行預定義, 這與UCOS是一樣的. 預定義將決定可以使用的UCGUI圖形功能, 下面我們將討論一下UCGUI的配製情況, 並探討一下其最小資源佔用是多少, 即最小內存佔用量.
從UCGUI源碼當中, 可以看到有這樣一個文件夾---Config, 這個文件夾下面包含了以下胡三個頭文件:
1. GUICONF.h--------------基本的GUI預定義控制.
2. GUITouchConf.h--------關於觸屏的控制預定義.
3. LCDConf.h---------------有關LCD夜晶顯示的參數控制.
一. 關於GUICONF.h
這個文件當中, 包含了最基本的一些GUI圖形預定義控制.  其內容如下:
#ifndef GUICONF_H
#define GUICONF_H
#define GUI_OS                               (1)   /* Compile with multitasking support */
#define GUI_SUPPORT_TOUCH      (1)  /* Support a touch screen(req. win-manager) */
#define GUI_SUPPORT_UNICODE  (1)  /* Support mixed ASCII/UNICODE strings */
#define GUI_DEFAULT_FONT         &GUI_Font6x8
/* Size of dynamic memory ... For WM and memory devices*/
#define GUI_ALLOC_SIZE                12500
/*********************************************************************
*
*         Configuration of available packages
*/
#define GUI_WINSUPPORT            1  /* Window manager package available */
#define GUI_SUPPORT_MEMDEV  1  /* Memory devices available */
#define GUI_SUPPORT_AA            1  /* Anti aliasing available */
#endif  /* Avoid multiple inclusion */
可以看到, 這裏面的配製並不是很多, 只有大約十項左右.
1.GUI_OS-------------是否須要多任務支持.
在GUI_Protected.h文件當中有如下的代碼:
.....
#if !GUI_OS
  #define GUI_LOCK()
  #define GUI_UNLOCK()
  #define GUITASK_INIT()
#else
  #define GUI_LOCK() GUI_Lock()
  #define GUI_UNLOCK() GUI_Unlock()
  #define GUITASK_INIT() GUITASK_Init()
#endif
......
並且在Core\guitask.C文件中, 如果GUI_OS未定義, 則會:
void GUI_Unlock(void) {}
void GUI_Lock(void) {}
void GUITASK_Init(void) {}
void GUITASK_StoreDefaultContext(void) {}
將上面的幾個函數都定義爲空的.那什麼都不做.所以GUI_OS的主要作用是在進行多任時支持時的互鎖功能.當有了多任務支持,纔有必要提供鎖的功能. 這種鎖功能對於資源的訪問可以做到獨佔性而避免出現死鎖或使用過程中被修改的情況,在模擬器當中, 這幾個函數的實現都是通過WINDOWS的信息量功能來實現的..
GUI_OS未定義時,將被定義爲0.
#ifndef GUI_OS
  #define GUI_OS              0
#endif
2.關於GUI_SUPPORT_TOUCH
這個是關於觸摸屏的支持, 首先必須是非功過硬件有觸摸的支持, 詳情參看源碼.
3.關於GUI_SUPPORT_UNICODE
是否支持UNICODE碼的預定義, 如果進行了預定義,那麼顯示字符前會先轉化爲UNICODE碼. 主要在GUIUC0.C文件中提供.
4.GUI_DEFAULT_FONT
缺省字體, 在GUI\CORE\FONT文件夾下, 提供了十幾種字體的支持, 這裏的預定義將決定哪種字體將被支持, 要UCGUI中字體是點陣形式處理的, 而且是與GUI編譯在一起, 使用哪種字體就會將哪種字體編譯進去.在這裏. 如果要支持多種字體, 而又採用字體與GUI代碼編譯在一起的做法, 將使GUI的資源佔用非常大.缺省字體佔用關不多8K左右.
5.GUI_ALLOC_SIZE
GUI_ALLOC_SIZE指定UCGUI可自己動態使用的內存量, 默認的是12500, 差不多是12K左右.UCGUI中使用動態內存管理是類似NEW,DELETE的,原理是一樣的, 但比較簡單一點. 使用的是雙向鏈表, 在整個內存(12500)沒有使用之前,鏈表中只有一個節點, 當申請過一次後, 就會變成兩個節點, 一個記載申請的結點的內存信息,另外一個則是剩餘內存信息.
GUIAlloc.c文件當中提供了內存管理的功能.
typedef struct {
  tALLOCINT Off;       /* Offset of memory area */
  tALLOCINT Size;      /* usable size of allocated block */
  HANDLE Next;      /* next handle in linked list */
  HANDLE Prev;
} tBlock;
/****************************************************************
*              Static data
*/
GUI_HEAP GUI_Heap;       /* Public for debugging only */
static tBlock aBlock[GUI_MAXBLOCKS];
struct {
  int       NumUsedBlocks, NumFreeBlocks, NumFreeBlocksMin;        /* For statistical purposes only */
  tALLOCINT NumUsedBytes,  NumFreeBytes,  NumFreeBytesMin;
} GUI_ALLOC;
#define HMEM2PTR(hMem) (void*)&GUI_Heap.abHeap[aBlock[hMem].Off]
GUIHEAP在GUI.h中提供的.
typedef union {
  int aintHeap[GUI_ALLOC_SIZE/4];     /* required for proper alignement */
  U8  abHeap[GUI_ALLOC_SIZE];
} GUI_HEAP;
extern GUI_HEAP GUI_Heap;     /* Public for debugging only */
以上幾點是內存管理的關鍵數據結構.
GUI_Heap是一個聯合體結構, 其內數據可以以INT整型, 一次以四個字節來訪問; 也可以以字節來訪問,一次訪問一個字節, 這塊內存是以數組的形式來提供的.GUI_HEAP GUI_Heap; 這個全局變量即是UCGUI中可以動態分配使用的全部內存, 在分配使用時, 是按照塊來使用的. tBlock aBlock[GUI_MAXBLOCKS];這個全局變量定義了可以用來管理動態內存的節點信息的塊數組.
GUI_MAXBLOCKS的大小如下:
#ifndef GUI_MAXBLOCKS
  #define GUI_MAXBLOCKS (2+GUI_ALLOC_SIZE/32)
#endif
如果是總共內存爲12500個字節, 則要48個這樣的塊結構.其佔用內存大小爲48*sizeof(tBlock)=48*16=768字節,這是最大的佔用; 小的時候爲一半, 結點大小爲8個字節. 這768個字節是爲了動態內存分配負出的代價.
當第一次申請一塊內存時. 整個動態內存的最初狀態是:
  aBlock[0].Size = (1<<GUI_BLOCK_ALIGN);  /* occupy minimum for a block */
  aBlock[0].Off  = 0;
  aBlock[0].Next = 0;
那麼申請動態內存之前, 第一步就是先從塊結構數組(即記錄動態內存分配狀況的數組)中找一個空閒的元素. 來作爲記錄將要分配內存的節點. 第二步,所有的塊結構數組當中查找出可供使用的內存, 並將此內存的偏移地址, 這個偏移是相對於GUI_Heap這個整個動態內存的起始點的偏移.
舉一個實際的例子如下:
aBlock[0].Size = 4;
aBlock[0].Off  = 0;
aBlock[0].Next = 0;
aBlock[0].Pre = 0;
當成功分配兩塊大小爲500的內存時, 結點狀態如下:
aBlock[0].Size = 4;
aBlock[0].Off  = 0;
aBlock[0].Next = &aBlock[1];
aBlock[0].Pre = &aBlock[2];
aBlock[1].Size = 500;
aBlock[1].Off  = 3;
aBlock[1].Next = &aBlock[2];
aBlock[1].Pre = &aBlock[0];
aBlock[2].Size = 500;
aBlock[2].Off  = 503;
aBlock[2].Next = &aBlock[0];
aBlock[2].Pre = &aBlock[1];
此時GUI_Heap的內存使用狀態如下:
從GUI_Heap.abHeap[0]到GUI_Heap.abHeap[3]爲一塊, 使用狀態記錄於aBlock[0];
從GUI_Heap.abHeap[4]到GUI_Heap.abHeap[503]爲一塊, 使用狀態記錄於aBlock[1];
從GUI_Heap.abHeap[504]到GUI_Heap.abHeap[1007]爲一塊, 使用狀態記錄於aBlock[2];
此時剩餘的是GUI_Heap.abHeap[1008]---GUI_Heap.abHeap[12499]這一段.
如果在此基礎上, 要現分一塊大小爲爲1002字節的, 則會首先討調整大小(1002+1<<GUI_BLOCK_ALIGN-1) & 0x3, 將其大小調整爲4的倍數對齊.其後, 則會通過查找, 找到aBlock[3].Size記錄爲0, 那麼這個塊節點可以用來記錄一個內存配信息.
查找用於記錄該塊內存的結點時,  從aBlock[0]查起, 發覺0---3已用, 查看結點aBlock[1], 得知4-503這夫內存已分配, 再查看其它已分配結點,  可得知 0---1007 爲已分配,  其餘都沒有使用, 即此次分配起點爲1008, 即1008~(1008+1004).
分配之後, 記錄內存分配信息的結點狀態如下:
aBlock[0].Size = 4;
aBlock[0].Off  = 0;
aBlock[0].Next = &aBlock[1];
aBlock[0].Pre = &aBlock[3];
aBlock[1].Size = 500;
aBlock[1].Off  = 3;
aBlock[1].Next = &aBlock[2];
aBlock[1].Pre = &aBlock[0];
aBlock[2].Size = 500;
aBlock[2].Off  = 503;
aBlock[2].Next = &aBlock[3];
aBlock[2].Pre = &aBlock[1];
aBlock[3].Size = 1004;
aBlock[3].Off  = 2012;
aBlock[3].Next = &aBlock[0];
aBlock[3].Pre = &aBlock[2];
這種情況是最理想的狀態下, 如果說內存經過多次分配與釋放, 則情況將複雜一些. 比如說, 如果剛纔所說的第一次申請的500個字節內存已經用完並被釋放掉了,此時記錄節點狀態如下所示:
aBlock[0].Size = 4;
aBlock[0].Off  = 0;
aBlock[0].Next = &aBlock[2];   //不再指向1,直接指向2.
aBlock[0].Pre = &aBlock[3];
aBlock[1].Size = 0;
aBlock[1].Off  = 0;
aBlock[1].Next = 0;
aBlock[1].Pre = 0;
aBlock[2].Size = 500;
aBlock[2].Off  = 503;
aBlock[2].Next = &aBlock[3];
aBlock[2].Pre = &aBlock[0]; //不再指向1, 直接指向0.
aBlock[3].Size = 1004;
aBlock[3].Off  = 2012;
aBlock[3].Next = &aBlock[0];
aBlock[3].Pre = &aBlock[2];
在這種情況下, 如果再要求申請一塊200字節的內存,  則會找到空閒節點aBlock[1]來記錄此次內存分配.  此次分配會導致在aBlock[1]與aBlock[2]這間產生一個300字節的HOLE. 如果後來又有200字節的內存分配請求. 則aBlock[4]將會用於記載此次內存分配.
現在就有分配, 之後釋放, 然後又有分配的過程做一個完整的分析如下:
1. 申請500字節,
2. 再申請500字節,
3. 再申請1002字節
4. 進行釋放, 將第1次的500字節釋放掉.
5. 再申請一次200字節,
6. 再申請一次100字節,
7. 再申請一次400字節.
那麼此時的內存格局最終是什麼樣子呢?? 如下所示:
aBlock[0].Size = 4; 
aBlock[0].Off  = 0;
aBlock[0].Next = &aBlock1];   //再一次指向1.先前在第4步釋放500字節時, 指向2.aBlock[1]節點空閒..aBlock[1]最開始記載的是第1次分配的500字節內存
aBlock[0].Pre = &aBlock[5];    //指向5..
aBlock[1].Size = 200;             //第1次申請了500,第5次時被free後被用作記載第4次配200.
aBlock[1].Off  = 4;
aBlock[1].Next = &aBlock[2];
aBlock[1].Pre = &aBlock[0];   //指向0..
aBlock[2].Size = 500;
aBlock[2].Off  = 503;
aBlock[2].Next = &aBlock[3];
aBlock[2].Pre = &aBlock[1];    //再一次指向1.
aBlock[3].Size = 1004;
aBlock[3].Off  = 2012;
aBlock[3].Next = &aBlock[4];
aBlock[3].Pre = &aBlock[2];
aBlock[4].Size = 100;  //第5次分配100. 還是在原來的第1次配500的空間內.
aBlock[4].Off  = 203;
aBlock[4].Next = &aBlock[5];
aBlock[4].Pre = &aBlock[3];
aBlock[5].Size = 400; //第6次分配400, 第1次申請的500 free後已經用300,剩200不夠,只能從後面中找空間
aBlock[5].Off  = 2013+400;
aBlock[5].Next = &aBlock[0];
aBlock[5].Pre = &aBlock[4];
最終內存空間分佈情況如下:
0~~3-----------------------首結點4字節.
4~~203--------------------第4次分配佔用
204~~303-----------------第5次分配佔用
304~~503-----------------free
504~~1003---------------第二次分配佔用
1004~~2013--------------第三次分配佔用
2014~~2413--------------第六次分配佔用
如此, 這個內存分配的過程與原理就比較清晰的展示出來了, 在整個內存分配過程中, 用於記錄內存分配狀態的節點數組中, 形成的鏈表是在爲不斷的變化中的.認清這種變化纔可以對內存分配的本質有所認識, 才能夠真正分清內存分配.
5.關於GUI_WINSUPPORT
GUI_WINSUPPORT是用於是否須要窗口支持的, 在UCGUI當中提供了Frame winodws,edit, button, progress等基本的圖形控件,與WINDOWS上的類似, 但目前的功能則還不盡人意.圖形效果與功能都不強..
6.關於GUI_SUPPORT_MEMDEV
GUI_SUPPORT_MEMDEV是指顯示時, 是直接寫一個一個象素到顯示設備, 還是在內存當中當畫好所有要畫一屏幕點後再全部一次寫到顯示設置. 這兩點的主要區別是, 如果一個一個點寫, 則會出現閃的現象, 因爲一個一個點的畫, 如果速度慢, 可以扞到畫一個複雜的圖形時,是分幾步一點點的畫出來的...但是如果先畫到內存當中, 再一次性COPY所有象素點到顯示設備就不會有這種現象, 是一個連續的過程..畫點時是連續的畫,沒有間隔.
7.關於GUI_SUPPORT_AA
GUI_SUPPORT_AA是指是否須要對邊界進行模糊填充的功能, 比如說, 畫一條斜線, 可以看到是一段一段的:
        \
         \
           \
            \
              \
               \
這樣從效果上看, 那麼不是特別美觀, 如果可以在線的偏離的周圍進行線的顏色的淡化處理,即在線的周圍填充一點*近線的顏
色的象素點..那麼看上去將會偏離得沒那麼明顯, 比較模糊一點.
二. GUITouch.h的配製.
#ifndef GUITOUCH_CONF_H
#define GUITOUCH_CONF_H
#define GUI_TOUCH_AD_LEFT  20  
#define GUI_TOUCH_AD_RIGHT  240   
#define GUI_TOUCH_SWAP_XY    1
#define GUI_TOUCH_MIRROR_X   0
#define GUI_TOUCH_MIRROR_Y   1
#endif /* GUITOUCH_CONF_H */
由以上可以看出.GUITouch.h可預定義的選項更少了, 只是一些數值上的定義, 基本不會影響到UCGUI編譯後的代碼大小.
三.關於LCDConf.h
#define LCD_XSIZE      (320)   /* X-resolution of LCD, Logical coor. */
#define LCD_YSIZE      (240)   /* Y-resolution of LCD, Logical coor. */
#define LCD_BITSPERPIXEL (16)
#define LCD_CONTROLLER 1375
//Add by houhh 20050420
/*********************************************************************
*
*                   List of physical colors
*
**********************************************************************
*/
/*********************************************************************
*
*                   Full bus configuration
*
**********************************************************************
*/
#define LCD_READ_MEM(Off)            *((U16*)         (0xc00000+(((U32)(Off))<<1)))
#define LCD_WRITE_MEM(Off,data)      *((U16*)         (0xc00000+(((U32)(Off))<<1)))=data
#define LCD_READ_REG(Off)            *((volatile U16*)(0xc1ffe0+(((U16)(Off))<<1)))
#define LCD_WRITE_REG(Off,data)      *((volatile U16*)(0xc1ffe0+(((U16)(Off))<<1)))=data
    .
    .
    .
    .
#endif /* LCDCONF_H */
1. LCD_XSIZE/LCD_YSIZE
這是指定LCD顯示屏的寬高的.
2.LCD_BITSPERPIXEL
是指定屏幕上一個象素由幾位來表示. 位數越多, 能夠表示的顏色數就越多. 一屏所佔用的內存就越多.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章