,
(上海海事大學 信息工程學院,上海 201306)
引 言
伴隨著嵌入式技術的成熟,人性化圖形用戶界面在嵌入式系統(tǒng)中的應用愈發(fā)廣泛[1]。圖形用戶界面(Graphical User Interface,簡稱GUI),是指采用圖形方式顯示的計算機操作用戶界面。與命令行界面相比,圖形界面對于大部分用戶來說更易于接受和操作。
RFID手持終端致力于解決當前物流行業(yè)取貨、運輸、配送等場合出現(xiàn)的問題。同時為了降低設備成本且方便一線員工使用,本文采用Cortex-M4內核的STM32F407ZGT6作為處理器,輔以FreeRTOS操作系統(tǒng)和emWin GUI設計出簡單易操作的GUI界面用于人機交互,能夠很好地滿足實際需要。
1 RFID手持終端簡介
隨著物聯(lián)網(wǎng)普及和物流行業(yè)的快速發(fā)展,RFID標簽代替條碼標簽的趨勢愈發(fā)明顯,為了方便物流運輸環(huán)節(jié)運輸員對RFID標簽的操作,包括取貨環(huán)節(jié)輸入運單號和送貨環(huán)節(jié)讀取商品信息,并與物流數(shù)據(jù)中心保持信息交互,本文設計的RFID終端包括硬件和軟件部分。
1.1 硬件組成
考慮到RFID手持終端需要對標簽進行讀寫,與物流數(shù)據(jù)中心保持信息交互,并有很好的可操作性,故設計一款采用ARM 32位Cortex-M4內核的STM32F407ZGT6作為主控芯片,SIM800C作為數(shù)據(jù)傳輸模塊,MD3650A-HA 作為射頻讀寫模塊,且使用ATK-7’TFT LCD電容觸摸屏作為人機交互的RFID手持終端。另外,為了顯示快遞實時定位信息,給RFID手持終端增加GPS定位功能,以滿足快遞取貨送貨最后一公里的真實需求。
寫運單號面設計圖如圖1所示。

