I/O 設(shè)備

基于多線程的氣象傳感器數(shù)字網(wǎng)絡(luò)化系統(tǒng)

ainet.cn   2007年08月28日

  1.引言

  隨著計算機(jī)技術(shù)、通信技術(shù)和數(shù)據(jù)處理技術(shù)的發(fā)展,利用計算機(jī)實現(xiàn)生成過程的自動化成為了提高生產(chǎn)力、減輕勞動強(qiáng)度的有效手段。其中對周圍環(huán)境氣象數(shù)據(jù)的實時監(jiān)控不僅與人們的生活息息相關(guān),而且對工業(yè)生產(chǎn)中設(shè)備的正常運作也起到至關(guān)重要的作用。鑒于串行通信是計算機(jī)與其他設(shè)備進(jìn)行數(shù)據(jù)交換時經(jīng)常使用的方法之一,它具有實現(xiàn)簡單,使用靈活方便,數(shù)據(jù)傳輸可靠等優(yōu)點,因此基于串口通信技術(shù),構(gòu)建一個多線程的氣象監(jiān)控系統(tǒng)是有十分有必要的。

  本文采用串口通信的方式接收由溫度、濕度傳感器采集到當(dāng)前環(huán)境參數(shù),利用Visual C++ 6.0提供的Windows API實現(xiàn)對串口的控制,采用多線程以及雙緩沖隊列技術(shù)可以實時獲取采集數(shù)據(jù)、本地存儲采集處理;同時還利用Socket通信技術(shù)使采集數(shù)據(jù)傳送到遠(yuǎn)程監(jiān)控中心,進(jìn)行數(shù)據(jù)分析濾波處理以及數(shù)據(jù)庫的存儲,并繪制出相應(yīng)的P—T曲線。

  2.軟件系統(tǒng)設(shè)計方案

  本系統(tǒng)由本地采集計算和遠(yuǎn)程監(jiān)控中心構(gòu)成一個C/S結(jié)構(gòu)監(jiān)控系統(tǒng)。在環(huán)境惡劣的工業(yè)現(xiàn)場,無法進(jìn)行人為的實時監(jiān)控,由硬件設(shè)備采集環(huán)境氣象參數(shù)首先發(fā)送給本地計算機(jī),然后傳送給遠(yuǎn)程監(jiān)控中心進(jìn)行處理。本地采集計算機(jī)利用Visual C++ 6.0提供的Windows API實現(xiàn)對串口的操作。主要包括串口通信、設(shè)備控制、數(shù)據(jù)存儲等模塊,操作方便,人機(jī)界面簡單清晰。在應(yīng)用過程中,首先需要設(shè)定串口配置參數(shù),如波特率、數(shù)據(jù)位、奇偶校驗等,串口初始化后,程序開始運行,采集到的數(shù)據(jù)同時被保存在擴(kuò)展名為.txt文件中。然后通過Socket的通信方式把采集到的數(shù)據(jù)傳送給遠(yuǎn)程監(jiān)控中心,由它來進(jìn)行數(shù)據(jù)在數(shù)據(jù)庫中的存儲,以及數(shù)據(jù)平滑濾波處理,并繪制出P—T曲線。整個系統(tǒng)實現(xiàn)流程如圖1所示。


 
  3.程序設(shè)計思想

  當(dāng)前,一般的MCU都內(nèi)置了串口的硬件控制模塊,用戶通過查詢和中斷的方法編寫比較簡單的控制程序就可以使用串口通信。但是,本系統(tǒng)要求在接收數(shù)據(jù)采集設(shè)備發(fā)送大量數(shù)據(jù)的同時完成對己接收到數(shù)據(jù)的實時存儲,如何處理好二者之間的關(guān)系,保證不會造成數(shù)據(jù)的缺失和程序的崩潰是程序設(shè)計的一個難點。本文重點對串口通信程序進(jìn)行了改進(jìn),盡量做到不因為串口通信影響整個系統(tǒng)的性能。

  Window的最大特征之一是設(shè)備無關(guān)性,使得Window程序員不用對硬件直接進(jìn)行操作。利用Window的SDK提供完備的API函數(shù)和以中斷方式驅(qū)動的通信程序,可以更加簡化串口通信編程。而且Window系統(tǒng)是搶先式的多任務(wù)操作系統(tǒng),使得應(yīng)用程序能夠同時執(zhí)行多個任務(wù),即在一個進(jìn)程中可以同時運行多個線程,系統(tǒng)可以不停的在多個線程之間切換。所以在串行通訊程序中應(yīng)用多線程就可以簡化應(yīng)用程序的結(jié)構(gòu),把一些復(fù)雜的運算放在后臺并行執(zhí)行,從而大大提高應(yīng)用程序的響應(yīng)實時能力。

  串口通信程序的輸出與輸入是兩個需要并發(fā)執(zhí)行的操作。如果由主線程獨自完成所有的工作,即在的單線程情況下,程序可能會不定期地鎖定。因此,為了具備實時響應(yīng)的能力和提高程序的效率,本文的串口通信程序程序設(shè)計如圖2所示。

