歡迎您光臨本站 登入註冊首頁

概述

 目前,嵌入式Linux設備已廣泛應用到計算機、通信和工業控制等領域,負責各種數據的處理和存儲,並進行控制決策。MiniGUI是一種面向嵌入式系統和實時系統的圖形用戶界面支持系統。在MiniGUI環境……

 目前,嵌入式Linux 設備已廣泛應用到計算機、通信和工業控制等領域,負責各種數據的處理和存儲,並進行控制決策。MiniGUI 是一種面向嵌入式系統和實時系統的圖形用戶界面支持系統。在MiniGUI 環境下實現多個RS-232 串口通信,多串口實時協同工作,可滿足許多工控和通信場合需要。該文實現平台為擴展了5 個串口的Intel PXA255 Sitsang 的嵌入式硬體平台以及基於嵌入式Linux2.4.19 的軟體平台,採用MiniGUI 作為圖形用戶界面,在MiniGUI 的兩個運行模式下設計並實現了多個串口的實時雙工通信。

1  MiniGUI 及其兩個運行模式
    目前,在Linux 之上進行(實時) 嵌入式系統開發,一般選擇如下幾種GUI 系統:緊縮的X Window 系統、MiniGUI、MicroWindows、OpenGUI、QT/Embedded 等。該文採用MiniGUI 1.3.0 版本作為系統GUI ,應用程序建立在圖形界面和嵌入式Linux 內核之上。
    MiniGUI 可以編譯成兩個截然不同的運行模式:一個是MiniGUI-Threads ,一個是MiniGUI-Lite 。MiniGUI-Threads 具有非常高的實時性,採用了線程機制。MiniGUI-Threads 的應用程序,可以具有多個線程,每個線程有不同的功能和任務,可以在不同的線程中建立多個窗口,但所有的窗口在一個進程或者地址空間中運行。不同的線程之間可通過MiniGUI 的消息傳遞機制進行事件傳送和同步。但顯然,這種基於線程的結構也導致了系統整體的脆弱,如果某個線程因為非法的數據訪問而終止運行,則整個進程都將受到影響。不過,這種體系結構對實時控制系統等時間關鍵的系統來講,還是非常適合的。為了改變Threads 版本體系上的脆弱, MiniGUI-Lite 版本使用進程機制。和MiniGUI-Threads 相反,MiniGUI-Lite 上的每個程序是單獨的進程,每個進程也可以建立多個窗口。在Lite 版本中,可以同時運行多個MiniGUI 應用程序。首先需要啟動一個伺服器程序mginit ,然後啟動其他作為客戶端運行的MiniGUI 應用程序。如果因為某種原因客戶終止,伺服器不受影響,可以繼續運行。

2  MiniGUI-Threads 下多線程串口通信
  串口通信程序要做到實時性高,吞吐量大,程序的輸出與輸入是兩個需要併發執行的操作,因此在MiniGUI-Threads 下採用多線程技術。在多串口的MiniGUI 環境下,通信程序至少應具備如下兩個線程:主線程和串口監聽線程。主線程是串口通信程序的管理者,用來進行人機交互的操作、部分串口操作和數據處理及協調好各線程運行;串口監聽線程的職責是實時監聽各個串口的狀態,一旦發生預定的事件,需要判斷是哪個串口有數據到來,然後進行一定的數據處理,並立即向主線程發送相應消息,請求主線程對其進行相應處理。主線程在接到串口監聽線程發送來的消息后,立即調用相應的過程函數進行處理。串口通信程序可以在MiniGUIMain() 中通過CreateThreadForMainWindow 函數創建了兩個併發的線程,定義線程的入口函數地址並返回線程標識符。
    在主線程中配置termios 結構完成對串口的初始化操作,創建主窗口,建立控鍵並進入消息循環。監視線程和主線程同時啟動,此後串口監視線程在後台對各個串口進行實時監控,在監視到預定事件時,立即通過SendMessage 向主線程發送相應的消息。與此同時,主線程對監視線程發送來的消息作出相應的處理,讀取串口數據到緩衝區。主線程在處理完該消息后,串口監視線程繼續執行後面的程序代碼,對串口繼續監聽。主線程還可以同時進行其他工作,比如接收或處理鍵盤、滑鼠一類的消息,數據顯示和響應控制項事件等。
    MiniGUI-Threads 下的SendMessage 的傳遞機制,可以用來發送“同步消息”。如果發送消息的線程和接收消息的線程不是同一個線程,發送消息的線程將阻塞並等待另一個線程的處理結果,然後繼續運行;如果發送消息的線程和接收消息的線程是同一個線程,則與MiniGUI-Lite 的SendMessage一樣, 直接調用接收消息窗口的過程函數。
    MiniGUI 定義了MSG_USER 宏,用戶能夠自定義消息,並利用自定義消息傳遞數據。應用程序可如下定義自己的消息:
