劉剛
(蘇州市職業大學計算機工程學院,蘇州215104)
隨著工業物聯網的發展,各種嵌入式產品也得到了廣泛地應用。這些嵌入式產品將感知、監控、控制、通信等技術融入到了工業生產的各個環節,在提高制造效率,改善產品質量,降低生產成本等方面發揮了巨大的作用[1]。串口通信技術作為嵌入式產品開發中一項重要的通信技術,其通信性能的高低決定了嵌入式產品的性能好壞。特別是對實時性要求較高的應用尤為重要。傳統的雙串口通信機制在數據收發和處理時存在程序的負荷過重,響應不及時的缺點。為了解決這個問題,本文設計了一個新的高性能雙串口通信模型,該模型的每個串口對應一個應用進程,負責和單個串口進行通信和數據處理。當兩個串口之間需要數據交互時,兩個應用程序可通過進程間通信實現。這樣減輕了程序的處理負荷,降低了程序之間的耦合度,加快了程序的響應速度,提升了用戶體驗。
串行接口(簡稱串口)是計算機上通用的設備通信協議。它將接收來自CPU的并行數據轉換為串行數據流發送出去,同時可將接收到的串行數據流轉換為并行的數據字符供給CPU,來實現數據處理設備和外圍設備之間的信息傳輸[2]。其通信示意圖如圖1所示。

圖1串口通信示意圖
由于串口通信是一種通用的,且使用非常廣泛標準協議,因此在進行應用程序開發時有很多標準的串口通信組件或接口可使用。CnComm[3]是llbird開發的Windows/WinCE多線程串口通訊開源庫,使用C++(ANSI/Unicode)開發,支持的平臺包括Windows
(Win98/NT/2000/XP/2003/Vista)、WinCE 5.0/6.0、Pock?et PC 2003,在BC++5(free tool)、C++Builder 4,5,6,X、EVC 4(sp4)、G++3,4、Intel C++7,8,9、VC++6(sp6)、.NET 2003,2005等,提供同步I/O并發訪問的支持,內存管理采用內存池技術。CnComm多線程串口類的類結構如圖2所示。

圖2 CnComm多線程串口類結構
CnComm是定義的多線程串口類,CnComm::Block?Buffer類是根據通訊特點開發的緩沖區類,單向鏈表內存塊,提供一些擴展以支持和API掛接,CnComm::In?nerLock是自動鎖類,用于函數內部,利用對象的生命周期完成鎖定及解鎖,CnComm::MfcException是一個異常處理類,用于MFC的異常處理,CnComm::BlockBuf?fer::Block是定義的緩沖區內存塊,CnComm::BlockBuf?fer::InnerLock是定義的自動鎖類,CnComm::BlockBuf?fer::Iterator是定義的緩沖區迭代器。
英達EM9000是一款面向工業自動化領域的高端嵌入式工控主板[4]。其內核CPU為200MHz的ARM920T,預裝正版Window CE5.0實時多任務操作系統。EM9000帶有一個10M/100M自適應快速以太網接口、4個異步串口以及2個HOST模式的USB接口、一個高速全雙工SPI以及一個CAN總線接口。EM9000產品正視圖如圖3所示。

圖3 EM9000工控板正視圖
EM9000的4個輸入輸出插座,是按照一定的功能劃來配置的。CN1主要系統的通訊接口(如以太網、異步串口、USB等)和矩陣鍵盤;CN2主要包括精簡ISA擴展總線、GPIO以及+5V電源供電,數字音頻和SPI與部分GPIO管腳復用;CN4主要是TFT LCD接口信號和觸摸屏;而CN5則只包括標準IDE接口信號。EM9000的CN1、CN2和CN4所在位置示意圖如圖4所示。