圖2 串口程序設(shè)計示意圖

  應(yīng)用程序創(chuàng)建了輸出與輸入兩個子線程共同完成通信任務(wù)。而又由于串口發(fā)送和接收的數(shù)據(jù)是相對獨立的,故可將其分開,設(shè)置兩個緩沖區(qū),一個是發(fā)送緩沖區(qū)m_TxQueue,另一個是接收緩沖區(qū)m_RxQueue,并為每個緩沖區(qū)分別設(shè)置兩個指針,一個指向輸出線程將要發(fā)送的數(shù)據(jù),另一個指向輸入線程將要從緩沖區(qū)讀取數(shù)據(jù)的起始位置。這種方式稱之為采用雙緩沖隊列的方法,保證了無關(guān)數(shù)據(jù)的順序操作。

  3.1 多線程的設(shè)計

  線程是進(jìn)程內(nèi)的一條執(zhí)行路徑.它包含獨立的堆棧和CPU寄存器。每個線程共享所有的進(jìn)程資源,包括打開的文件、信號標(biāo)識及動態(tài)分配的內(nèi)存等等。一個進(jìn)程內(nèi)的所有線程使用同一個32位地址空間,而這些線程的執(zhí)行由系統(tǒng)調(diào)度程序控制,調(diào)度程序決定哪個線程可執(zhí)行和什么時候執(zhí)行線程。線程有優(yōu)先級別,優(yōu)先權(quán)較低的線程必須等到優(yōu)先權(quán)較高的線程執(zhí)行完仃務(wù)后再執(zhí)行。在VC++6.0中的MFC應(yīng)用程序的線程是由CwinThread對象來表示,該線程分::用戶界面線程(GUI-Thread)和工作者線程(Worker-Thread)。用戶界面線程能夠提供界面和用戶交互,用于處理用戶輸入和響應(yīng)各種信息和事件;工作者線程沒有消息循環(huán),主要用來處理應(yīng)用程序的后臺任務(wù)。本文所采用的串口操作線程即為工作者線程。程序通過調(diào)用AfxBejinThread()函數(shù)自動創(chuàng)建一個CwinThread對象,通過響應(yīng)己設(shè)置好的一組事件句柄來啟動一個線程的執(zhí)行。

  3.1.1 輸出線程

  輸出線程比較簡單,它只為串口的寫操作創(chuàng)建一個OVERLAPPED結(jié)構(gòu),并設(shè)置一組事件的句柄。它可響應(yīng)的事件有刪除線程事件、寫請求事件及中斷請求事件,然后線程進(jìn)入主循環(huán),等待三個事件之一的發(fā)生,以便采取適當(dāng)?shù)男袆?。例如?dāng)檢測到寫請求事件時,表明輸出緩沖區(qū)內(nèi)有一些數(shù)據(jù)等待發(fā)送,輸出線程便會試圖發(fā)送傳送隊列中的所有數(shù)據(jù)。在寫操作進(jìn)行時,如果端口比較忙就會進(jìn)入重疊模式。此時WriteFile( )返回FALSE,用GetLastError( )可以發(fā)現(xiàn)當(dāng)前錯誤是ERROR_ IO_ PENDING,意味著重疊I/O操作已經(jīng)開始了。若是刪除線程消息到來,輸出線程將跳出循環(huán),關(guān)閉事件句柄,最后結(jié)束線程。

  3.1.2輸入線程

  輸入線程較為復(fù)雜一些,它既要處理串口數(shù)據(jù)的讀操作,又要處理串口狀態(tài)的讀取。而且由于輸入的數(shù)據(jù)是隨機(jī)到達(dá)的,所以輸入線程必須一直讀。輸入線程首先要創(chuàng)建兩個OVERLAPPED結(jié)構(gòu),用于讀數(shù)據(jù)和獲得通信事件,并為它們分別創(chuàng)建兩個事件。然后輸入線程要響應(yīng)四個需要監(jiān)視的事件:刪除線程事件、讀信息事件、狀態(tài)信息事件和讀請求事件設(shè)置事件句柄。接著輸入線程便進(jìn)入主循環(huán),直到刪除線程的消息到來才退出。只要輸入緩沖區(qū)有空間可用,輸入線程就會一直讀發(fā)送過來的數(shù)據(jù)。與輸出一樣,如果讀操作失敗了,而且返回的錯誤代碼是ERROR_ IO_ PENDING,意味著還在進(jìn)行讀的重疊操作。輸入線程在等待數(shù)據(jù)輸入的同時,也在等待傳入的事件。在輸入線程里可以用SetCommMask( )函數(shù)建立事件掩模來監(jiān)視特定通信資源上的事件。如圖:

圖3 輸入線程示意圖

  在應(yīng)用程序中,輸出線程只是簡單的一直調(diào)用WaitForMu1tip1e0bject()等待事件的發(fā)生,并以一個Switch Case語句為每個已發(fā)生事件提供處理方案。輸入線程的工作繁重許多,它分別調(diào)用ReadFile()和WaitCommEvent( )接收數(shù)據(jù)和通信狀態(tài)。如果接收到的是數(shù)據(jù),輸入線程將它保存到指定位置。如果是通信狀態(tài),輸入線程將它交給其它函數(shù)判斷狀態(tài)內(nèi)容,指引程序下一步的活動。ReadFile()和WaitCommEvent ()都是在重疊模式下工作,其步驟與輸出線程相同。

  3.1.3 線程同步
  
  在串口通信程序中,輸入緩沖區(qū)和輸出緩沖區(qū)能夠被多個線程訪問。它們用于在程序的主線程和輸入、輸出線程之間傳送數(shù)據(jù)塊。當(dāng)端口上出現(xiàn)一些操作時,主線程和輸入、輸出線程會經(jīng)常訪問這兩個對象。如果兩個線程同時處理緩沖區(qū),就會產(chǎn)生不正確的數(shù)據(jù),這就破壞了數(shù)據(jù)的完整性。C++提供了信號量( Semaphore)、互斥對象(Mutex)、臨界區(qū)(Critical Section)等手段來保護(hù)這些數(shù)據(jù)對象,防止兩個線程在同一時間訪問同一數(shù)據(jù)。保持在同一個進(jìn)程內(nèi)的線程工作協(xié)調(diào)一致(線程同步)。其中,臨界區(qū)是一種保證在一個時間只有一個線程訪問數(shù)據(jù)集的非常簡單的方法。當(dāng)你使用臨界區(qū),你就給了線程一個它們必須共享的對象。任何擁有臨界區(qū)對象的線程可以訪問被保護(hù)起來的數(shù)據(jù),其它線程必須等待直到第一個線程釋放了臨界區(qū)對象。此后其它線程可以按照順序搶占臨界區(qū)對象,訪問數(shù)據(jù)。因為線程只有擁有臨界區(qū)對象才能訪問數(shù)據(jù),而且在一個時刻只有一個線程可以擁有臨界區(qū)對象,所以決不會出現(xiàn)一個時刻有多個線程訪問數(shù)據(jù)的現(xiàn)象。

  考慮到本文所設(shè)計的通信緩沖區(qū)既不允許多個線程同時訪問,又不必供其它進(jìn)程的線程訪問。因此,臨界區(qū)是串口通信程序多線程同步最有效的辦法。 
 
  3.2 雙緩沖隊列的設(shè)計
  
  為了提高效率,本文把緩沖區(qū)數(shù)據(jù)存儲在標(biāo)準(zhǔn)C++庫中的deque<char>對象中,它作為一種優(yōu)化的存儲容器支持元素的添加和刪除。它能高效地插入未知數(shù)量的對象,并且插入和刪除元素時系統(tǒng)的負(fù)擔(dān)很小。根據(jù)需要,本文創(chuàng)建了兩個獨立的緩沖區(qū)對象,一個是發(fā)送緩沖區(qū)m_TxQueue,另一個是接收緩沖區(qū)m_RxQueue,并將它們置于臨界區(qū)的保護(hù)下,就能確保一次只有一個線程處理緩沖區(qū)。本文所設(shè)計的類MThreadDeque提供了對緩沖區(qū)的各種操作,如Extract(),Clear(),Insert()等,每種操作開始和結(jié)束的時候都要調(diào)用::EnterCriticalSection( &m_Lock )和::LeaveCriticalSection( &m_Lock ),關(guān)鍵代碼如下:

  class MThreadDeque
  
  {

  protected :
   
  const m_iMaxSize;
   
  deque<char> m_Queue;
   
  CRITICAL_SECTION m_Lock;

public :
   
  MThreadDeque( int max_size ) : m_iMaxSize( max_size )
   
  {
   
      ::InitializeCriticalSection( &m_Lock );
   
  }   
   
  ~ MThreadDeque ()
   
  {
   
      ::DeleteCriticalSection( &m_Lock );
   
  }      
   
  int Insert( char c )
   
  {
   
      int return_value;
   
      ::EnterCriticalSection( &m_Lock );
   
      if ( () < m_iMaxSize ) {
   
          _back( c );
   
          return_value = c & 0xff;
   
      } else
   
          return_value = -1;
   
      ::LeaveCriticalSection( &m_Lock );
   
      return return_value;
   
  }
   
     ……
  };
 
  3.3 網(wǎng)絡(luò)通信部分的設(shè)計

  當(dāng)工業(yè)現(xiàn)場環(huán)境惡劣,不適合人為操作時,將硬件采集的數(shù)據(jù)傳送到遠(yuǎn)程監(jiān)控中心進(jìn)行分析和處理是十分有必要的。Socket套接字是目前最流行的網(wǎng)絡(luò)通信應(yīng)用程序接口之一,利用它可以方便地實現(xiàn)局域網(wǎng)內(nèi)的數(shù)據(jù)的傳輸,是開發(fā)客戶機(jī)/服務(wù)器網(wǎng)絡(luò)應(yīng)用程序的重要方法。當(dāng)向一個套接字寫入時,所送數(shù)據(jù)會自動出現(xiàn)在套接宇的另一端,另一端可能是相同機(jī)器上運行的另一個進(jìn)程,也可能是世界上任何地方互連的一臺計算機(jī)。TCP/IP傳輸層有兩個并列的協(xié)議:T C P ( Transport Contro1 Protocol)和UDP(User Datagram Protocol)其中TCP是面向連接的,UDP是無連接的,Socket同時支持這兩種通信模式,所對應(yīng)的Socket分別為數(shù)據(jù)流Socket和數(shù)據(jù)報Socket。數(shù)抓流Socket定義了一種可靠的面向連接的服務(wù),實現(xiàn)無差錯、無重復(fù)的順序數(shù)據(jù)傳輸;數(shù)據(jù)報Socket定義了一個無連接的服務(wù),數(shù)據(jù)通過相互獨立的包進(jìn)行傳輸,包的傳輸是無序,并且不保證是否出錯、丟失和重復(fù)。本文采用了流式Socket來實現(xiàn)遠(yuǎn)程數(shù)據(jù)傳輸,工作過程如圖4所示。

 
