1. 程式人生 > >Vc 三種串列埠通訊方式

Vc 三種串列埠通訊方式

本文介紹了在Windows平臺下序列通訊的實現機制,討論了根據不同的條件用Visual C++ 設計序列通訊程式的三種方法,並結合實際,實現對溫度資料的接收監控。

在實驗室和工業應用中,串列埠是常用的計算機與外部序列裝置之間的資料傳輸通道,由於序列通訊方便易行,所以應用廣泛。依據不同的條件實現對串列埠的靈活程式設計控制是我們所需要的。

在光學鏡片鍍膜工藝中,用微控制器進行多路溫度資料採集控制,採集結果以序列方式進入主機,每隔10S向主機發送一次取樣資料,主機向單片機發送相關的控制命令,實現序列資料接收,處理,記錄,顯示,實時繪製曲線。序列通訊程式開發環境為 VC++ 6.0。

與以往DOS下序列通訊程式不同的是,Windows不提倡應用程式直接控制硬體,而是通過Windows

作業系統提供的裝置驅動程式來進行資料傳遞。序列口在Win 32中是作為檔案來進行處理的,而不是直接對埠進行操作,對於序列通訊,Win 32 提供了相應的檔案I/O函式與通訊函式,通過了解這些函式的使用,可以編制出符合不同需要的通訊程式。與通訊裝置相關的結構有COMMCONFIG ,COMMPROP,COMMTIMEOUTS,COMSTAT,DCB,MODEMDEVCAPS,MODEMSETTINGS共7個,與通訊有關的Windows API函式共有26個,詳細說明可參考MSDN幫助檔案。以下將結合例項,給出實現序列通訊的三種方法。

:使用VC++提供的序列通訊控制元件MSComm 首先,在對話方塊中建立通訊控制元件,若Control工具欄中缺少該控制元件,可通過選單Project --> Add to Project --> Components and Control插入即可,再將該控制元件從工具箱中拉到對話方塊中。此時,你只需要關心控制元件提供的對 Windows 通訊驅動程式的 API 函式的介面。換句話說,只需要設定和監視MSComm控制元件的屬性和事件。

在ClassWizard中為新建立的通訊控制元件定義成員物件(CMSComm m_Serial),通過該物件便可以對串列埠屬性進行設定,MSComm 控制元件共有27個屬性,這裡只介紹其中幾個常用屬性:

CommPort 設定並返回通訊埠號,預設為COM1。

Settings 以字串的形式設定並返回波特率、奇偶校驗、資料位、停止位。

PortOpen 設定並返回通訊埠的狀態,也可以開啟和關閉埠。

Input 從接收緩衝區返回和刪除字元。

Output 向傳送緩衝區寫一個字串。

InputLen 設定每次Input讀入的字元個數,預設值為0,表明讀取接收緩衝 區中的全部內容。

InBufferCount 返回接收緩衝區中已接收到的字元數,將其置0可以清除接收緩 衝區。

InputMode 定義Input屬性獲取資料的方式(為0:文字方式;為1:二進位制方式)。

RThreshold 和 SThreshold 屬性,表示在 OnComm 事件發生之前,接收緩衝區或傳送緩衝區中可以接收的字元數。

以下是通過設定控制元件屬性對串列埠進行初始化的例項:

  1. BOOL     CSampleDlg:: PortOpen()  
  2. {  
  3.     BOOL   m_Opened;   
  4.     ......   
  5.     m_Serial.SetCommPort(2);            //   指定串列埠號 
  6.     m_Serial.SetSettings("4800,N,8,1"); //   通訊引數設定 
  7.     m_Serial.SetInBufferSize(1024);     //   指定接收緩衝區大小 
  8.     m_Serial.SetInBufferCount(0);       //   清空接收緩衝區 
  9.     m_Serial.InputMode(1);              //   設定資料獲取方式 
  10.     m_Serial.SetInputLen(0);            //   設定讀取方式 
  11.     m_Opened=m_Serail.SetPortOpen(1);   //   開啟指定的串列埠       
  12.     return   m_Opened;     
  13. }  

