VC++ 串列埠通訊(轉)
在VC++中有兩種方法可以進行串列埠通訊。一種是利用Microsoft公司提供的ActiveX控制元件 Microsoft Communications Control。另一種是直接用VC++訪問串列埠。下面將簡述這兩種方法。
一、Microsoft Communications Control
Microsoft公司在WINDOWS中提供了一個串列埠通訊控制元件,用它,我們可以很簡單的利用串列埠進行通訊。在使用它之前,應將控制元件加在應用程式的對話方塊上。然後再用ClassWizard 生成相應的物件。現在我們可以使用它了。
該控制元件有很多自己的屬性,你可以透過它的屬性視窗來設定,也可以用程式設定。我推薦用程式設定,這樣更靈活。
SetCommPort:指定使用的串列埠。
GetCommPort:得到當前使用的串列埠。
SetSettings:指定串列埠的引數。一般設為預設引數"9600,N,8,1"。這樣方便與其他串列埠進行通訊。
GetSettings:取得串列埠引數。
SetPortOpen:開啟或關閉串列埠,當一個程式開啟串列埠時,另外的程式將無法使用該串列埠。
GetPortOpen:取得串列埠狀態。
GetInBufferCount:輸入緩衝區中接受到的字元數。
SetInPutLen:一次讀取輸入緩衝區的字元數。設定為0時,程式將讀取緩衝區的全部字元。
GetInPut:讀取輸入緩衝區。
GetOutBufferCount:輸出緩衝區中待傳送的字元數。
SetOutPut:寫入輸出緩衝區。
一般而言,使用上述函式和屬性就可以進行串列埠通訊了。以下是一個範例。
#define MESSAGELENGTH 100 class CMyDialog : public CDialog { protected: VARIANT InBuffer; VARIANT OutBuffer; CMSComm m_Com; public: ...... } BOOL CMyDiaLog::OnInitDialog() { CDialog::OnInitDialog(); m_Com.SetCommPort(1); if (!m_Com.GetPortOpen()) { m_Com.SetSettings("57600,N,8,1"); m_Com.SetPortOpen(true); m_Com.SetInBufferCount(0); SetTimer(1,10,NULL); InBuffer.bstrVal=new unsigned short[MESSAGELENGTH]; OutBuffer.bstrVal=new unsigned short[MESSAGELENGTH]; OutBuffer.vt=VT_BSTR; } return true; } void CMyDiaLog::OnTimer(UINT nIDEvent) { if (m_Com.GetInBufferCount()>=MESSAGELENGTH) { InBuffer=m_Com.GetInput(); // handle the InBuffer. // Fill the OutBuffer. m_Com.SetOutput(OutBuffer); } CDialog::OnTimer(nIDEvent); } |
用該控制元件傳輸的資料是UNICODE格式。關於UNICODE和ANSI的關係和轉換請參看MSDN。
關於該控制元件的其他詳細資料請檢視MSDN關於COMM CONTROL部分。
二、直接用VC++訪問串列埠。
在VC++中,串列埠和磁碟檔案可以統一的方式來簡單讀寫。這兩者幾乎沒有什麼不同,只是在WINDOWS 9X下磁碟檔案只能做同步訪問,而串列埠只能做非同步訪問。
CreateFile:用指定的方式開啟指定的串列埠。通常的方式為
m_hCom = CreateFile( "COM1", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL );
m_hCom為檔案控制程式碼。GENERIC_READ | GENERIC_WRITE指定可以對串列埠進行讀寫操作。第三個引數0表示串列埠為獨佔開啟。OPEN_EXISTING表示當指定串列埠不存在時,程式將返回失敗。 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED則表示檔案屬性。當開啟串列埠時,必須指定 FILE_FLAG_OVERLAPPED,它表示檔案或裝置不會維護訪問指標,則在讀寫時,必須使用OVERLAPPED 結構指定訪問的檔案偏移量。
ReadFile:讀取串列埠資料。
WriteFile:向串列埠寫資料。
CloseHandle:關閉串列埠。
COMMTIMEOUTS:COMMTIMEOUTS主要用於串列埠超時引數設定。COMMTIMEOUTS結構如下:
typedef struct _COMMTIMEOUTS { DWORD ReadIntervalTimeout; DWORD ReadTotalTimeoutMultiplier; DWORD ReadTotalTimeoutConstant; DWORD WriteTotalTimeoutMultiplier; DWORD WriteTotalTimeoutConstant; } COMMTIMEOUTS,*LPCOMMTIMEOUTS; |
ReadIntervalTimeout:兩字元之間最大的延時,當讀取串列埠資料時,一旦兩個字元傳輸的時間差超過該時間,讀取函式將返回現有的資料。設定為0表示該引數不起作用。
ReadTotalTimeoutMultiplier:讀取每字元間的超時。
ReadTotalTimeoutConstant:一次讀取串列埠資料的固定超時。所以在一次讀取串列埠的操作中,其超時為ReadTotalTimeoutMultiplier乘以讀取的位元組數再加上 ReadTotalTimeoutConstant。將ReadIntervalTimeout設定為MAXDWORD,並將ReadTotalTimeoutMultiplier 和ReadTotalTimeoutConstant設定為0,表示讀取操作將立即返回存放在輸入緩衝區的字元。
WriteTotalTimeoutMultiplier:寫入每字元間的超時。
WriteTotalTimeoutConstant:一次寫入串列埠資料的固定超時。所以在一次寫入串列埠的操作中,其超時為WriteTotalTimeoutMultiplier乘以寫入的位元組數再加上 WriteTotalTimeoutConstant。
SetCommTimeouts函式可以設定某裝置控制程式碼的超時引數,要得到某裝置控制程式碼的超時引數可以用GetCommTimeouts函式。
DCB:DCB結構主要用於串列埠引數設定。該結構太龐大,這裡就不一一講述了,有興趣者可檢視MSDN關於DCB的描述。其中下面兩個是比較重要的屬性。
BaudRate:串列埠的通訊速度。一般設定為9600。
ByteSize:位元組位數。一般設定為8。
DCB結構可以用SetCommState函式來設定,並可以用GetCommState來得到現有串列埠的屬性。
SetupComm:設定串列埠輸入、輸出緩衝區。
OVERLAPPED:儲存串列埠非同步通訊的資訊。具體結構如下:
typedef struct _OVERLAPPED { DWORD Internal; DWORD InternalHigh; DWORD Offset; DWORD OffsetHigh; HANDLE hEvent; } OVERLAPPED; |
Internal,InternalHigh是保留給系統使用的,使用者不需要設定。
Offset,OffsetHigh是讀寫串列埠的偏移量,一般設定OffsetHigh為NULL,可以支援2GB資料。
hEvent讀寫事件,因為串列埠是非同步通訊,操作可能被其他程式堵塞,程式可以透過檢查該時間來得知是否讀寫完畢。事件將在讀寫完成後,自動設定為有效。
透過以上這些函式和結構,我們就可以透過串列埠進行通訊了,現在我們具體看下面的例項:
BOOL CSerial::Open( int nPort, int nBaud ) { if( m_bOpened ) return( TRUE ); char szPort[15]; DCB dcb; wsprintf( szPort, "COM%d", nPort ); m_hComDev = CreateFile( szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL ); if( m_hComDev == NULL ) return( FALSE ); memset( &m_OverlappedRead, 0, sizeof( OVERLAPPED ) ); memset( &m_OverlappedWrite, 0, sizeof( OVERLAPPED ) ); COMMTIMEOUTS CommTimeOuts; CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF; CommTimeOuts.ReadTotalTimeoutMultiplier = 0; CommTimeOuts.ReadTotalTimeoutConstant = 0; CommTimeOuts.WriteTotalTimeoutMultiplier = 0; CommTimeOuts.WriteTotalTimeoutConstant = 5000; SetCommTimeouts( m_hComDev, &CommTimeOuts ); m_OverlappedRead.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); m_OverlappedWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); dcb.DCBlength = sizeof( DCB ); GetCommState( m_hComDev, &dcb ); dcb.BaudRate = nBaud; dcb.ByteSize = 8; if( !SetCommState( m_hComDev, &dcb ) || !SetupComm( m_hComDev, 10000, 10000 ) || m_OverlappedRead.hEvent == NULL || m_OverlappedWrite.hEvent == NULL ){ DWORD dwError = GetLastError(); if( m_OverlappedRead.hEvent != NULL ) CloseHandle( m_OverlappedRead.hEvent ); if( m_OverlappedWrite.hEvent != NULL ) CloseHandle( m_OverlappedWrite.hEvent ); CloseHandle( m_hComDev ); return FALSE; } m_bOpened = TRUE; return m_bOpened; } int CSerial::InBufferCount( void ) { if( !m_bOpened || m_hComDev == NULL ) return( 0 ); DWORD dwErrorFlags; COMSTAT ComStat; ClearCommError( m_hIDComDev, &dwErrorFlags, &ComStat ); return (int)ComStat.cbInQue; } DWORD CSerial::ReadData( void *buffer, DWORD dwBytesRead) { if( !m_bOpened || m_hComDev == NULL ) return 0; BOOL bReadStatus; DWORD dwErrorFlags; COMSTAT ComStat; ClearCommError( m_hComDev, &dwErrorFlags, &ComStat ); if( !ComStat.cbInQue ) return 0; dwBytesRead = min(dwBytesRead,(DWORD) ComStat.cbInQue); bReadStatus = ReadFile( m_hComDev, buffer, dwBytesRead, &dwBytesRead, &m_OverlappedRead ); if( !bReadStatus ){ if( GetLastError() == ERROR_IO_PENDING ){ WaitForSingleObject( m_OverlappedRead.hEvent, 2000 ); return dwBytesRead; } return 0; } return dwBytesRead; } DWORD CSerial::SendData( const char *buffer, DWORD dwBytesWritten) { if( !m_bOpened || m_hComDev == NULL ) return( 0 ); BOOL bWriteStat; bWriteStat = WriteFile( m_hComDev, buffer, dwBytesWritten, &dwBytesWritten, &m_OverlappedWrite ); if( !bWriteStat){ if ( GetLastError() == ERROR_IO_PENDING ) { WaitForSingleObject( m_OverlappedWrite.hEvent, 1000 ); return dwBytesWritten; } return 0; } return dwBytesWritten; } |
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10172717/viewspace-926891/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- VC++ 的串列埠通訊 (轉)C++串列埠
- 串列埠通訊 (轉)串列埠
- VC++串列埠通訊程式設計詳解C++串列埠程式設計
- 串列埠通訊串列埠
- 用VB除錯串列埠通訊 (轉)除錯串列埠
- linux 串列埠通訊Linux串列埠
- 串列埠通訊協議串列埠協議
- Android 串列埠通訊Android串列埠
- C# 串列埠通訊C#串列埠
- 11. 串列埠通訊串列埠
- 串列埠通訊型別串列埠型別
- (10)uart串列埠通訊串列埠
- VC++串列埠程式設計之簡訊應用開發(轉)C++串列埠程式設計
- 通過串列埠進行通訊 :串列埠
- 串列埠資料抓取及串列埠通訊模擬串列埠
- 安卓串列埠通訊疑問安卓串列埠
- java串列埠通訊例項 -Java串列埠
- 串列埠無法正常通訊串列埠
- Android USB 轉串列埠通訊開發基本流程Android串列埠
- 串列埠通訊應用程式的解決方案 (轉)串列埠
- Linux下串列埠通訊詳解(下)讀寫串列埠及關閉串列埠Linux串列埠
- AndroidSerialPort:安卓串列埠通訊庫Android安卓串列埠
- 串列埠通訊gui介面顯示串列埠GUI
- ROS環境下串列埠通訊ROS串列埠
- Android藍芽串列埠通訊Android藍芽串列埠
- 小型plc串列埠通訊簡介串列埠
- STM32串列埠通訊串列埠
- C#串列埠通訊遇到的坑C#串列埠
- android ndk 虛擬串列埠通訊Android串列埠
- C#串列埠通訊程式SerialPort類C#串列埠
- .NET Compact Framework下的串列埠通訊Framework串列埠
- STMF4串列埠通訊使用串列埠
- 串列埠通訊與其他通訊方式相比有什麼優勢?串列埠
- 序列通訊的基本原理及用MFC實現串列埠通訊程式設計 (轉)串列埠程式設計
- Arduino下的STM32的串列埠通訊UI串列埠
- ros中使用serial包實現串列埠通訊ROS串列埠
- 在VB中利用API進行串列埠通訊API串列埠
- 打工筆記--------------------------c#實現串列埠通訊筆記C#串列埠