圖4 Socket通信流程圖

  3.4 VC與Sql Sever數(shù)據(jù)庫的數(shù)據(jù)交換

  VC提供一些接口,可以處理數(shù)據(jù)庫操作,主要有:開放式數(shù)據(jù)庫連接(ODBC) ,OLE DB、ActiveXDataObject( ADO )等。ADO基于通用對象組件模型(COM),操作靈活,代碼添加少,本系統(tǒng)采用ADO操作Sql server2000數(shù)據(jù)庫,主要包括四個基本步驟:

 ?、貱OM庫的初始化,用#import指令引入ADO庫定義文件;

 ?、?創(chuàng)建Connection對象指針,并用其連接Sql server2000數(shù)據(jù)庫,本文通過DSN數(shù)據(jù)源對數(shù)據(jù)庫進(jìn)行連接,代碼如下:

  m_pConnection->Open("Datasource=adotest;UID=sa;PWD=;","","",adModeUnknown)。

 ?、劾媒⒑玫倪B接,通過Connection、Command對象執(zhí)行SQL命令,進(jìn)行創(chuàng)建表、添加記錄、添加字段等操作,或利用Recordset對象取得結(jié)果記錄集進(jìn)行查詢、處理;

 ?、苁褂猛戤吅箨P(guān)閉連接釋放對象。

  有了以上基礎(chǔ),就可以方便的把采集來的數(shù)據(jù)按照制定的順序存放在Sql Server數(shù)據(jù)中,可以完成對數(shù)據(jù)進(jìn)行快速查詢、瀏覽和刪除等工作。

  4.結(jié)論
  
  氣象數(shù)據(jù)能夠進(jìn)行可靠和實時的采集和通信是本系統(tǒng)實現(xiàn)的的關(guān)鍵所在。在系統(tǒng)的實現(xiàn)過程中,遇到許多技術(shù)問題,如通信的可靠性、多線程之間的互斥與同步、突發(fā)性數(shù)據(jù)處理與計算機(jī)響應(yīng)速度之間的協(xié)調(diào)和系統(tǒng)性能問題等,其中有些問題只能在現(xiàn)場調(diào)試的過程中發(fā)現(xiàn)并加以解決。本系統(tǒng)的實現(xiàn)為氣象監(jiān)控系統(tǒng)的更進(jìn)一步發(fā)展提供了參考,同時對于實現(xiàn)工業(yè)監(jiān)控系統(tǒng)的集成化、自動化具有極大的推進(jìn)作用。

  參考文獻(xiàn):

  [1]李現(xiàn)勇. Visual C++串口通信技術(shù)與工程實踐[M].北京:人民郵電出版社,2002

  [2]汪翔,袁輝.Visual C++實踐與提高一網(wǎng)絡(luò)編程篇[M].北京:中國鐵道出版社,2001:167-186

  [3] 徐軍譯.Visual C++開發(fā)人員指南[M],北京:機(jī)械工業(yè)出版社,1998

  [4] 潘愛民.VC++技術(shù)內(nèi)幕(第四版)[M].北京:清華人學(xué)出版社,1997.
   

 

 

(轉(zhuǎn)載)

標(biāo)簽:傳感器 網(wǎng)絡(luò)化系統(tǒng) 我要反饋 
泰科電子ECK、ECP系列高壓直流接觸器白皮書下載
優(yōu)傲機(jī)器人下載中心
億萬克
專題報道