開啟所需串列埠後,需要考慮串列埠通訊的時機。在接收或傳送資料過程中,可能需要監視並響應一些事件和錯誤,所以事件驅動是處理串列埠互動作用的一種非常有效的方法。使用 OnComm 事件和 CommEvent 屬性捕捉並檢查通訊事件和錯誤的值。發生通訊事件或錯誤時,將觸發 OnComm 事件,CommEvent 屬性的值將被改變,應用程式檢查 CommEvent 屬性值並作出相應的反應。在程式中用ClassWizard為CMSComm控制元件新增OnComm訊息處理函式:

  1. void   CSampleDlg::OnComm()  
  2. {     
  3.     ......     
  4.     switch(m_Serial.GetCommEvent())     
  5.     {  
  6.      case   2:       //   序列口資料接收,處理;   
  7.     }  
  8. }  

在單執行緒中實現自定義的串列埠通訊類

控制元件簡單易用,但由於必須拿到對話方塊中使用,在一些需要線上程中實現通訊的應用場合,控制元件的使用顯得捉襟見肘。此時,若能夠按不同需要定製靈活的串列埠通訊類將彌補控制元件的不足,以下將介紹如何在單執行緒中建立自定義的通訊類。

該通訊類CSimpleComm需手動加入標頭檔案與原始檔,其基類為CObject,大致建立步驟如下:

(1) 開啟串列埠,獲取串列埠資源控制代碼

通訊程式從CreateFile處指定串列埠裝置及相關的操作屬性。再返回一個控制代碼,該控制代碼將被用於後續的通訊操作,並貫穿整個通訊過程。CreateFile()函式中有幾個值得注意的引數設定:串列埠共享方式應設為0,串列埠為不可共享裝置;建立方式必須為OPEN_EXISTING,即開啟已有的串列埠。對於dwFlagAndAttribute引數,對串列埠有意義的值是FILE_FLAG_OVERLAPPED,該標誌表明串列埠採用非同步通訊模式,可進行重疊操作;若值為NULL,則為同步通訊方式,在同步方式下,應用程式將始終控制程式流,直到程式結束,若遭遇通訊故障等因素,將導致應用程式的永久等待,所以一般多采用非同步通訊。

(2)串列埠設定

串列埠開啟後,其屬性被設定為預設值,根據具體需要,通過呼叫GetCommState(hComm,&dcb)讀取當前串列埠裝置控制塊DCB(Device Control Block)設定,修改後通過SetCommState(hComm,&dcb)將其寫入。再需注意非同步讀寫的超時控制設定, 通過COMMTIMEOUTS結構設定超時,呼叫SetCommTimeouts(hComm,&timeouts)將結果寫入。以下是溫度監控程式中串列埠初始化成員函式:

  1. BOOL   CSimpleComm::Open()  
  2. {     
  3.     DCB dcb;  
  4.     m_hIDComDev=CreateFile( "COM2", GENERIC_READ | GENERIC_WRITE,  
  5.         0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVE     RLAPPED, NULL );         //   開啟串列埠,非同步操作
  6.     if( m_hIDComDev == NULL )   
  7.         return( FALSE );  
  8.     dcb.DCBlength = sizeof( DCB );  
  9.     GetCommState( m_hIDComDev, &dcb );   //   獲得埠預設設定
  10.     dcb.BaudRate=CBR_4800;  
  11.     dcb.ByteSize=8;  
  12.     dcb.Parity= NOPARITY;  
  13.     dcb.StopBits=(BYTE) ONESTOPBIT;  
  14.     ......   
  15. }  

(3)串列埠讀寫操作

主要運用ReadFile()與WriteFile()API函式,若為非同步通訊方式,兩函式中最後一個引數為指向OVERLAPPED結構的非空指標,在讀寫函式返回值為FALSE的情況下,呼叫GetLastError()函式,返回值為ERROR_IO_PENDING,表明I/O操作懸掛,即操作轉入後臺繼續執行。此時,可以用WaitForSingleObject()來等待結束訊號並設定最長等待時間,舉例如下:

  1. BOOL   bReadStatus;  
  2. bReadStatus = ReadFile( m_hIDComDev, buffer,   dwBytesRead, &dwBytesRead,     &m_OverlappedRead );       
  3. if(!bReadStatus)     
  4. {       
  5.     if(GetLastError()==ERROR_IO_PENDING)  
  6.     {         
  7.         WaitForSingleObject(m_OverlappedRead.hEvent,1000);     
  8.         return ((int)dwBytesRead);     
  9.     }     
  10.     return(0);     
  11. }     
  12. return ((int)dwBytesRead);  