# define MSG_MYMESSAGE1 (MSG_USER + 1) ;
# define MSG_MYMESSAGE2 (MSG_USER + 2) 。
    這種方式能有效防止數據的堵塞,避免線程出現死鎖等情況的出現。MiniGUI-Threads 下串口通信程序過程如圖1 所示。
 
圖1  串口通信程序框圖

3  MiniGUI-Lite 下多進程串口通信
  Lite 版本是支持客戶伺服器(C/S) 方式的多進程系統,在運行過程中有且僅有一個伺服器程序在運行,它的全局變數mgServer 被設為TRUE ,其餘的MiniGUI 應用程序為客戶,mgServer 變數被設為FALSE。各個應用程序分別運行於各自不同的進程空間,如圖2 所示。
 
圖2  Lite 版本下的多進程系統
    串口通信程序要在MiniGUI-Lite 下做到實時性高,吞吐量大,管理協調,可以參照MiniGUI -Threads 下串口通信程序的設計,分別建立伺服器程序和客戶監聽程序。
    根據MiniGUI-Lite 的特點,多串口通信程序首先初始化並啟動伺服器程序。MiniGUI-Lite 下伺服器程序名需要命名為mginit ,該程序為客戶應用程序準備共享資源,並管理客戶應用程序。首先,需要初始化OnNewDelClient 和OnChangeLayer 這兩個伺服器程序特有的全局變數。這兩個變數是兩個函數的指針變數,分別用來監視來自客戶和層的事件。當客戶連接到mginit 或者斷開與mginit 之間的套接字連接時,如果程序設置了OnNewDelClient這個變數,將調用這個變數指向的函數。同樣,當MiniGUI-Lite 的層發生變化時,比如有新的客戶加入到某個層,或者層中的活動客戶發生了變化,如果程序中設置了OnChangeLayer 這個變數,則會調用這個變數指向的函數。通過調用這些函數,可以得到客戶標號或者層的指針、客戶指針,mginit 程序就可以方便地訪問MiniGUI 函數庫中的內部數據結構,獲得當前的客戶以及當前層的所有信息,從而管理客戶程序。接著調用ServerStart up 函數啟動mginit 的伺服器功能,這個函數所做的工作比較簡單,就是建立監聽客戶連接的套接字(/ var/ tmp/minigui) 並返回。最後調用SetDesktopRect 設定屏幕上由伺服器獨佔的矩形區域,客戶程序不能使用這塊矩形區域。設定之後,客戶程序就只能在這個獨佔的區域以外進行繪製。伺服器初始化完畢后,用exec_app () 函數啟動客戶串口監聽程序,完成伺服器和客戶程序的建立。
   為了實現客戶和伺服器之間的通訊,MiniGUI-Lite 通過經過封裝的UNIX Domain Socket 處理函數在伺服器和監聽程序之間進行數據傳遞。伺服器可以使用serv_listen ( ) 函數建立一個監聽套接字,並返回套接字文件描述符:
# define L ISTEN_SOCKET " / var/ tmp/ mysocket"
static int listen_fd ;
BOOL listen_socket ( HWND hwnd)
{
 if ( (listen_fd = serv_listen (L ISTEN_ SOCKET) )< 0)
return FALSE;
eturn RegisterListenFD ( fd , POLL_IN , hwnd ,NULL) ; /*在系統中註冊監聽文件描述符,在被監聽的文件描述符上發生指定事件時, 向某窗口發送MSG_ FDEVENT 消息* /
}
    當伺服器接收到來自客戶的連接請求時,伺服器hwnd 窗口將接收到MSG_ FDEVEN T 消息,這時,伺服器可接受該連接請求:
int MyWndProc ( HWND hwnd , int message ,WPARAM wParam , L PARAM lParam)
{
switch (message) {
case MSG_FDEVENT :
if (LOWORD (wParam) = = listen_fd) { / *來自監聽套接字*/
pid_t pid ; uid_t uid ; int conn_fd ;
conn _ fd = serv _ accept ( listen _ fd , &pid ,&uid) ; /* 伺服器調用serv_accept () 函數接受來自客戶的連接請求*/
if (conn_fd > = 0) {
RegisterListenFD ( conn _ fd , POLL _ IN ,hwnd , NULL) ; }
}
else {  int fd = LOWORD(wParam) ; /* 來自已連接套接字*/
sock_read_t (fd , ...) ; /* 處理來自客戶的數據*/
sock_write_t (fd , ....) ; }
break ;
 }
}
  上面的代碼中,伺服器將連接得到的新文件描述符也註冊為監聽描述符, 因此,在MSG_ FDEVEN T 消息的處理中,應該判斷導致MSG_ FDEVEN T 消息的文件描述符類型,並適當處理。在客戶端,當需要連接到伺服器時,可通過如下代碼:
