串列埠使用和CSerial類

NO IMAGE
1 Star2 Stars3 Stars4 Stars5 Stars 給文章打分!
Loading...

1 串列埠通訊的基本原理

串列埠通訊中無論是寫入串列埠還是讀取串列埠,都是對緩衝區操作的。可以理解為寫串列埠就是向輸出緩衝區寫入內容,讀取串列埠就是從輸入串列埠緩衝區讀取內容。但是何時開啟串列埠,何時傳送資料,何時接受資料都是未知的。所以在串列埠通訊時一般是一個主動一個被動。通訊雙方有一定的協議,就是事先協商好的資料格式。接收方接收到資料後,返回一個應答標誌,告訴傳送方已經接收到資料了。如果接收錯誤則返回接收錯誤標誌,或者一直等待接收到正確的資料再返回。至於接收方怎麼才知道有資料傳送過來了,對於微控制器之類的可以使用串列埠中斷或者巡檢的方式。對於工控機之類只能使用巡檢的方式了。前段時間做一個檢測系統,用到串列埠通訊,順手就寫了一個類,這裡分享出來。

2 串列埠通訊的基本操作步驟

無論哪種操作方式,串列埠通訊一般都通過四個步驟來完成:
1、開啟串列埠;
2、配置串列埠;
3、讀寫串列埠;
4、關閉串列埠;

2.1 開啟串列埠

在Windows中使用串列埠通訊一般有兩種方式,一種是使用Windows中的API,另一種方式使用MFC中的控制元件。這裡採用API的方式。

HANDLE CreateFile(
LPCTSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDistribution,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile);

lpFileName,要開啟的串列埠號,如“COM1”;

dwDesiredAccess,串列埠訪問的型別,可以是隻讀、只寫、可讀可寫。其取值可以是GENERIC_READ、GENERIC_WRITE或者他們的組合;

dwShareMode,共享屬性,由於串列埠不能共享,該引數必須置為0;

lpSecurityAttributes,引用的安全型別,一般設定為NULL;

dwCreationDistribution,建立檔案的標誌,對於串列埠操作該引數必須置為OPEN_EXISTING;

dwFlagsAndAttributes,串列埠通訊是同步還是非同步,0表示同步。FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED表示非同步;

hTemplateFile:對串列埠而言該引數必須置為NULL。

非同步方式開啟串列埠示例程式碼:

CreateFile(
m_strCom,
GENERIC_READ|GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
NULL);
2.2 配置串列埠

串列埠開啟需要配置一些引數,如DCB結構、輸入輸出緩衝區大小、設定超時結構。
配置DCB結構,該結構中可以配置波特率、資料位、奇偶校驗和停止位之類的資訊;
設定該結構的時候需要用到幾個函式:

BOOL GetCommState(HANDLE hFile, LPDCB lpDCB);
BOOL SetCommState(HANDLE hFile, LPDCB lpDCB);

示例程式碼如下:

DCB dcb;
GetCommState(m_hCom, &dcb);
dcb.BaudRate = m_dwBaudRate;
dcb.ByteSize = m_byteSize;
dcb.Parity = m_byteCheck;
dcb.StopBits = m_byteStop;
SetCommState(m_hCom, &dcb);

設定串列埠緩衝區大小:

BOOL SetupComm( HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue);

示例程式碼如下:

DWORD dwInQueue = 1024;
DEWORD dwOutQueue = 1024;
SetupComm(hCom, dwInQueue, dwOutQueue);

設定超時:

BOOL SetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts);

該函式第一個引數不用多說,第二個引數是個結構體。

typedef struct _COMMTIMEOUTS {
DWORD ReadIntervalTimeout;
DWORD ReadTotalTimeoutMultiplier;
DWORD ReadTotalTimeoutConstant;
DWORD WriteTotalTimeoutMultiplier;
DWORD WriteTotalTimeoutConstant;
} COMMTIMEOUTS,*LPCOMMTIMEOUTS;

ReadIntervalTimeout,讀取操作過程中兩個字元之間的延時,當讀取串列埠的時候如果兩個字元傳輸的時間差如果超過這個時間的話,讀取串列埠函式就會返回;