定義全域性變數m_Serial作為新建通訊類CSimpleComm的物件,通過呼叫類的成員函式即可實現所需序列通訊功能。與方法一相比,方法二賦予序列通訊程式設計較大的靈活性,埠的讀寫可選擇較簡單的查詢式,或通過設定與外設資料傳送時間間隔TimeCycle相同的定時器:SetTimer(1,TimeCycle,NULL),進行定時讀取或傳送。

  1. CSampleView:: OnTimer(UINT nIDEvent)       
  2. {         
  3.     char   InputData[30];         
  4.     m_Serial.ReadData(InputData,30);         
  5.     // 資料處理     
  6. }  

若對埠資料的響應時間要求較嚴格,可採用事件驅動I/O讀寫,Windows定義了9種串列埠通訊事件,較常用的有:

EV_RXCHAR: 接收到一個位元組,並放入輸入緩衝區。

EV_TXEMPTY: 輸出緩衝區中的最後一個字元傳送出去。

EV_RXFLAG: 接收到事件字元(DCB結構中EvtChar成員),放入輸入緩衝區。

在用SetCommMask()指定了有用的事件後,應用程式可呼叫WaitCommEvent()來等待事件的發生。SetCommMask(hComm,0)可使WaitCommEvent()中止。

多執行緒下實現序列通訊

方法一,二適用於單執行緒通訊。在很多工業控制系統中,常通過擴充套件串列埠連線多個外設,各外設傳送資料的重複頻率不同,要求後臺實時無差錯捕捉,採集,處理,記錄各埠資料,這就需要在自定義的序列通訊類中建立埠監視執行緒,以便在指定的事件發生時向相關的視窗傳送通知訊息。

執行緒的基本概念可詳見VC++參考書目,Windows內部的搶先排程程式在活動的執行緒之間分配CPU時間,Win 32 區分兩種不同型別的執行緒,一種是使用者介面執行緒UI(User Interface Thread),它包含訊息迴圈或訊息泵,用於處理接收到的訊息;另一種是工作執行緒(Work Thread),它沒有訊息迴圈,用於執行後臺任務。用於監視串列埠事件的執行緒即為工作執行緒。

多執行緒通訊類的編寫在埠的配置,連線部分與單執行緒通訊類相同,在埠配置完畢後,最重要的是根據實際情況,建立多執行緒之間的同步物件,如訊號燈,臨界區,事件等,相關細節可參考VC++ 中的同步類。

一切就緒後即可啟動工作執行緒:

  1. CWinThrea *CommThread = AfxBeginThread(CommWatchThread,   // 執行緒函式名 
  2. (LPVOID) m_pTTYInfo,            // 傳遞的引數 
  3. THREAD_PRIORITY_ABOVE_NORMAL,   // 設定執行緒優先順序   
  4. (UINT) 0,                       //   最大堆疊大小   
  5. (DWORD) CREATE_SUSPENDED ,      //   建立標誌 
  6. (LPSECURITY_ATTRIBUTES) NULL    //   安全性標誌
  7. );           

同時,在串列埠事件監視執行緒中:

  1. if(WaitCommEvent(pTTYInfo->idComDev,&dwEvtMask,NULL))     
  2. {   
  3.     if((dwEvtMask   & pTTYInfo->dwEvtMask )== pTTYInfo->dwEvtMask)   
  4.     {     
  5.         WaitForSingleObject(pTTYInfo->hPostEvent,0xFFFFFFFF);         
  6.         ResetEvent(pTTYInfo->hPostEvent);     // 置同步事件物件為非訊號態     
  7.         ::PostMessage(CSampleView,ID_COM1_DATA,0,0);   // 傳送通知訊息   
  8.     }     
  9. }  

