今兒看了幾篇碩士論文,又看到了有人在用MSComm控件編的串口。當時我就不太懂這玩意兒是怎麼用的,其實是因爲在MFC(visual studio 2013環境)裏怎麼找也找不到這個控件。。。好吧,偷懶不成只好自己編一個串口類來實現功能了。
參考了很多文獻和CSDN上的前輩的程序,最後編了一個小玩意兒,雖然不大,但是設置、收發、等待和其他一些功能也是完備了。
直接上代碼吧,以供後來人參考,回報社會。
(p.s. 1. 串口使用非重疊模式(在代碼中標識爲異步模式,兩者是否嚴格等價有待考證),執行收發程序時不必等待操作完成;2. 串口名實際命名爲\\\\.\\COMX,X是串口號,這樣可以創建10以上的串口)
頭文件
#ifndef MYSERIALPORT_H_
#define MYSERIALPORT_H_
#include "stdafx.h"
#include "MyMutex.h"
class CSerialPort
{
private:
// 串口句柄
HANDLE m_hComm;
// 串口名
CString m_comName;
// 串口波特率
DWORD m_Baud;
// 串口讀寫緩衝區
DWORD m_dwInQueue;
DWORD m_dwOutQueue;
// 串口超時
DWORD m_ReadIntervalTimeout;
DWORD m_ReadTotalTimeoutMultiplier;
DWORD m_ReadTotalTimeoutConstant;
DWORD m_WriteTotalTimeoutMultiplier;
DWORD m_WriteTotalTimeoutConstant;
// 返回錯誤碼
DWORD m_dwError;
public:
// 串口讀相關變量
COMSTAT m_ComStat;
OVERLAPPED m_ovRead;
BOOL m_bWaitRead;
DWORD m_BytesRead;
BOOL m_IsReadFault;// 判斷是否讀出錯,出錯TRUE,沒錯FALSE
DWORD m_ReadError;
// 串口寫相關變量
OVERLAPPED m_ovWrite;
BOOL m_bWaitWrite;
DWORD m_BytesSent;
BOOL m_IsWriteFault;// 判斷是否寫出錯,出錯TRUE,沒錯FALSE
DWORD m_WriteError;
// 標誌操作是否成功
BOOL IsCreate;
BOOL IsClose;
BOOL IsSetBaud;
BOOL IsSetQueue;
BOOL IsSetTimeOut;
private:
// 用於設置串口屬性,設置爲內聯函數
BOOL BaudExeu();
BOOL QueueExeu();
BOOL TimeOutExeu();
public:
// 構造函數及默認構造函數
CSerialPort(CString Name = _T("COM1"));
// 複製構造函數
CSerialPort(CSerialPort & Obj_port);
// 重載等號
CSerialPort & operator = (const CString Name);
// 析構函數
virtual ~CSerialPort();
// 轉換函數,隱式
operator HANDLE() { return HANDLE(m_hComm); }
// 初始化串口屬性的基本操作
BOOL CreatePort();
void Baud_Config(DWORD Baud = 57600);
void QueueSize_Config(DWORD inQueueSize = 1024, DWORD outQueueSize = 1024);
void TimeOut_Config(DWORD RT = 0, DWORD RM = 0, DWORD RC = 0, DWORD WM = 0, DWORD WC = 0);
// 獲取句柄
HANDLE GetSerialHANDLE();
// close handle
BOOL ReleaseHandle();
// 獲取錯誤碼
DWORD GetErrorCode();
// 配置串口讀寫的操作
void InitParamofRW(BOOL IfWaitRead = TRUE, BOOL IfWaitWrite = TRUE);
// 串口讀寫函數
BOOL RecvData(char* bufferRecv);
BOOL SendData(char* m_szWriteBuffer, UINT num = NULL, BOOL Default = TRUE);
// 判斷讀寫超時
BOOL StillOverlappedRead(DWORD timeout = INFINITE);
BOOL StillOverlappedWrite(DWORD timeout = INFINITE);
};
#endif
源文件
#include "stdafx.h"
#include "MySerialPort.h"
CSerialPort::CSerialPort(CString Name)
{
m_hComm = NULL;
m_comName = Name;
m_Baud = 57600;
m_dwInQueue = 1024;
m_dwOutQueue = 1024;
m_ReadIntervalTimeout = 0;
m_ReadTotalTimeoutMultiplier = 0;
m_ReadTotalTimeoutConstant = 0;
m_WriteTotalTimeoutMultiplier = 0;
m_WriteTotalTimeoutConstant = 0;
IsCreate = FALSE;
IsSetBaud = FALSE;
IsSetQueue = FALSE;
IsSetTimeOut = FALSE;
m_dwError = 0;
}
CSerialPort::CSerialPort(CSerialPort & Obj_port)
{
}
CSerialPort & CSerialPort::operator = (const CString Name)
{
m_hComm = NULL;
//m_comName.Format(Name.GetString());
m_comName = Name;
m_Baud = 57600;
m_dwInQueue = 1024;
m_dwOutQueue = 1024;
m_ReadIntervalTimeout = 0;
m_ReadTotalTimeoutMultiplier = 0;
m_ReadTotalTimeoutConstant = 0;
m_WriteTotalTimeoutMultiplier = 0;
m_WriteTotalTimeoutConstant = 0;
IsCreate = FALSE;
IsClose = FALSE;
IsSetBaud = FALSE;
IsSetQueue = FALSE;
IsSetTimeOut = FALSE;
m_dwError = 0;
return *this;
}
CSerialPort::~CSerialPort()
{
if (m_hComm != NULL)
{
CloseHandle(m_hComm);
m_hComm = NULL;
}
}
BOOL CSerialPort::CreatePort()
{
CString ipszPortName = _T("");
ipszPortName.Format(_T("\\\\.\\%s"), m_comName);
m_hComm = CreateFile(ipszPortName, // COM串口
GENERIC_READ | GENERIC_WRITE,
0, // 獨佔方式
NULL,
OPEN_EXISTING, // 打開而不是創建
FILE_FLAG_OVERLAPPED, // 重疊方式
NULL);
if (m_hComm == INVALID_HANDLE_VALUE) // if create failed
{
m_dwError = GetLastError();
CloseHandle(m_hComm);
m_hComm = NULL;
IsCreate = FALSE;
return FALSE;
}
IsClose = FALSE;
// set specific serial port event
SetCommMask(m_hComm,
EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RXCHAR | EV_TXEMPTY);
IsSetBaud = BaudExeu();
IsSetQueue = QueueExeu();
IsSetTimeOut = TimeOutExeu();
InitParamofRW(FALSE, TRUE);
IsCreate = TRUE;
return TRUE;
}
inline BOOL CSerialPort::BaudExeu()
{
DCB dcb;
memset(&dcb, 0, sizeof(dcb));
if (!GetCommState(m_hComm, &dcb))//獲取當前 DCB 配置
{
m_dwError = GetLastError();
return FALSE;
}
//set DCB to configure the serialport
dcb.DCBlength = sizeof(dcb);
//Serial Port Config
dcb.BaudRate = m_Baud;
dcb.Parity = NOPARITY;
dcb.fParity = 0;
dcb.StopBits = ONESTOPBIT;
dcb.ByteSize = 8;
dcb.fOutxCtsFlow = 0;
dcb.fOutxDsrFlow = 0;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fDsrSensitivity = 0;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.fOutX = 0;
dcb.fInX = 0;
//misc parameters
dcb.fErrorChar = 0;
dcb.fBinary = 1;
dcb.fNull = 0;
dcb.fAbortOnError = 0;
dcb.wReserved = 0;
dcb.XonLim = 2;
dcb.XoffLim = 4;
dcb.XonChar = 0x13;
dcb.XoffChar = 0x19;
dcb.EvtChar = 0;
//set DCB
if (!SetCommState(m_hComm, &dcb))
{
m_dwError = GetLastError();
return FALSE;
}
return TRUE;
}
inline BOOL CSerialPort::QueueExeu()
{
// in and out buffer size, byte
if (!SetupComm(m_hComm, m_dwInQueue, m_dwOutQueue))
{
m_dwError = GetLastError();
return FALSE;
}
return TRUE;
}
inline BOOL CSerialPort::TimeOutExeu()
{
COMMTIMEOUTS TimeOuts;
TimeOuts.ReadIntervalTimeout = m_ReadIntervalTimeout;
TimeOuts.ReadTotalTimeoutMultiplier = m_ReadTotalTimeoutMultiplier;
TimeOuts.ReadTotalTimeoutConstant = m_ReadTotalTimeoutConstant;
TimeOuts.WriteTotalTimeoutMultiplier = m_WriteTotalTimeoutMultiplier;
TimeOuts.WriteTotalTimeoutConstant = m_WriteTotalTimeoutConstant;
if (!SetCommTimeouts(m_hComm, &TimeOuts)) // 設定超時
{
m_dwError = GetLastError();
return FALSE;
}
return TRUE;
}
void CSerialPort::Baud_Config(DWORD Baud)
{
m_Baud = Baud;
}
void CSerialPort::QueueSize_Config(DWORD inQueueSize, DWORD outQueueSize)
{
m_dwInQueue = inQueueSize;
m_dwOutQueue = outQueueSize;
}
void CSerialPort::TimeOut_Config(DWORD RT, DWORD RM, DWORD RC, DWORD WM, DWORD WC)
{
m_ReadIntervalTimeout = RT;
m_ReadTotalTimeoutMultiplier = RM;
m_ReadTotalTimeoutConstant = RC;
m_WriteTotalTimeoutMultiplier = WM;
m_WriteTotalTimeoutConstant = WC;
}
HANDLE CSerialPort::GetSerialHANDLE()
{
return m_hComm;
}
BOOL CSerialPort::ReleaseHandle()
{
//if (m_hComm == NULL)
//{
// return FALSE;
//}
PurgeComm(m_hComm,
PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_RXABORT);
if (!CloseHandle(m_hComm))
{
m_dwError = GetLastError();
return FALSE;
}
m_dwError = GetLastError();
m_hComm = NULL;
IsCreate = FALSE;
IsClose = TRUE;
return TRUE;
}
DWORD CSerialPort::GetErrorCode()
{
return m_dwError;
}
void CSerialPort::InitParamofRW(BOOL IfWaitRead, BOOL IfWaitWrite)
{
m_BytesRead = 0;
m_IsReadFault = FALSE;
m_ReadError = 0;
m_bWaitRead = IfWaitRead;// overlapped read
// read event
memset(&m_ovRead, 0, sizeof(OVERLAPPED));
// 2nd param, auto reset; 3rd param, init status no signal
// when call function ReadFile or WriteFile,
m_ovRead.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
m_BytesSent = 0;
m_IsWriteFault = FALSE;
m_WriteError = 0;
m_bWaitWrite = IfWaitWrite;// overlapped write
// write event
memset(&m_ovWrite, 0, sizeof(OVERLAPPED));
// 2nd param, auto reset; 3rd param, init status no signal
// when call function ReadFile or WriteFile,
m_ovWrite.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
// clear in & out buffer in serial port
PurgeComm(m_hComm,
PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_RXABORT);
}
BOOL CSerialPort::RecvData(char* bufferRecv)
{
// 下面這個不對,因爲要在外部通過m_ComStat位來確定是不是有數
/*if (!ClearCommError(m_hComm, &m_ReadError, &m_ComStat))
{
m_ReadError = GetLastError();
}*/
if (!ReadFile(m_hComm,//Handle to COMM port
bufferRecv,//RXBuffer Pointer
m_ComStat.cbInQue, //Read m_ComStat.cbInQue bytes
&m_BytesRead,//Stores number of bytes read
&m_ovRead))//pointer to the m_ov structure
{
m_ReadError = GetLastError();
switch (m_ReadError)
{
case ERROR_IO_PENDING:
//case ERROR_IO_INCOMPLETE:
m_IsReadFault = FALSE;
break;
default:
m_IsReadFault = TRUE;
break;
}
return FALSE;
}
return TRUE;
}
BOOL CSerialPort::StillOverlappedRead(DWORD timeout)
{
WaitForSingleObject(m_hComm, timeout);
// 非零表示異步操作結束,零表示異步操作仍在執行
if (0 != GetOverlappedResult(m_hComm, //Handle to COMM port
&m_ovRead,// Overlapped structure
&m_BytesRead, // Stores number of bytes read
FALSE)) //Wait flag
{
return FALSE;
}
return TRUE;
}
BOOL CSerialPort::SendData(char* m_szWriteBuffer, UINT num, BOOL Default)
{
// Clear buffer
PurgeComm(m_hComm, PURGE_TXCLEAR | PURGE_TXABORT);
m_ovWrite.Offset = 0;
m_ovWrite.OffsetHigh = 0;
DWORD m_nToSend = 0;
if (Default)
m_nToSend = strlen(m_szWriteBuffer);
else
m_nToSend = num;
if (!WriteFile(m_hComm, // Handle to COMM Port
m_szWriteBuffer, // Pointer to message buffer in calling finction
m_nToSend, // Length of message to send
&m_BytesSent, //Where to store the number of bytes sent
&m_ovWrite))//Overlapped structure
{
m_WriteError = GetLastError();
switch (m_WriteError)
{
case ERROR_IO_PENDING:
//case ERROR_IO_INCOMPLETE:
m_IsWriteFault = FALSE;
break;
default:
m_IsWriteFault = TRUE;
break;
}
return FALSE;
}
return TRUE;
}
BOOL CSerialPort::StillOverlappedWrite(DWORD timeout)
{
WaitForSingleObject(m_hComm, timeout);
// 非零表示異步操作結束,零表示異步操作仍在執行
if (0 != GetOverlappedResult(m_hComm, //Handle to COMM port
&m_ovWrite,// Overlapped structure
&m_BytesSent, //Stores number of bytes sent
FALSE)) //Waitflag
{
return FALSE;
}
return TRUE;
}