ReadTotalTimeoutMultiplier,讀取操作計算總超時時每個字元讀取的時間,其實就是估算的每個字元傳輸需要的時間;

ReadTotalTimeoutConstant,一次串列埠讀取超時時間的固定值,其實就是擔心估計的兩個字元之間傳輸時間不準確,然後又加上的一個超時時間;

讀取總超時時間的計算方法如下:

讀取操作總超時 = ReadTotalTimeoutMultiplier*讀取字元數 ReadTotalTimeoutConstant;

讀取串列埠的時候有兩種超時,一種是兩個傳輸字元之間的時間間隔;如果讀取兩個字元之間的時間超過ReadIntervalTimeout的話,讀取串列埠的操作就會返回。另一種是讀取總時間超時,如果讀取操作時間超過剛計算的總超時的話,讀取操作也會返回;這裡說的返回與串列埠的同步操作和非同步操作中說的返回不同。同步和非同步那種返回是指函式的返回,這裡的返回是指串列埠讀取操作的返回;

WriteTotalTimeoutMultiplier,同讀操作相關的引數;

WriteTotalTimeoutConstant,同讀操作相關引數;

寫操作總超時時間計算方法如下:

寫操作總超時 = WriteTotalTimeoutMultiplier*寫入字元數 WriteTotalTimeoutConstant;

寫入操作只有一種超時,只有總超時;
一般做以下設定:

TimeOuts.ReadIntervalTimeout = MAXDWORD;     // 把間隔超時設為最大,
//把總超時設為0將導致ReadFile立即返回並完成操作
TimeOuts.ReadTotalTimeoutMultiplier = 0;     //讀時間係數
TimeOuts.ReadTotalTimeoutConstant = 0;       //讀時間常量
TimeOuts.WriteTotalTimeoutMultiplier = 50;   //總超時=時間係數*要求讀/寫的字元數 時間常量
TimeOuts.WriteTotalTimeoutConstant = 2000;   //設定寫超時以指定WriteComm成員函式中的

這樣設定後讀取完所有字元後就會返回,寫完操作後也會返回;

2.3 讀寫串列埠

使用兩個函式ReadFile和WriteFile。

ReadFile:

BOOL ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped);

hFile,要讀取串列埠的控制代碼;

lpBuffer,要接收資料的緩衝區;

nNumberOfBytesToRead,要讀取資料的位元組數;

lpNumberOfBytesRead,DWORD指標,儲存實際讀入的資料的個數;

lpOverlapped,OVERLAPPED結構體,如果是同步串列埠通訊串列埠設定為NULL。非同步串列埠通訊操作需要一個OVERLAPPED結構體指標;

非同步讀取資料示例程式碼如下:

DWORD dwRead;//這個值需要根據實際要讀取的資料
DWORD dwReadTrue = 0;
BOOL bRead;
//清除錯誤標誌
COMSTAT ComStat;
DWORD dwErrorFlags;
ClearCommError(m_hCom, &dwErrorFlags, &ComStat);
dwRead = (dwLength <= ComStat.cbInQue)?dwLength:ComStat.cbInQue;
if ( !dwRead ) return MAXDWORD;//輸入快取區裡面沒有內容
OVERLAPPED osRead;
memset(&osRead, 0, sizeof(OVERLAPPED));
HANDLE hEventRecv = CreateEvent(NULL, TRUE, FALSE, NULL);//這個事件必須為手動復位
osRead.hEvent = hEventRecv;
bRead = ReadFile(m_hCom, pBuffer, dwRead, &dwReadTrue, &osRead);
if ( !bRead && (ERROR_IO_PENDING == GetLastError()) )//讀操作未完成
{
GetOverlappedResult(m_hCom, &osRead, &dwReadTrue, TRUE);//等待讀操作完成,暫時這樣操作
PurgeComm(m_hCom, PURGE_RXABORT|PURGE_RXCLEAR);
ResetEvent(m_hEventRecv);
return dwReadTrue;
}
else if ( !bRead )
{
ClearCommError(m_hCom, &dwErrorFlags, &ComStat);
PurgeComm(m_hCom, PURGE_RXABORT|PURGE_RXCLEAR);
return MAXDWORD;
}
return dwReadTrue;