用PostMessage()向指定視窗的訊息佇列傳送通知訊息,相應地,需要在該視窗建立訊息與成員函式間的對映,用ON_MESSAGE將訊息與成員函式名關聯。

BEGIN_MESSAGE_MAP(CSampleView, CView) // {{AFX_MSG_MAP(CSampleView)ON_MESSAGE(ID_COM1_DATA, OnProcessCom1Data)   ON_MESSAGE(ID_COM2_DATA, OnProcessCom2Data)   .....//}}AFX_MSG_MAPEND_MESSAGE_MAP()

然後在各成員函式中完成對各串列埠資料的接收處理,但必須保證在下一次監測到有資料到來之前,能夠完成所有的中間處理工作。否則將造成資料的捕捉錯誤。

多執行緒的實現可以使得各埠獨立,準確地實現序列通訊,使串列埠通訊具有更廣泛的靈活性與嚴格性,且充分利用了CPU時間。但在具體的實時監控系統中如何協調多個執行緒,執行緒之間以何種方式實現同步也是在多執行緒序列通訊程式實現的難點。

以VC++ 6.0 為工具,實現序列通訊的三種方法各有利弊,

根據不同需要,選擇合適的方法,將達到事半功倍的效果。在溫度監控系統中,筆者採用了方法二,在Window 98 ,Windows 95 上執行穩定,取得了良好的效果

相關推薦

Vc 串列通訊方式

本文介紹了在Windows平臺下序列通訊的實現機制,討論了根據不同的條件用Visual C++ 設計序列通訊程式的三種方法,並結合實際,實現對溫度資料的接收監控。 在實驗室和工業應用中,串列埠是常用的計算機與外部序列裝置之間的資料傳輸通道,由於序列通訊方便易行,所以應用

VC中實現串列通訊的摸索過程

串列埠通訊對於需要進行嵌入式開發的小夥伴們來說是必不可少的,甚至說是無法迴避的。而VC卻又不像C#或者QT那樣人性化,沒有自帶串列埠類(貌似VC6時代還有一個串列埠控制元件可以下載然後通過安裝到VC6中),所以我們不得不到處尋找開源的串列埠通訊程式碼。 這裡我找到的是CSerialPor