圖4 EM9000的CN1、CN2、CN4和CN5所在位置示意圖
本文使用Visual Studio 2005創建應用程序,在創建應用程序之前,假設讀者已搭建好了開發環境(包括WinCE SDK、EM9000SDK和Visual Studio 2005的安裝與配置等),也已經下載了相應的CnComm類庫文件。
首先,打開Visual Studio 2005,選擇創建新項目。在項目創建向導中,選擇智能設備->MFC智能設備應用程序,并為程序輸入一個合適的項目名稱。接下來在Platform SDK中,選擇之前已經安裝好的EM9000 SDK,應用程序類型選擇基于對話框的類型。
首先,在新建的項目中,導入CnComm.h頭文件。接著,在應用程序類中添加兩個CnComm類對象m_com1和m_com2。之后,在應用程序的初始化實例中,就可以打開串口,代碼如下:
BOOL CSerialTest::InitInstance()
{
if(!m_com1.IsOpen())
{
if(!m_com1.Open(1,19200)){
return false
}
}
if(!m_com2.IsOpen())
{
if(!m_com2.Open(2,19200))
{
return false
}
}
}
首先,在CSerialTestDlg類的初始化函數中設置串口數據接收的窗口句柄,代碼如下:
theApp.m_com1.SetWnd(this->m_hWnd);
theApp.m_com1.SetWnd(this->m_hWnd);
其次,在SerialTestDlg.h文件中,添加消息處理函數,代碼如下:
afx_msg LRESULTOnComRecv(WPARAM,LPARAM)
接著,在SerialTestDlg.cpp文件中,添加消息映射,代碼如下:
BEGIN_MESSAGE_MAP
ON_MESSAGE(ON_COM_RECEIVE,OnComRecv)
END_MESSAGE_MAP
最后,實現OnComRecv消息處理函數,代碼如下:
LRESULT CSerialTestDlg::OnComRecv(WPARAM wParam,
LPARAMlParam)
{
int portNum=(int)wParam;
if(1==portNum)
{
BYTEbuf[256];
int len=theApp.m_com1.Read(buf,256);
buf[len]=0;
BYTEdata[]={0x01};
theApp.m_com2.Write((LPVOID)data,sizeof(data)/sizeof
(BYTE));
}
elseif(2==portNum)
{
BYTEbuf[256];
int len=theApp.m_com1.Read(buf,256);
buf[len]=0;
BYTEdata[]={0x02};
theApp.m_com1.Write((LPVOID)data,sizeof(data)/sizeof
(BYTE))
}
}
從上述代碼中可以看出,利用CnComm類進行串口通信應用開發非常方便,只需要定義兩個串口對象,之后就可以調用CnComm類中封裝好的函數,完成諸如串口的打開、數據的發送和接收等。上述的雙串口通信中,數據的接收處理全部是在OnComRecv函數中完成,其通信模型如圖5所示。

圖5傳統雙串口通信模型
傳統通信模型的優點是:若串口1和串口2之間存在信息交互,可直接調用對方串口對象的Write函數實現信息的發送。但問題是串口1和串口2的數據處理全部糅合在一個應用程序中完成,增加了應用程序數據處理的負荷,特別是對于一些復雜的、耗時的處理和實時性要求較高的應用,就會造成程序卡頓或假死現象。
為了解決上述問題,本文設計了一個新的高性能雙串口通信模型,如圖6所示。該模型每個串口對應一個應用程序,負責和單個串口進行通信和數據處理。當兩個串口之間需要數據交互時,兩個應用程序可通過進程間通信實現。

圖6高性能雙串口通信模型
單串口通信應用程序僅需要創建一個串口類對象,其余過程實現和第2節所述過程完全相同,這不再贅述。若串口1和串口2之間有信息交換,可通過兩個單串口應用程序的進程間通信來完成,即通過向對方窗口發送WM_COPYDATA消息來實現。以串口1給串口2發送數據,串口2接收串口1的發送來的數據為例。
(1)串口1給串口2發送數據,通過FindWindow函數找到串口2應用程序的進程,將所要發送的數據封裝到COPYDATASTRUCT的結構體中,之后向串口2的應用程序窗口發送WM_COPYDATA消息即可。具體代碼如下:
CString sendContent=“要發送的數據”;
LRESULTcopyDataResult;
CWnd*pOtherWnd=CWnd::FindWindow(NULL,“App2”);
if(pOtherWnd)
{
COPYDATASTRUCTcpd;
cpd.dwData=1;
cpd.cbData=2*sendContent.GetLength()+1;
cpd.lpData=(void*)sendContent.GetBuffer(cpd.cbData);
copyDataResult=pOtherWnd->SendMessage(WM_COPY?
DATA,this->m_hWnd,(LPARAM)&cpd);
}
(2)串口2接收串口1發送來的數據
給應用程序2的對話框類添加WM_COPYDATA消息,此消息處理函數可以接收到應用程序1進程發送過來的數據,并在其中對接收來的數據進行處理。具體代碼如下:
BOOL CApp2Dlg::OnCopyData(CWnd*pWnd,COPYDATA?STRUCT*pCopyDataStruct)
{
CString strReceivedText=(LPWSTR)(pCopyDataStruct->lpData);
strReceivedText=strReceivedText.Left(pCopyDataStruct->cbData);
}
本文所提出的通信模型,將每個串口數據的收發和處理獨立開來,分別剝離到單一的應用程序中。這樣就減輕了程序的處理負荷,降低了程序之間的耦合度,加快了程序的響應速度。避免應用程序出現卡頓或假死的現象,提升了用戶體驗。圖7和圖8是相同功能采用兩種通信模型實現的應用程序在CPU處理負荷和響應速度上的表現。由圖7和圖8可知,本文所提模型在CPU負荷上相比傳統模型平均降低了41%,在響應速度上平均加快近了4.5倍。

圖7 CPU處理負荷對比

圖8響應速度對比
串口通信是嵌入式應用開發中進行設備間數據交換的重要途徑之一。在應用程序開始時,面對傳統雙串口通信模型的缺點,本文提出了一種高性能雙串口通信模型,該模型相比傳統通信模型平均降低CPU負荷41%,提升程序的響應速度約4.5倍。