【第3版emWin教程】第20章 emWin6.x儲存裝置之基本函式
教程不斷更新中:http://www.armbbs.cn/forum.php?mod=viewthread&tid=98429
第20章 emWin6.x儲存裝置之基本函式
本章節為大家講解儲存裝置之基本函式,儲存裝置比較重要,如果想做出比較華麗,流暢的介面得靠這個。另外把儲存裝置放在本章節講解是因為下個章節講解BMP,JPG和GIF的圖片顯示要用到。
20.1初學者重要提示
20.2 儲存裝置基礎知識
20.3 儲存裝置基本函式及其應用
20.4 實驗例程說明(RTOS)
20.5 實驗例程說明(裸機)
20.6 總結
20.1 初學者重要提示
- 相對來說,儲存裝置章節還是比較重要的,初學者只需掌握本章節講到的函式即可。未講解的函式也有很多,以後的工程中用到的時候再查閱即可。
- 儲存裝置的的所有API函式在emWin手冊中都有講解,下圖是中文版手冊裡面API函式的位置
下圖是英文版手冊裡面API函式的位置:
20.2 儲存裝置基礎知識
說明:介紹知識整理自emWin官方手冊。
20.2.1 什麼是儲存裝置
儲存裝置就是指的emWin的動態記憶體,操作儲存裝置就是操作emWin動態記憶體,只是對於這種型別的使用起了一個名字叫儲存裝置。
儲存裝置主要用於防止在繪製重疊專案時出現顯示器閃爍。其基本思想很簡單,不使用儲存裝置時,繪製操作直接寫入顯示器,螢幕在執行繪製操作時隨時更新,導致在進行各種更新時使螢幕閃爍。例如,如果要在背景中繪製一個位圖,在前景中繪製一些透明文字,應首先繪製點陣圖,然後繪製文字,效果將使文字出現閃爍。但是,如果在此過程中使用儲存裝置,則所有繪製操作都在儲存器中執行,僅在所有操作都完成後才將最終結果顯示在螢幕上,其優點是沒有閃爍。
下面我們通過一個例項來說明使用儲存裝置和不使用儲存裝置的區別。兩種情況下的目的是相同的:將藍色背景旋轉10°,字元不旋轉。
- 第一種情況下:不使用儲存裝置,螢幕必須清除,然後在新位置重繪多邊形,並寫入帶新標誌的字串。
- 第二種情況下:使用儲存裝置,在儲存器中執行相同的操作,但螢幕此時不更新。僅在呼叫 GUI_MEMDEV_CopyToLCD() 例程時出現更新,並且僅更新一次就反映出所有操作。請注意,這兩種操作步驟的初始狀態和最終輸出是相同的。
通過上面四步對比可以發現:如果不使用儲存裝置,則可以看到一步步的繪製操作效果,缺點是會出現顯示器閃爍。使用儲存裝置時,僅更新一次可見到所有操作的效果,就象單次操作一樣,不能實際看見中間步驟,其優點是完全消除了顯示器的閃爍,這個就是使用儲存裝置的優勢。
20.2.2 支援的顏色深度(bpp)
bpp的含義是bit per pixel,即每個畫素點由幾位來表示,比如1bpp就表示每個畫素點由1位二進位制數來表示,8bpp就是由8位二進位制數來表示,依此類推。
儲存裝置有 4 種不同的色彩深度可用:1bpp、 8bpp、 16bpp 和 32bpp。emWin支援兩種儲存裝置的建立方式。
- 自動建立與顯示屏顏色格式相容的儲存裝置
有兩種建立與顯示屏顏色格式相容的儲存裝置的方法。如果要避免閃爍,則應建立與顯示器相容的儲存裝置。相容的儲存裝置必須具有與顯示器相同或更高的色彩深度。如果使用了函式 GUI_MEMDEV_Create()、GUI_MEMDEV_CreateEx(),則 emWin 會自動為顯示器選擇正確型別的儲存裝置。視窗管理器也能為系統中的某些或全部視窗使用儲存裝置,同樣也使用這些函式。這樣會自動使用具有最低色彩深度(消耗動態記憶體最小)的儲存裝置。
- 建立指定顏色格式的儲存裝置
通過函式GUI_MEMDEV_CreateFixed()來實現建立指定顏色格式的儲存裝置。
20.2.3 儲存裝置和視窗管理器
(注意,視窗管理器在後面的章節中會講到,這裡作為了解內容即可)
視窗管理器可與儲存裝置完美搭配。每個視窗都有一個標記,告訴視窗管理器是否應使用儲存裝置進行渲染。此標記可以在建立視窗時指定,也可在任何時候進行設定或者重設。如果為特定視窗設定了儲存裝置標記,則視窗管理器在繪製視窗時自動使用儲存裝置。它會在繪製視窗前建立一個儲存裝置,然後在繪製操作完成後將其刪除。如果有足夠的記憶體可用,會將整個視窗裝入視窗管理器所建立儲存裝置的記憶體中。如果沒有足夠的記憶體將整個視窗裝入儲存裝置中,則視窗管理器使用“分段”來繪製視窗。用於繪製操作的記憶體僅在繪製操作期間分配。如果在繪製或者重繪視窗時沒有足夠的記憶體可用,則不使用儲存裝置重繪視窗。
20.2.4 基本函式用法
以下是使用儲存裝置時通常的使用流程,比較容易:
1. 建立儲存裝置(使用 GUI_MEMDEV_Create()等函式)。
2. 啟用它(使用 GUI_MEMDEV_Select())。
3. 執行繪製操作。
4. 將結果複製到顯示器中 (使用 GUI_MEMDEV_CopyToLCD()等函式)。
5. 不再需要它時,刪除該儲存裝置 (使用 GUI_MEMDEV_Delete())。
20.3 儲存裝置基本函式及其應用
儲存裝置相關的API函式也非常多,這裡我們選擇幾個常用的函式進行說明。
20.3.1 儲存裝置建立函式
儲存裝置的建立主要有以下三個函式:
- GUI_MEMDEV_Handle GUI_MEMDEV_Create(int x0, int y0, int XSize, int YSize)
在位置x0,y0建立長為Xsize,寬為Ysize的儲存裝置,即一塊顯示區。此函式會建立與顯示器顏色格式相容的儲存裝置(比如,STM32F429支援8種顏色格式設定,儲存裝置的建立就與這些顏色格式相容)。
- GUI_MEMDEV_Handle GUI_MEMDEV_CreateEx(int x0, int y0,int XSize, int Ysize,int Flags))
此函式與上面的函式功能一樣,只是多了一個引數flag,此引數有兩種數值可以取:
-
- GUI_MEMDEV_HASTRANS
實際應用中推薦使用這個標誌,表示使用透明性標記建立儲存裝置,該標記確保正確繪製背景。
使用此引數時,等效於函式GUI_MEMDEV_Create。
-
- GUI_MEMDEV_NOTRANS
建立儲存裝置,無透明性。優勢是速度較快,使用此標記可加速儲存裝置約 30% - 50%,且可將儲存裝置用於非矩形區域。缺點是使用者必須確保正確繪製背景。
- GUI_MEMDEV_Handle GUI_MEMDEV_CreateFixed(int x0, int y0,
Int xSize, int ySize, int Flags,
const tLCDDEV_APIList * pMemDevAPI,
constLCD_API_COLOR_CONV * pColorConvAPI);
此函式用於建立指定顏色格式的儲存裝置,這個函式涉及引數較多,我們這裡不再進行說明,具體引數看emWin官方手冊的API函式說明即可,實際呼叫是比較容易的。
下面是在模擬器上實際執行的例子,可以在模擬器上面執行的完整例子程式碼在V7-518_emWin6.x實驗_儲存裝置之基礎函式(模擬器)裡面。
#include "GUI.h" #include "stdio.h" #ifndef GUI_CONST_STORAGE #define GUI_CONST_STORAGE const #endif extern GUI_CONST_STORAGE GUI_BITMAP bmpic; static GUI_CONST_STORAGE unsigned short _acpic[] = { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFDE, 0xFFBE, 0xFFBE, 0xFFBE, 0xFFBE, 0xFFBE, 0xFFBE, 0xFFDE, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFBD, 0xF75B, 0xF6F9, 0xF697, 0xEE34, 0xEE13, 0xEDD1, 0xEDD1, 0xEDD1, 0xEDD1, 0xEDD1, 0xEDD1, 0xEE13, 0xEE55, 0xF6B7, 0xF71A, 0xF75C, 0xFFBE, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, /* 後面的資料未列出 */ }; GUI_CONST_STORAGE GUI_BITMAP bmpic = { 64, // xSize 64, // ySize 128, // BytesPerLine 16, // BitsPerPixel (unsigned char *)_acpic, // Pointer to picture data NULL, // Pointer to palette GUI_DRAW_BMP565 }; static GUI_CONST_STORAGE unsigned long _acpic1[] = { 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, /* 後面的資料未列出 */ }; GUI_CONST_STORAGE GUI_BITMAP bmpic1 = { 64, // xSize 64, // ySize 256, // BytesPerLine 32, // BitsPerPixel (unsigned char *)_acpic1, // Pointer to picture data NULL, // Pointer to palette GUI_DRAW_BMP8888 } /********************************************************************* * * MainTask */ void MainTask(void) { GUI_MEMDEV_Handle hMem0; GUI_MEMDEV_Handle hMem1; GUI_MEMDEV_Handle hMem2; GUI_MEMDEV_Handle hMem3; /* emWin初始化 */ GUI_Init(); /* 設定字型 */ GUI_SetFont(&GUI_Font16B_ASCII); //////////////////////////方式一///////////////////////////////////// /* 建立記憶體裝置,並將RGB565格式的點陣圖繪製到記憶體裝置上 */ hMem0 = GUI_MEMDEV_CreateEx(0, 0, 64, 64, GUI_MEMDEV_HASTRANS); GUI_MEMDEV_Select(hMem0); GUI_DrawBitmap(&bmpic, 0, 0); GUI_MEMDEV_Select(0); /* 顯示RGB565格式的點陣圖 */ GUI_DispStringAt("This is RGB565 bitmap & GUI_MEMDEV_CreateEx", 100, 50); GUI_MEMDEV_WriteAt(hMem0, 20, 20); ////////////////////////////方式二/////////////////////////////////// /* 建立記憶體裝置,並將RGB565格式的點陣圖繪製到記憶體裝置上 */ hMem1 = GUI_MEMDEV_CreateFixed(0, 0, 64, 64, GUI_MEMDEV_HASTRANS, GUI_MEMDEV_APILIST_16, GUI_COLOR_CONV_565); GUI_MEMDEV_Select(hMem1); GUI_DrawBitmap(&bmpic, 0, 0); GUI_MEMDEV_Select(0); /* 顯示RGB565格式的點陣圖 */ GUI_DispStringAt("This is RGB565 bitmap & GUI_MEMDEV_CreateFixed", 100, 150); GUI_MEMDEV_WriteAt(hMem1, 20, 120); //////////////////////////////方式三///////////////////////////////// /* 建立記憶體裝置,並將ARGB8888格式的點陣圖繪製到記憶體裝置上 */ hMem2 = GUI_MEMDEV_CreateEx(0, 0, 64, 64, GUI_MEMDEV_HASTRANS); GUI_MEMDEV_Select(hMem2); GUI_DrawBitmap(&bmpic1, 0, 0); GUI_MEMDEV_Select(0); /* 顯示ARGB8888格式的點陣圖 */ GUI_DispStringAt("This is ARGB8888 bitmap & GUI_MEMDEV_CreateEx", 100, 250); GUI_MEMDEV_WriteAt(hMem2, 20, 220); ////////////////////////////////方式四/////////////////////////////// /* 建立記憶體裝置,並將ARGB8888格式的點陣圖繪製到記憶體裝置上 */ hMem3 = GUI_MEMDEV_CreateFixed(0, 0, 64, 64, GUI_MEMDEV_HASTRANS, GUI_MEMDEV_APILIST_32, GUI_COLOR_CONV_8888); GUI_MEMDEV_Select(hMem3); GUI_DrawBitmap(&bmpic1, 0, 0); GUI_MEMDEV_Select(0); /* 顯示ARGB8888格式的點陣圖 */ GUI_DispStringAt("This is ARGB8888 bitmap & GUI_MEMDEV_CreateFixed", 100, 350); GUI_MEMDEV_WriteAt(hMem3, 20, 320); while (1) { GUI_Delay(10); } } /*************************** End of file ****************************/
實際顯示效果如下,解析度600*400:
20.3.2 儲存裝置的選擇和顯示函式
在20.3.1小節的例子中,我們用到了儲存裝置選擇函式和顯示函式:
- void GUI_MEASDEV_Select (GUI_MEASDEV_Handle hMem)
此函式用於選擇要使用的儲存裝置,打算在哪個儲存裝置上面進行繪製操作,引數就新增哪個儲存裝置的控制代碼,。如果引數填為0,將啟用LCD,即繪製操作是在LCD上面進行的,而不是在儲存裝置上面進行的。
- void GUI_MEMDEV_WriteAt(GUI_MEMDEV_Handle hMem, int x, int y);
此函式用於將儲存裝置的內容繪製到LCD顯示屏上。
20.3.3 儲存裝置的其它函式
儲存裝置的還有很多其它的函式,我們這裡暫時不做講解了,20.3.1和20.3.2小節中的函式是實際專案中用到最多的,其餘的函式在emWin的官方手冊中大部分都有舉例說明,可以在模擬器上面執行下,看看實際的效果。另外在我們論壇的這個帖子中也有其它部分函式說明,有興趣可以看下:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=1892 。
20.4 實驗例程說明(RTOS)
配套例子:
V7-520_emWin6.x實驗_儲存裝置之基礎函式(RTOS)
實驗目的:
- 學習emWin的儲存裝置之基本函式。
- 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解析度介面效果。
20.5 實驗例程說明(裸機)
配套例子:
V7-520_emWin6.x實驗_儲存裝置之基礎函式(RTOS)
實驗目的:
- 學習emWin的儲存裝置之基本函式。
- 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動態記憶體。
20.6 總結
本章節主要為大家講解了儲存裝置裡面幾個常用的函式,還有很多其它函式沒有做講解,有興趣的話,這些沒有講到的函式可以練習下。