WriteFile:

BOOL WriteFile(
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped);

hFile,要寫入的串列埠控制代碼;

lpBuffer,要寫入的資料;

nNumberOfBytesToWrite,要寫入資料的位元組數;

lpNumberOfBytesWritten,一個DWORD指標,實際寫入資料位元組數;

lpOverlapped,OVERLAPPED結構體,如果是同步串列埠通訊串列埠設定為NULL。非同步串列埠通訊操作需要一個OVERLAPPED結構體指標;

寫入資料示例程式碼如下:

DWORD dwToWrite = dwLength;
DWORD dwWritten = 0;
BOOL bWrite;
COMSTAT ComStat;
DWORD dwErrorFlags;
ClearCommError(m_hCom, &dwErrorFlags, &ComStat);
PurgeComm(m_hCom, PURGE_TXABORT|PURGE_TXCLEAR);
OVERLAPPED osWrite;
memset(&osWrite, 0, sizeof(OVERLAPPED));
HANDLE hEventSend = CreateEvent(NULL, TRUE, FALSE, NULL);//這個事件必須為手動復位
osWrite.hEvent = hEventSend;
bWrite = WriteFile(m_hCom, pBuffer, dwToWrite, &dwWritten, &osWrite);
if ( !bWrite && (ERROR_IO_PENDING == GetLastError()) )//串列埠寫操作未完成
{
GetOverlappedResult(
m_hCom,
&osWrite,
&dwWritten,
TRUE);//等待寫操作完成,這裡暫時使用這種操作方式
PurgeComm(m_hCom, PURGE_TXABORT|PURGE_TXCLEAR);
ResetEvent(m_hEventSend);
return dwWritten;
}
else if ( !bWrite )//串列埠寫入錯誤
{
ClearCommError( m_hCom, &dwErrorFlags, &ComStat );
PurgeComm(m_hCom, PURGE_TXABORT|PURGE_TXCLEAR);
return MAXDWORD;
}
return dwWritten;
2.4 關閉串列埠

串列埠屬於系統資源,開啟了使用後要關閉掉。呼叫以下函式就行了:

BOOL CloseHandle(HANDLE hObject);
2.5 還有些需要用到的函式
BOOL PurgeComm(HANDLE hFile, DWORD dwFlags);

引數dwFlags指定要完成的操作,可以如下值:

PURGE_TXABORT 無論串列埠處於什麼狀態,中斷所有寫操作並立即返回;

PURGE_RXABORT 無論串列埠處於什麼狀態,中斷所有讀操作並立即返回;

PURGE_TXCLEAR 清空輸出緩衝區;

PURGE_RXCLEAR 清空輸入緩衝區;

3 CSerial成員函式和成員變數

為了方便使用,對串列埠的一些API函式進行了封裝:CSerial類。下表中有CSerial類的說明,具體的使用會有一個使用案例。CSerial類是對串列埠使用的一個封裝,主要包括開啟串列埠,串列埠讀寫功能。該類使用比較簡單,不用複雜的配置,那倆可以馬上使用。還可以共享串列埠,不同的CSerial物件可以共享同一個串列埠,類中有一個對串列埠的引用計數,當與該串列埠繫結的物件都析構後會自動關閉該串列埠。類成員函式如下表:

成員函式說明
CSerial();建構函式;
CSerial(CString strCom, DWORD dwBaudRate = 9600, BYTE byteSize = 8, BYTE byteCheck = NOPARITY, BYTE byteStop = ONESTOPBIT, BOOL bSync = FALSE);建構函式;
WriteData(unsigned char *pBuffer, DWORD dwLength, DWORD dwTimeout = 1000);向串列埠寫入資料
ReadData(unsigned char *pBuffer, DWORD dwLength, DWORD dwTimeout = 1000);從串列埠讀出資料;
ClearError();清除串列埠錯誤,該函式會清除串列埠錯誤標誌位。
Purge();同API函式中的PurgeComm()
SetComString(CString strCom);設定串列埠號,比如“COM1”。只有當例項化CSerial物件是沒有傳入串列埠號或者想要修改串列埠號的時候使用該函式;
SetBaudRate(DWORD dwBaudRate);設定串列埠通訊的波特率,預設為9600;
SetByteSize(BYTE byteSize);設定串列埠通訊的資料位,預設為8位;
SetCheck(BYTE byteCheck);設定串列埠通訊的奇偶校驗,預設為不校驗;
SetStopBit(BYTE byteStopBit);設定串列埠通訊的停止位,預設為一位停止位;
SetSync(BOOL bSync);設定是串列埠通訊是同步還是非同步,預設是同步通訊;
SetInQue(DWORD dwInQue);設定輸入緩衝區大小,預設為1024;
SetOutQue(DWORD dwOutQue);設定輸出緩衝區大小,預設為1024;
SetTimeouts(COMMTIMEOUTS timeouts);設定超時設定,如果更改預設超時設定的時候,呼叫該函式;
GetComString();獲取串列埠通訊的串列埠號;
GetBaudRate();獲取串列埠通訊的波特率;
GetByteSize();獲取串列埠通訊的資料位數;
GetCheck();獲取串列埠通訊是否使用奇偶校驗;
GetStopBit();獲取串列埠通訊使用了幾位停止位;
GetSync();獲取串列埠通訊的通訊方式是同步還是非同步;
GetInQue();獲取串列埠通訊的輸入緩衝區大小;
GetOutQue();獲取串列埠通訊的輸出緩衝區大小;
GetComStatus();獲取串列埠的狀態,一般檢視串列埠是否正確開啟;

4 使用說明

——————————-
CSerial();

建構函式,當例項化物件的時候,不傳入引數則呼叫該函式。如果不傳入引數該物件不能用來通訊,需要通過SetComString(CString strCom);函式來設定該物件的串列埠號來正常通訊;

——————————-
CSerial(
CString strCom,
DWORD dwBaudRate = 9600,
BYTE byteSize = 8,
BYTE byteCheck = NOPARITY,
BYTE byteStop = ONESTOPBIT,
BOOL bSync = FALSE);

建構函式,需要傳入串列埠號。其他引數都有默然值。如果需要更改的話,可以通過Setxx()函式來設定相應的引數;

——————————-
DWORD WriteData(
unsigned char *pBuffer,
DWORD dwLength,
DWORD dwTimeout = 1000);

pBuffer,要寫入的資料;

dwLength,寫入資料的長度;

dwTimeout,非同步通訊的時超時時間,暫時沒有使用,可以不管;

——————————-
DWORD ReadData(
unsigned char *pBuffer,
DWORD dwLength,
DWORD dwTimeout = 1000);

pBuffer,讀取資料緩衝區;

dwLength,讀取資料長度;

dwTimeout,非同步通訊時的超時時間,暫時沒有使用可以不管;

——————————-
void Purge(DWORD dwFlags);

與API中的PurgeComm函式功能一樣,dwFlags的取值可以是PURGE_TXABORT、PUTGE_RXABORT、PURGE_TXCLEAR、PURGE_RXCLEAR或者他們的組合;

——————————-

使用CSerial進行串列埠通訊的例子:

CSerial SerialMeter("COM1");
DWORD dwWritten,dwReadTrue;
unsigned char TxData[11];
unsigned char RxData[11] = {0};
dwWritten = SerialMeter.WriteData(TxData, 11);
if( MAXDWORD == dwWritten )
{
SerialMeter.ClearError();
return;
}
Sleep(100);
dwReadTrue = m_SerialMeter.ReadData(RxData,11);
if ( MAXDWORD == dwReadTrue )
{
m_SerialMeter.ClearError();
return;
}

串列埠共享的時候只需要把一個物件賦值給另一個物件,或者用另一個物件來初始化一個物件就可以了。其他的就像使用單獨的一個物件一樣。串列埠的開啟和關閉由類自己管理。串列埠共享串列埠例子:

