Windows下的串口類及功能實現

今兒看了幾篇碩士論文,又看到了有人在用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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章