VC++USB及串列通訊程式(附工程)

 ResetEvent(USBReadOverlapped.hEvent);  bResult = ReadFile(HidHandle, USBRxBuff, dwBytesRead, &dwBytesRead, &USBReadOverlapped);  if (!bResult)  {

51 微控制器UART 串列通訊[ 方式1 ]實現

1  51序列口結構 51微控制器的UART序列通訊是基於其序列口的可程式設計硬體結構,只要用正確的程式程式碼通過初始化序列口對應暫存器的形式將其序列硬體結構初始化,再編寫符合此序列口通訊的程式程式碼

關於串列通訊查詢與中斷兩方式

void init_ser()   //串列埠初始化 {   TMOD=0x20;     //定時器1工作於方式2  TH1=0xf3;     //娤初值波特率為2400  TL1=0xf3;  TR1=1;      //開定時器1  SCON=0x50;     //設定串列埠方式1 允許接收

【C語言實現串列通訊知識點整理()】串列開啟、設定資料成功後進行資料讀寫

int OpenDev(char *Dev) { int fd = open(Dev,O_RDWR | O_NOCTTY | O_NONBLOCK); if(-1 == fd) { perror("Can't Open Serial Port"); return -1;

UART串列通訊淺談之()--字元與資料的轉換

版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/solar_Lan/article/details/78093692 學串列埠通訊的應用主要是實現微控制器和電腦之間的資訊互發,可以用電腦控制微控制器的一些資訊,可以把微控制器的一些資訊狀況發給電腦

經典vc串列通訊

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49

MFC串列通訊)——換電腦執行出現“Debug Assertion Failed“”

用MSComm控制元件寫好的程式,換電腦執行遇到Debug Assertion Failed“,如下圖 由於該電腦上沒有安裝mscomm.ocx 元件所造成,安裝方法如下: (1)下載控制元件,下載連結連結:https://download.csdn.net/download/kang

VS2013 Windows API 串列通訊程式設計--多執行緒非同步方式

轉載自:blog.csdn.net/mingojiang 1.串列埠通訊基礎 提到串列埠讓人想起並口,它們是計算機中兩個比較重要的通訊方式. 串列埠:也叫COM口,把位元組的二進位制位按位列隊進行傳輸,每個位元組佔一個固定的時間長,速度慢,但是傳輸距離遠, 有9針和25針

串列通訊校驗方式(even,odd,space,mark)

奇校驗 (odd parity):如果字元資料位中"1"的數目是偶數,校驗位為"1",如果"1"的數目是奇數,校驗位應為"0"。(校驗位調整個數) 偶校驗 (even parity):如果字元資料位中"1"的數目是偶數,則校驗位應為"0",如果是奇數則為"1"。(校驗位調整個數) mark parit

OHSCE入門教程()-PHP串列通訊、構建高可靠性的匯流排應用。

(寫於OHSCE_V0.1.25)    終於等到這篇文章了吧,其實之所以先寫了TCP/UDP的是因為在現在的環境下它倆是相輔相成的,其實在控制領域我們所說的TCP/UDP和串列埠匯流排應用非常接近,和普通的網際網路網路應用還是有著很大區別的,畢竟絕大部分網路控制產品都是從匯流排控制產品升級而來或沿襲了可靠

使用51微控制器採用中斷方式進行串列通訊的學習記錄:

使用51微控制器進行串列埠通訊的學習記錄之中斷方式: 1.51微控制器採用中斷方式的串列埠通訊過程及程式分析: 所謂中斷方式,就是串列埠收/發標志位出發中斷後,在中斷中執行既定操作,可通過函式呼叫來實現。 接收資料時 等待中斷->然後在中斷中接收資料 傳送資料時 傳

Unity之串列通訊(基於姿態感測器)

/*******************************/ using UnityEngine; using System.Collections; //Other libraries using System; using System.Threading; using System.Collect

智慧小車製作過程全紀錄: 、軟體平臺--- Java 平臺串列通訊

嵌入式Linux上大部分都是有C/C++來做開發的,主要的原因還是為了效率,但本人最近幾年用Java比較多所以決定用Java比較多所以決定還是用Java來開發,再者個人認為現在硬體的發展,對於實時性沒有苛刻要求的環境Java足可以勝任了,所以言歸正傳,下面開始實

VC++串列通訊程式設計詳解

總結來看串列埠通訊原理,(也可以說大多數通訊原理也是如此)。 通訊首先要有個通訊,可以簡單的把通訊看成一個小桶,傳送方住水桶裡裝水,接收方從水桶中取水。如果你要和對方通訊首先需要將桶蓋開啟,再將水

串列通訊基礎知識及VC++實現

串列埠是計算機上一種非常通用裝置通訊的協議。大多數計算機包含兩個基於RS232的串列埠。串列埠通訊的概念非常簡單,串列埠按位(bit)傳送和接收位元組。儘管比按位元組(byte)的並行通訊慢,但是由於串列埠通訊是非同步的,串列埠可以在使用一根線傳送資料的同時用另一根線接收資

基於STM32之UART串列通訊協議()接收

一、前言 1、簡介   回顧上一篇UART傳送當中,已經講解了如何實現UART的傳送操作了,接下來這一篇將會繼續講解如何實現UART的接收操作。 2、UART簡介   嵌入式開發中,UART串列埠通訊協議是我們常用的通訊協議之一,全稱叫做通用非同步收發傳輸器(Universal Asynchronou

android加載圖片方式

factor trac turn post static col ati 三種 sam package smalt.music.utils; import android.graphics.Bitmap; import android.graphics.Bitm

SSO單點登錄情況的實現方式詳解

否則 post請求 登錄用戶 搭建集群 本地 sub 簡單的 div nmp 單點登錄(SSO——Single Sign On)對於我們來說已經不陌生了。對於大型系統來說使用單點登錄可以減少用戶很多的麻煩。就拿百度來說吧,百度下面有很多的子系統——百度經驗、百度知道、百度文