CSerial SerialMeter("COM1");
CSerial SeralVelocty = SerialMeter;
DWORD dwWritten,dwReadTrue;
unsigned char TxData[11];
unsigned char RxData[11] = {0};
// 第一個串列埠物件讀寫
dwWritten = SerialMeter.WriteData(TxData, 11);
if( MAXDWORD == dwWritten )
{
SerialMeter.ClearError();
return;
}
Sleep(100);
dwReadTrue = m_SerialMeter.ReadData(RxData,11);
if ( MAXDWORD == dwReadTrue )
{
m_SerialMeter.ClearError();
return;
}
// 另一個串列埠物件讀寫
Sleep(100);
dwWritten = SeralVelocty.WriteData(TxData, 11);
if( MAXDWORD == dwWritten )
{
SeralVelocty.ClearError();
return;
}
Sleep(100);
dwReadTrue = SeralVelocty.ReadData(RxData,11);
if ( MAXDWORD == dwReadTrue )
{
SeralVelocty.ClearError();
return;
}

原始碼如下:
標頭檔案:

//CSerial類標頭檔案
#pragma once
class CSerial
{
public:
CSerial();
CSerial(
CString strCom,
DWORD dwBaudRate = 9600,
BYTE byteSize = 8,
BYTE byteCheck = NOPARITY,
BYTE byteStop = ONESTOPBIT,
BOOL bSync = FALSE);
~CSerial();
inline CSerial(const CSerial &com)
{
m_hCom = com.m_hCom;
m_hEventSend = com.m_hEventSend;
m_hEventRecv = com.m_hEventRecv;
m_bSync = com.m_bSync;
m_bIsFirst = com.m_bIsFirst;
m_strCom = com.m_strCom;
m_dwBaudRate = com.m_dwBaudRate;
m_byteSize = com.m_byteSize;
m_byteCheck = com.m_byteCheck;
m_byteStop = com.m_byteStop;
m_dwInQueue = com.m_dwInQueue;
m_dwOutQueue = com.m_dwOutQueue;
m_Timeouts = com.m_Timeouts;
m_nInitResult = com.m_nInitResult;
m_pnReusecount = com.m_pnReusecount;
if ( m_pnReusecount )
{
(* m_pnReusecount)  ;
}
}
inline CSerial & operator = (const CSerial &com)
{
m_hCom = com.m_hCom;
m_hEventSend = com.m_hEventSend;
m_hEventRecv = com.m_hEventRecv;
m_bSync = com.m_bSync;
m_bIsFirst = com.m_bIsFirst;
m_strCom = com.m_strCom;
m_dwBaudRate = com.m_dwBaudRate;
m_byteSize = com.m_byteSize;
m_byteCheck = com.m_byteCheck;
m_byteStop = com.m_byteStop;
m_dwInQueue = com.m_dwInQueue;
m_dwOutQueue = com.m_dwOutQueue;
m_Timeouts = com.m_Timeouts;
m_nInitResult = com.m_nInitResult;
m_pnReusecount = com.m_pnReusecount;
if ( m_pnReusecount )
{
(* m_pnReusecount)  ;
}
return * this;
}
private:
int *m_pnReusecount;
BOOL m_bIsFirst;         //是否是第一次成功開啟串列埠
HANDLE m_hCom;           //串列埠控制代碼
HANDLE m_hEventSend;     //傳送資料事件
HANDLE m_hEventRecv;     //接收資料事件
BOOL m_bSync;            //同步傳輸還是非同步傳輸,TRUE則為同步,FALSE為非同步,預設為非同步
CString m_strCom;        //串列埠埠
DWORD m_dwBaudRate;      //波特率
BYTE m_byteSize;         //資料位
BYTE m_byteCheck;        //校驗方式
BYTE m_byteStop;         //停止位
DWORD m_dwInQueue;       //串列埠輸入緩衝區     
DWORD m_dwOutQueue;     //串列埠輸出緩衝區
//超時相關變數
COMMTIMEOUTS m_Timeouts;
int m_nInitResult;
public:
DWORD WriteData(unsigned char *pBuffer, DWORD dwLength, DWORD dwTimeout = 1000);  //dwTimeout為佔位符,暫時未用,返回,MAXDWORD表示寫入錯誤
DWORD ReadData(unsigned char *pBuffer, DWORD dwLength, DWORD dwTimeout = 1000);   //dwTimeout為佔位符,暫時未用,返回,MAXDWORD表示讀取錯誤
void CloseCom();
int InitCom();//返回1,表示沒有錯誤,返回其他表示錯誤
void ClearError();
void Purge(DWORD dwFlags);
int SetComString(CString strCom);
int SetBaudRate(DWORD dwBaudRate);
int SetByteSize(BYTE byteSize);
int SetCheck(BYTE byteCheck);
int SetStopBit(BYTE byteStopBit);
int SetSync(BOOL bSync);
int SetInQue(DWORD dwInQue);
int SetOutQue(DWORD dwOutQue);
int SetTimeouts(COMMTIMEOUTS timeouts);
CString GetComString();
DWORD GetBaudRate();
BYTE GetByteSize();
BYTE GetCheck();
BYTE GetStopBit();
BOOL GetSync();
DWORD GetInQue();
DWORD GetOutQue();
int GetComStatus();//InitCom的返回值,觀察串列埠是否開啟成功,0表示沒有串列埠名稱,1表示開啟成功,MAXINI32表示串列埠開啟錯誤
};