圖1 寫運單號面設計圖
1.2 軟件組成
綜合對RFID終端的使用場景、功能、成本、開發(fā)難度等方面考慮,采用輕量級FreeRTOS作為終端操作系統(tǒng),其具有最小的ROM、RAM和處理開銷且能提供任務管理、時間管理等一系列常用功能,其完全免費,源碼公開,同時具有可移植、可裁減、調度策略靈活的特點。二次開發(fā)簡單,可以方便地移植到各種單片機上運行[2-3],能夠很好滿足終端的使用需求。
2 嵌入式GUI
目前在嵌入式平臺上可用的GUI產(chǎn)品比較豐富,但大體上可分為如下幾類。
① 低端嵌入式GUI:包括emWin(μCGUI)、RT-Thread/GUI,此類GUI適用于單片機、ARM7、ARM Cortex-M等平臺,多與簡單的RTOS系統(tǒng)(比如FreeRTOS、μC/OS、RT-Thread)配合使用,開發(fā)語言為C語言。
② 中端嵌入式GUI:包括miniGUI、OpenGUI、Microwindows等等,主要適用于ATM7、ARM9、ARM11、ARM Cortex-R等平臺,多與嵌入式Linux、μCLinux操作系統(tǒng)配合使用,開發(fā)語言為C語言。
③ 高端嵌入式GUI:包括Qt/Embedded、Android、MFC等,主要適用于ARM9、ARM11、ARM Cortex-A等平臺,多與嵌入式Linux、Win CE/Win Phone操作系統(tǒng)配合使用,開發(fā)語言為C++和JAVA語言。
介于本文設計的物聯(lián)網(wǎng)終端主核芯片為ARM Cortex-M4架構的STM32F407,且采用的操作系統(tǒng)為FreeRTOS,結合手持終端要求的功耗低、成本低、性價比高等要求,選定SEGGER公司授權給ST(意法半導體)的STemwin,使用ST芯片的用戶均可以免費試用。emWin軟件架構和功能成熟,通過調用emWin提供的函數(shù)接口,可為圖形LCD操作任何應用程序提供方便有效且與處理器和LCD控制器無關的圖形用戶界面(GUI)。而且emWin對ROM和RAM的消耗并不高,這使得其在嵌入式人機交互場合廣受歡迎。
2.1 emWin簡介
emWin是德國SEGGER公司的一個嵌入式GUI圖形庫,GUI圖形庫的概念就好像它是一個平臺,我們只需要在這個平臺上通過其提供的方法寫自己的用戶界面應用程序,非常簡單、便捷。
emWin設計用于提供高效且獨立于處理器和顯示控制器的圖形用戶界面,用于任何使用圖形顯示進行操作的應用。它與單任務和多任務環(huán)境、專用操作系統(tǒng)或任何具有商業(yè)RTOS系統(tǒng)均兼容,同時由于其源代碼開放,使得開發(fā)難度大大降低。
2.2 emWin組成
在emWin界面應用程序中,每個頁面都是由三部分組成:
① 控件結構體數(shù)組:控件結構體數(shù)組包括此頁面用到的所有控件。
② 回調函數(shù):每個頁面都對應這著一個回調函數(shù),對界面進行的任何操作都會跳轉到回調函數(shù)里面對對應的消息函數(shù)進行處理。
③ 頁面創(chuàng)建函數(shù):所有的頁面和控件都對應一個句柄,通過句柄和ID可以找到并管理任意的頁面和控件。
另外,控件句柄、控件ID 、消息也是非常重要的三個元素。其具體實現(xiàn)如下:
static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] =//控件結構體數(shù)組{
控件(ID_0)
控件(ID_1)
……
控件(ID_x)
};
static void _cbDialog(WM_MESSAGE* pMsg){ //回調函數(shù)
case WM_PAINT:
//窗口重繪消息,要在Framewin或Window窗口之中顯示文字
//或繪制直線、矩形、圓等在這里實現(xiàn)
……
case WM_INIT_DIALOG:
//初始化消息,創(chuàng)建窗口/控件時對其初始化參數(shù)進行設置,即
//顯示的是未操作時的界面
……
case WM_NOTIFY_PARENT:
//操作觸發(fā)消息處理(操作屏幕程序會跑到這里),一般功能函
//數(shù)放在此消息下,比如點擊按鍵、點擊編輯框(任何的操作)所
//實現(xiàn)的功能
……
}
hWin= GUI_CreateDialogBox(控件結構體數(shù)組, 回調函數(shù), 父窗口句柄); //頁面創(chuàng)建函數(shù),返回該頁面句柄,即hWin
3 emWin移植
移植包括對emWin進行參數(shù)配置、LCD驅動程序、觸摸屏驅動程序編寫以及emWin與FreeRTOS操作系統(tǒng)接口修改等。
3.1 emWin配置文件參數(shù)
主要是針對實際情況進行相應的參數(shù)調整,本文采用LCD規(guī)格為800×480,控制器為GT811。
3.1.1 修改GUICong.c
在GUICong.c為emWin分配內存,這里使用外部RAM。代碼如下:
//設置EMWIN內存大小
#define GUI_NUMBYTES (500×1024)
#define GUI_BLOCKSIZE 0X80 //塊大小
void GUI_X_Config(void){
U32*aMemory=mymalloc(SRAMEX,GUI_NUMBYTES); //從外部RAM中分配內存
GUI_ALLOC_AssignMemory((void*)aMemory, GUI_NUMBYTES); //為存儲管理系統(tǒng)分配存儲塊
GUI_ALLOC_SetAvBlockSize(GUI_BLOCKSIZE); //設置塊大小
GUI_SetDefaultFont(GUI_FONT_6X8); //設置字體
}
3.1.2 修改GUICong.h
在GUICong.h中進行功能配置修改,設置如下:
#define GUI_NUM_LAYERS 10 //顯示的最大層數(shù)
#define GUI_OS (1) //使用操作系統(tǒng)
#define GUI_MAXTASK(5)
//最大可調用Emwin任務數(shù)
#define GUI_SUPPORT_TOUCH (1) //支持觸摸
#define GUI_DEFAULT_FONT &GUI_Font6x8 //默認字體
#define GUI_SUPPORT_MOUSE (1) //支持鼠標
#define GUI_WINSUPPORT (1) //窗口管理
#define GUI_SUPPORT_MEMDEV (1) //存儲設備
#define GUI_SUPPORT_DEVICES (1) //使用設備指針
3.1.3 配置LCDConf.h
根據(jù)觸摸屏的具體規(guī)格來修改LCDConf.h 文件里面的參數(shù),設置如下:
#define XSIZE_PHYS 800 //LCD 每一行的像素數(shù)
#define YSIZE_PHYS 480 ///LCD 的行數(shù)
#define COLOR_CONVERSION GUICC_M565
//選擇RGB565色彩模式
#define TOUCH_AD_TOP160
//按下觸摸屏的頂部,寫下Y軸模擬輸入值
#define TOUCH_AD_BOTTOM3990
//按下觸摸屏的底部,寫下Y軸模擬輸入值
#define TOUCH_AD_LEFT160
//按下觸摸屏的左側,寫下X軸模擬輸入值
#define TOUCH_AD_RIGHT3990
//按下觸摸屏的右側,寫下X軸模擬輸入值
#define CT_EXCHG_XY 1 //調轉 XY 坐標
#define CT_MAX_TOUCH 5 //電容觸摸屏最大支持的點數(shù)
3.2 LCD畫點程序
液晶驅動最核心的函數(shù)是畫點函數(shù),可以認為幾乎所有的emWin顯示功能都是通過最終調用畫點函數(shù)來實現(xiàn)的[4],本設計畫點函數(shù)設計如下:
//畫點,x,y:坐標,POINT_COLOR:此點顏色值
void LCD_DrawPoint(u16 x,u16 y){
LCD_SetCursor(x,y); //設置光標位置
LCD_WriteRAM_Prepare(); //開始寫入GRAM
TFTLCD->LCD_RAM=POINT_COLOR;
}
3.3 LCD觸摸屏驅動程序
STM32F407通過FSMC總線與觸摸屏模塊相連,首先調用GT811_Init()函數(shù)用于初始化電容觸摸屏驅動芯片GT811,并在其中開啟外部中斷1,使用GT811_Send_Cfg發(fā)送GT811的配置參數(shù)。初始化完成后,每當GT811有數(shù)據(jù)可供讀取的時候,CPU就可以在CT_INT信號上接收到一個脈沖信號(100us左右的低電平脈沖),CPU只需要在接收到CT_INT中斷后,調用GT811_Scan()函數(shù)依次讀取GT811的輸出信息寄存器,將讀取到的數(shù)據(jù)組織起來,就可以獲得最多5個點的觸摸數(shù)據(jù)。
3.4 操作系統(tǒng)相關接口部分的修改
FreeRTOS移植成功后,便可以將emWin與CPU的相關部分交給FreeRTOS處理,即需要提供一些內核接口函數(shù)來實現(xiàn)emWin在FreeRTOS上的運行。任務調度相關接口函數(shù)實現(xiàn)如下:
//GUI延時函數(shù)
void GUI_X_Delay(int period) {
vTaskDelay(period);}
void GUI_X_InitOS(void){
osMutex=xSemaphoreCreateMutex();//創(chuàng)建互斥信號量
vSemaphoreCreateBinary(osSemaphore);//創(chuàng)建二值信號量
}
//等待信號量
void GUI_X_Lock(void){
xSemaphoreTake(osMutex,portMAX_DELAY);
//請求信號量
}
//發(fā)送信號量
void GUI_X_Unlock(void){
xSemaphoreGive(osMutex);//釋放信號量
}
//返回任務ID
U32 GUI_X_GetTaskId(void){
return((uint32_t)xTaskGetCurrentTaskHandle());
//獲取任務ID
}
至此,emWin GUI的移植基本上完成,需要編寫測試用例,如果顯示效果不理想,再對移植的GUI進行底層配置優(yōu)化和改進。
4 用戶界面設計與功能實現(xiàn)
4.1 設計流程
本項目利用emWin的配套工具GUIBuilder,允許不使用C語言的情況下,編程圖形創(chuàng)建對話框??梢詫Υ翱谛〔考M行創(chuàng)建、拖曳、刪除和調整大小等操作,以實現(xiàn)組態(tài)、拖放式人機用戶界面設計[5]。GUIBuilder操作界面非常簡單、一目了然,生成的界面文件是標準C文件,將生成的C文件加到emWin工程中,并在emWin這個圖形庫平臺上運行,即可顯示所設計的界面。
初步界面設計完成后,用CodeBlocks進行模擬顯示,CodeBlocks是emWin脫機模擬仿真開發(fā)環(huán)境軟件,將emWin GUIBuilder保存的.c文件復制到Codeblocks示例文件的Application文件中,在LCDConf.c里面設置屏幕尺寸,GUIDEMO_Start.c里面創(chuàng)建主窗體,加入中文顯示庫和代碼并在對應按鈕消息下添加界面轉換函數(shù),便可模擬出GUIBuilder所設計的界面。
通過C語言和API函數(shù)對照emWin使用手冊可對模擬界面進行完善,以設計出更友善的人機交互界面。
最后將CodeBlocks中的C文件加入μVision工程中,并添加相應的功能實現(xiàn)代碼,燒錄進單片機之后便可進行實際測試。
物聯(lián)網(wǎng)終端擬設計主界面和4個子界面,子界面分別為讀標簽信息、寫入運單號、設置、GPRS數(shù)據(jù)傳送。下面就主界面和RFID標簽讀寫等三個界面進行具體分析。
4.2 RFID終端界面設計
GUIBuilder設計界面如圖2所示。模擬圖如圖3所示。

