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;
}


你可能感兴趣的:(c/c++,program)