int conn_fd ;
if ( (conn_fd = cli_conn (L ISTEN_SOCKET , 'b') ) >= 0) {
/* 客戶調用cli_conn 函數連接到伺服器*/
sock_write_t (fd , ....) ; /* 向伺服器發送請求*/
sock_read_t (fd , ....) ; } /* 獲取來自伺服器的處理結果*/

4  兩種模式下需要注意的一些差別
4.1  實現串口監聽程序的差別
  串口監聽程序擔當著實時監控的任務,監視預定義事件。在MiniGUI-Threads 下監聽線程需要給主線程發送預定義消息;在MiniGUI-Lite 下,監聽程序要完成和伺服器的數據交換和通信。在這裡,預定義事件就是多個串口中有一個串口有數據到來時,判斷並鎖定這個串口進行數據讀取。使用I/O 多路復用( I/O multiplexing) 技術可以很好地解決這個問題。其基本思想是:先構造一張有關描述符的表,然後調用一個函數,它要到這些描述符中的一個已準備好的進行I/O 時才返回。在返回時,它告訴線程哪一個描述符已準備好可以進行I/O。使用這種返回值,就可調用相應的I/O 函數(一般是read 或write ) , 並且確知該函數不會阻塞。
    Linux 下的系統調用select 函數可以執行I/O 多路復用。Select 函數原型為:
Int select ( int maxf dp1 , fd_set *readfds , f d_set *writefds , fd_ set *exceptf ds , Struct timeval *tvpt r) ;
    在MiniGUI-Threads 中,因為每個線程都有自己相應的消息隊列,而系統消息隊列是由單獨運行的desktop 線程管理的,所以任何一個應用程序建立的線程都可以長時間阻塞,從而可以使用select系統調用。
    在MiniGUI-Lite 之上運行的應用程序只有一個消息隊列。應用程序在初始化之後,會建立一個消息循環,然後不停地從這個消息隊列當中獲得消息並處理,直到接收到MSG_QUIT 消息為止。應用程序的窗口過程在處理消息時,要在處理完消息之後立即返回,以便有機會獲得其他的消息並處理。現在,如果應用程序在處理某個消息時監聽某個文件描述符而調用select 系統調用,就有可能會出現問題———因為select 系統調用可能會長時間阻塞,而由MiniGUI-Lite 伺服器發送給客戶的事件得不到及時處理。這樣,消息驅動的方式和select 系統調用就難於很好地融合。在MiniGUI-Lite 當中,可以用以下幾種方法解決這一問題:
①在調用select系統調用時,傳遞超時值,保證select 系統調用不會長時間阻塞;
② 設置定時器,定時器到期時,利用select 系統調用查看被監聽的文件描述符。如果沒有相應的事件發生,則立即返回,否則進行讀寫操作;
③ 利用MiniGUI-Lite 提供的RegisterListenFD 函數在系統中註冊監聽文件描述符,並在被監聽的文件描述符上發生指定的事件時,向某個窗口發送MSG_FDEVENT 消息。

4.2  處理同步問題的差別
    在MiniGUI-Threads 下,對於共享資源的互斥性同步,可以使用“互斥(mutex) ”來解決,它是一種鎖或者信號燈,相關宏定義和函數包含在<pthread.h>中。當一個線程調用pthread_mutex_lock () 函數鎖定某個Mutex 后,其它也要鎖定Mutex 的線程將被阻塞,直至Mutex 被釋放,從而達到資源的獨佔。對於線程按正確順序執行的順序同步,正如上面提到的,Sendmessage 的消息傳遞機制起到了“事件同步”的作用。當一個線程要等待另一個線程的某個事件時,會把自己掛起,直至另一個線程的相應事件發生后把自己喚醒。而在MiniGUI-Lite 中主要是應用程序間的互斥性同步,可以使用Linux 下常用的“信號量機制”等方式解決多個進程的共享與互斥問題。

5  結論
    在嵌入式GUI 環境下,需要結合操作系統和GUI 系統的特點,充分利用兩者的資源來實現多串口通信。在Intel PXA255 Sitsang 板上實踐證明,在MiniGUI-Threads 下採用多線程技術, 在MiniGUI-Lite 下採用伺服器程序結合監聽程序,實現多串口全雙工通信,有效地解決了在串口通信中的實時響應問題,降低了數據的丟失率,提高了嵌入式系統的可靠性。


[admin via 研發互助社區 ] MiniGUI-Threads與MiniGUI-Lite下多串口通信的設計與實現已經有3413次圍觀

http://cocdig.com/docs/show-post-42172.html