原始檔:

#include "stdafx.h"
#include "Serial.h"
CSerial::CSerial()
{
m_pnReusecount = NULL;
m_hCom = NULL;
m_hEventRecv = NULL;
m_hEventSend = NULL;
m_strCom = _T("");
m_dwBaudRate = 9600;
m_byteSize = 8;
m_byteCheck = NOPARITY;
m_byteStop = ONESTOPBIT;
m_bSync = TRUE;
m_bIsFirst = TRUE;
//緩衝區變數初始化
m_dwInQueue = 1024;
m_dwOutQueue = 1024;
//超時變數初始化
COMMTIMEOUTS timeout = {MAXDWORD, 0, 0, 50, 1000};
m_Timeouts = timeout;
}
CSerial::CSerial(
CString strCom,
DWORD dwBaudRate,
BYTE byteSize,
BYTE byteCheck,
BYTE byteStop,
BOOL bSync)
{
m_pnReusecount = NULL;
m_hCom = NULL;
m_hEventRecv = NULL;
m_hEventSend = NULL;
m_strCom = strCom;
m_dwBaudRate = dwBaudRate;
m_byteSize = byteSize;
m_byteCheck = byteCheck;
m_byteStop = byteStop;
m_bSync = bSync;
m_bIsFirst = TRUE;
//緩衝區變數初始化
m_dwInQueue = 1024;
m_dwOutQueue = 1024;
//超時變數初始化
COMMTIMEOUTS timeout = {MAXDWORD, 0, 0, 50, 1000};
m_Timeouts = timeout;
m_nInitResult = InitCom();
}
CSerial::~CSerial()
{
if (m_pnReusecount)
{
(* m_pnReusecount)--;
if( 0 >= *m_pnReusecount )
{
CloseCom();
delete m_pnReusecount;
}
}
}
void CSerial::CloseCom()
{
if ( m_hEventRecv )
{
CloseHandle(m_hEventRecv);
m_hEventRecv = NULL;
}
if ( m_hEventSend )
{
CloseHandle(m_hEventSend);
m_hEventSend = NULL;
}
if ( m_hCom )
{
CloseHandle(m_hCom);
m_hCom = NULL;
}
}
int CSerial::InitCom()
{
if ( m_strCom == _T("") ) return 0;//如果串列埠傳入為空,則進行串列埠初始化
if ( m_hCom )
{
CloseHandle(m_hCom);
}
if ( m_bSync )
{
m_hCom = CreateFile(m_strCom, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
}
else
{
m_hCom = CreateFile(m_strCom, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, NULL);
}
if ( m_hCom == INVALID_HANDLE_VALUE )//串列埠開啟失敗
{
m_hCom = NULL;
return 2;
}
//設定緩衝區大小,預設為1024;
SetupComm(m_hCom, m_dwInQueue, m_dwOutQueue);
//超時設定
SetCommTimeouts(m_hCom, &m_Timeouts);
//配置串列埠
DCB dcb;
GetCommState(m_hCom, &dcb);
dcb.BaudRate = m_dwBaudRate;
dcb.ByteSize = m_byteSize;
dcb.Parity = m_byteCheck;
dcb.StopBits = m_byteStop;
SetCommState(m_hCom, &dcb);
PurgeComm(m_hCom, PURGE_TXABORT|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_RXCLEAR);
if ( m_bIsFirst )
{
m_pnReusecount = new int;
* m_pnReusecount = 1;
m_bIsFirst = FALSE;
}
return 1;
}
void CSerial::ClearError()
{
COMSTAT ComStat;
DWORD dwErrorFlags;
ClearCommError(m_hCom, &dwErrorFlags, &ComStat);
PurgeComm(m_hCom, PURGE_TXABORT|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_RXCLEAR);
if ( m_hEventRecv ) ResetEvent(m_hEventRecv);
if ( m_hEventSend ) ResetEvent(m_hEventSend);
}
DWORD CSerial::WriteData(unsigned char *pBuffer, DWORD dwLength, DWORD dwTimeout)
{
if ( !m_hCom ) return MAXDWORD;
DWORD dwToWrite = dwLength;
DWORD dwWritten = 0;
BOOL bWrite;
COMSTAT ComStat;
DWORD dwErrorFlags;
ClearCommError(m_hCom, &dwErrorFlags, &ComStat);
PurgeComm(m_hCom, PURGE_TXABORT|PURGE_TXCLEAR);
if ( m_bSync )//同步
{
bWrite =WriteFile(m_hCom, pBuffer, dwToWrite, &dwWritten, NULL);
if ( bWrite )
{
return dwWritten;
}
else
{
return MAXDWORD;
}
}
else//非同步
{
OVERLAPPED osWrite;
memset(&osWrite, 0, sizeof(OVERLAPPED));
if ( !m_hEventSend )
{
m_hEventSend = CreateEvent(NULL, TRUE, FALSE, NULL);//這個事件必須為手動復位
}
osWrite.hEvent = m_hEventSend;
bWrite = WriteFile(m_hCom, pBuffer, dwToWrite, &dwWritten, &osWrite);
if ( !bWrite && (ERROR_IO_PENDING == GetLastError()) )//串列埠寫操作未完成
{
GetOverlappedResult(m_hCom, &osWrite, &dwWritten, TRUE);//等待寫操作完成,這裡暫時使用這種操作方式
PurgeComm(m_hCom, PURGE_TXABORT|PURGE_TXCLEAR);
ResetEvent(m_hEventSend);
return dwWritten;
}
else if ( !bWrite )//串列埠寫入錯誤
{
ClearCommError( m_hCom, &dwErrorFlags, &ComStat );
PurgeComm(m_hCom, PURGE_TXABORT|PURGE_TXCLEAR);
return MAXDWORD;
}
return dwWritten;
}
}
DWORD CSerial::ReadData(unsigned char *pBuffer, DWORD dwLength, DWORD dwTimeout)
{
if ( !m_hCom ) return MAXDWORD;
DWORD dwRead;
DWORD dwReadTrue = 0;
BOOL bRead;
//清除錯誤標誌
COMSTAT ComStat;
DWORD dwErrorFlags;
ClearCommError(m_hCom, &dwErrorFlags, &ComStat);
dwRead = (dwLength <= ComStat.cbInQue)?dwLength:ComStat.cbInQue;
if ( !dwRead ) return MAXDWORD;//輸入快取區裡面沒有內容
if ( m_bSync )//同步
{
bRead = ReadFile(m_hCom, pBuffer, dwRead, &dwReadTrue, NULL);
if ( bRead )
{
return dwReadTrue;
}
else
{
return MAXDWORD;
}
}
else//非同步
{
OVERLAPPED osRead;
memset(&osRead, 0, sizeof(OVERLAPPED));
if ( !m_hEventRecv )
{
m_hEventRecv = CreateEvent(NULL, TRUE, FALSE, NULL);//這個事件必須為手動復位
}
osRead.hEvent = m_hEventRecv;
bRead = ReadFile(m_hCom, pBuffer, dwRead, &dwReadTrue, &osRead);
if ( !bRead && (ERROR_IO_PENDING == GetLastError()) )//讀操作未完成
{
GetOverlappedResult(m_hCom, &osRead, &dwReadTrue, TRUE);//等待讀操作完成,暫時這樣操作
PurgeComm(m_hCom, PURGE_RXABORT|PURGE_RXCLEAR);
ResetEvent(m_hEventRecv);
return dwReadTrue;
}
else if ( !bRead )
{
ClearCommError(m_hCom, &dwErrorFlags, &ComStat);
PurgeComm(m_hCom, PURGE_RXABORT|PURGE_RXCLEAR);
return MAXDWORD;
}
return dwReadTrue;
}
}
void CSerial::Purge(DWORD dwFlags)
{
PurgeComm(m_hCom, dwFlags);
}
int CSerial::SetComString(CString strCom)
{
CString strTemp = m_strCom;
m_strCom = strCom;
m_nInitResult = InitCom();
if ( 1 != m_nInitResult )
{
m_strCom = strTemp;
return -1;
}
return 0;
}
int CSerial::SetBaudRate(DWORD dwBaudRate)
{
DWORD dwTemp = m_dwBaudRate;
m_dwBaudRate = dwBaudRate;
m_nInitResult = InitCom();
if ( 1 != m_nInitResult )
{
m_dwBaudRate = dwTemp;
return -1;
}
return 0;
}
int CSerial::SetByteSize(BYTE byteSize)
{
BYTE byteTemp = m_byteSize;
m_byteSize = byteSize;
m_nInitResult = InitCom();
if ( 1 != m_nInitResult )
{
m_byteSize = byteTemp;
return -1;
}
return 0;
}
int CSerial::SetCheck(BYTE byteCheck)
{
BYTE byteTemp = m_byteCheck;
m_byteCheck = byteCheck;
m_nInitResult = InitCom();
if ( 1 != m_nInitResult )
{
m_byteCheck = byteTemp;
return -1;
}
return 0;
}
int CSerial::SetStopBit(BYTE byteStopBit)
{
BYTE byteTemp = m_byteStop;
m_byteStop = byteStopBit;
m_nInitResult = InitCom();
if ( 1 != m_nInitResult )
{
m_byteStop = byteTemp;
return -1;
}
return 0;
}
int CSerial::SetSync(BOOL bSync)
{
BOOL bTemp = m_bSync;
m_bSync = bSync;
m_nInitResult = InitCom();
if ( 1 != m_nInitResult )
{
m_bSync = bTemp;
return -1;
}
return 0;
}
int CSerial::SetInQue(DWORD dwInQue)
{
DWORD dwTemp = m_dwInQueue;
m_dwInQueue = dwInQue;
m_nInitResult = InitCom();
if ( 1 != m_nInitResult )
{
m_dwInQueue = dwTemp;
return -1;
}
return 0;
}
int CSerial::SetOutQue(DWORD dwOutQue)
{
DWORD dwTemp = m_dwOutQueue;
m_dwOutQueue = dwOutQue;
m_nInitResult = InitCom();
if ( 1 != m_nInitResult )
{
m_dwOutQueue = dwTemp;
return -1;
}
return 0;
}
int CSerial::SetTimeouts(COMMTIMEOUTS timeouts)
{
COMMTIMEOUTS timeoutTemp = m_Timeouts;
m_Timeouts = timeouts;
m_nInitResult = InitCom();
if ( 1 != m_nInitResult )
{
m_Timeouts = timeoutTemp;
return -1;
}
return 0;
}
CString CSerial::GetComString()
{
return m_strCom;
}
DWORD CSerial::GetBaudRate()
{
return m_dwBaudRate;
}
BYTE CSerial::GetByteSize()
{
return m_byteSize;
}
BYTE CSerial::GetCheck()
{
return m_byteCheck;
}
BYTE CSerial::GetStopBit()
{
return m_byteStop;
}
BOOL CSerial::GetSync()
{
return m_bSync;
}
DWORD CSerial::GetInQue()
{
return m_dwInQueue;
}
DWORD CSerial::GetOutQue()
{
return m_dwOutQueue;
}
int CSerial::GetComStatus()
{
return m_nInitResult;
}

相關文章

程式語言 最新文章