圖2 主界面設計圖

圖3 主界面模擬圖
控件結構體數(shù)組為:
static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = {
{FRAMEWIN_CreateIndirect, "TFT LCD", ID_FRAMEWIN_0, 0, 0, 800, 480, 0, 0x64, 0},
{ BUTTON_CreateIndirect, "read data", ID_BUTTON_0, 189, 126, 107, 33, 0, 0x0, 0 },
{ BUTTON_CreateIndirect, "write RFID", ID_BUTTON_1, 187, 240, 110, 35, 0, 0x0, 0 },
{ BUTTON_CreateIndirect, "send data", ID_BUTTON_2, 385, 241, 110, 37, 0, 0x0, 0 },
{ IMAGE_CreateIndirect, "Image", ID_IMAGE_0, 619, 318, 97, 99, 0, 0, 0 },
{ BUTTON_CreateIndirect, "Button", ID_BUTTON_3, 385, 123, 109, 33, 0, 0x0, 0 },
};
主要成員方法見表1。

表1 終端界面成員方法表
4.3 寫運單號界面
GUIBuilder設計界面如圖4所示。模擬圖如圖5所示。

圖4 寫運單號面設計圖

圖5 寫運單號面模擬圖
用12個按鈕來分別模擬數(shù)字0~9、空格和刪除鍵,其中數(shù)字和空格的按鈕操作觸發(fā)消息處理函數(shù)為:
void Button_trans(char k){
int i;
for(i=0;i<20;i++){
if(trans_number[i] == '