⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 comport.cpp

📁 支持同步异步模式的串口类,当串口有数据过来时自动接受,可被继承扩展
💻 CPP
字号:
#include "stdafx.h"
#include "ComPort.h"

CComPort::CComPort()
:m_bOverlapped(FALSE),
m_hComm(INVALID_HANDLE_VALUE)
{
  ZeroMemory(&m_ReadOverlapped, sizeof(OVERLAPPED));
  ZeroMemory(&m_WriteOverlapped, sizeof(OVERLAPPED));
  ZeroMemory(&m_WriteOverlapped, sizeof(OVERLAPPED));

  m_pReadComThread = new CReadComThread(this);
}

CComPort::~CComPort()
{
  Close();
  delete m_pReadComThread;
}

/************************************************************************
	打开串口
************************************************************************/
BOOL CComPort::Open(int nPort, BOOL bOverlapped /*=FALSE*/, DWORD dwBaud /*= 9600*/, BYTE DataBits /*= 8*/, CComPort::Parity parity /*= NoParity*/, CComPort::StopBits stopbits /*= OneStopBit*/, CComPort::FlowControl fc /*= NoFlowControl*/)
{
	 ASSERT(nPort>0 && nPort<=255);

    CString  strPort;
	strPort.Format(_T("\\\\.\\COM%d"), nPort);

	DWORD dwFlags;
	if (bOverlapped)
	{
		dwFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED;
	}
	else
	{
        dwFlags = FILE_ATTRIBUTE_NORMAL;
	}
	m_hComm = CreateFile(strPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, dwFlags, NULL);
    if (m_hComm == INVALID_HANDLE_VALUE)
	{
		return FALSE;
	}
	//Get the current state prior to changing it
	DCB dcb;
	dcb.DCBlength = sizeof(DCB);
	GetCommState(m_hComm, &dcb);

	//Setup the baud rate
	dcb.BaudRate = dwBaud; 

	//Setup the Parity
	switch (parity)
	{
	case EvenParity:  dcb.Parity = EVENPARITY;  break;
	case MarkParity:  dcb.Parity = MARKPARITY;  break;
	case NoParity:    dcb.Parity = NOPARITY;    break;
	case OddParity:   dcb.Parity = ODDPARITY;   break;
	case SpaceParity: dcb.Parity = SPACEPARITY; break;
	default:          ASSERT(FALSE);            break;
	}

	//Setup the data bits
	dcb.ByteSize = DataBits;

	//Setup the stop bits
	switch (stopbits)
	{
	case OneStopBit:           dcb.StopBits = ONESTOPBIT;   break;
	case OnePointFiveStopBits: dcb.StopBits = ONE5STOPBITS; break;
	case TwoStopBits:          dcb.StopBits = TWOSTOPBITS;  break;
	default:                   ASSERT(FALSE);               break;
	}

	//Setup the flow control 
	dcb.fDsrSensitivity = FALSE;
	switch (fc)
	{
	case NoFlowControl:
		{
			dcb.fOutxCtsFlow = FALSE;
			dcb.fOutxDsrFlow = FALSE;
			dcb.fOutX = FALSE;
			dcb.fInX = FALSE;
			break;
		}
	case CtsRtsFlowControl:
		{
			dcb.fOutxCtsFlow = TRUE;
			dcb.fOutxDsrFlow = FALSE;
			dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
			dcb.fOutX = FALSE;
			dcb.fInX = FALSE;
			break;
		}
	case CtsDtrFlowControl:
		{
			dcb.fOutxCtsFlow = TRUE;
			dcb.fOutxDsrFlow = FALSE;
			dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
			dcb.fOutX = FALSE;
			dcb.fInX = FALSE;
			break;
		}
	case DsrRtsFlowControl:
		{
			dcb.fOutxCtsFlow = FALSE;
			dcb.fOutxDsrFlow = TRUE;
			dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
			dcb.fOutX = FALSE;
			dcb.fInX = FALSE;
			break;
		}
	case DsrDtrFlowControl:
		{
			dcb.fOutxCtsFlow = FALSE;
			dcb.fOutxDsrFlow = TRUE;
			dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
			dcb.fOutX = FALSE;
			dcb.fInX = FALSE;
			break;
		}
	case XonXoffFlowControl:
		{
			dcb.fOutxCtsFlow = FALSE;
			dcb.fOutxDsrFlow = FALSE;
			dcb.fOutX = TRUE;
			dcb.fInX = TRUE;
			dcb.XonChar = 0x11;
			dcb.XoffChar = 0x13;
			dcb.XoffLim = 100;
			dcb.XonLim = 100;
			break;
		}
	default:
		{
			ASSERT(FALSE);
			break;
		}
	}

	//Now that we have all the settings in place, make the changes
	SetCommState(m_hComm, &dcb);
    
	SetBufferSize(1024, 1024);

	PurgeComm(m_hComm, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);

	COMMTIMEOUTS  timeouts;
	GetTimeouts(timeouts);
	timeouts.ReadIntervalTimeout = 100;
	SetTimeouts(timeouts);

	m_bOverlapped = bOverlapped;
    if (m_bOverlapped)
	{
		m_ReadOverlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
		m_WriteOverlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
		m_WaitOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	}
	m_pReadComThread->Create();

	return  TRUE;
}

/************************************************************************
  关闭串口
************************************************************************/
void CComPort::Close()
{
    if (IsOpen())
	{
		if (m_pReadComThread)
		{
			m_pReadComThread->Exit();
		}
		CloseHandle(m_hComm);
		m_hComm = INVALID_HANDLE_VALUE;
		m_bOverlapped = FALSE;
		
		if (m_ReadOverlapped.hEvent)
		{
			CloseHandle(m_ReadOverlapped.hEvent);
		}
		if (m_WriteOverlapped.hEvent)
		{
			CloseHandle(m_WriteOverlapped.hEvent);
		}
		if (m_WaitOverlapped.hEvent)
		{
			CloseHandle(m_WaitOverlapped.hEvent);
		}
	}
}

void CComPort::SetTimeouts(COMMTIMEOUTS& timeouts)
{
	ASSERT(IsOpen());

	if (!SetCommTimeouts(m_hComm, &timeouts))
	{
		TRACE(_T("Failed in call to SetCommTimeouts\n"));
	}
}

void CComPort::GetTimeouts(COMMTIMEOUTS& timeouts)
{
	ASSERT(IsOpen());

	if (!GetCommTimeouts(m_hComm, &timeouts))
	{
		TRACE(_T("Failed in call to GetCommTimeouts\n"));
	}
}

/************************************************************************
 串口是否打开
************************************************************************/
BOOL CComPort::IsOpen() const
{
	return m_hComm != INVALID_HANDLE_VALUE;
}

/************************************************************************
 设置串口输入和输出缓冲区大小
************************************************************************/
void CComPort::SetBufferSize(DWORD dwInputSize, DWORD dwOutputSize)
{
    ASSERT(IsOpen());
	SetupComm(m_hComm, dwInputSize, dwOutputSize);
}

/************************************************************************
 获取串口输入缓冲区字节数量
************************************************************************/
DWORD CComPort::GetInputSize() const
{
	COMSTAT Stat;
	DWORD dwError;
	return ClearCommError(m_hComm, &dwError, &Stat) == TRUE  ? Stat.cbInQue : (DWORD)-1L;
}

/************************************************************************
 设置事件信号掩码
************************************************************************/
void CComPort::SetEvent(DWORD dwMask)
{
    ASSERT(IsOpen());
	SetCommMask(m_hComm, dwMask);
}

/************************************************************************
  支持同步,异步模式 
************************************************************************/
BOOL CComPort::WaitEvent(DWORD &dwMask)
{
	ASSERT(IsOpen());
 
	LPOVERLAPPED pWait = NULL;
	if (m_bOverlapped)
	{
       pWait = &m_WaitOverlapped;
	}

	if (!WaitCommEvent(m_hComm, &dwMask, pWait))
	{
		if (pWait)
		{
			if (GetLastError()== ERROR_IO_PENDING)
			{
				DWORD dwLength;
				return GetOverlappedResult(m_hComm, &m_WaitOverlapped, &dwLength, TRUE);
			}
			else
			{
				return FALSE;
			}
		}
		else
		{
			return FALSE;
		}
		
	}

	return TRUE;
}

/************************************************************************
  从串口读数据,  可设定超时
  当为同步模式时,忽略超时;异步模式时,超时有效
************************************************************************/
DWORD CComPort::ReadComm(void* pData, DWORD dwDataSize, DWORD dwTimeouts /* = 0 */)
{
     ASSERT(pData);
 	 ASSERT(IsOpen());

	 COMSTAT  Stat;
	 DWORD dwError;
	 if(::ClearCommError(m_hComm, &dwError, &Stat) && dwError > 0)
	 {
		 ::PurgeComm(m_hComm, PURGE_RXABORT | PURGE_RXCLEAR);
		 return 0;
	 }

	 // 缓冲区无数据
	 if(!Stat.cbInQue) 
		 return 0;

	 DWORD dwReadBytes = 0;
	 LPOVERLAPPED pOver = NULL;

	 //异步读取数据
	 if (m_bOverlapped)
	 {
         pOver = &m_ReadOverlapped;
     }
	 dwDataSize = min(Stat.cbInQue, dwDataSize);
	 if (!ReadFile(m_hComm, pData, dwDataSize, &dwReadBytes, pOver))
	 {
		 if (pOver)
		 {
			if (ERROR_IO_PENDING == GetLastError())
			{
				WaitForSingleObject(m_ReadOverlapped.hEvent, dwTimeouts); //等待dwTimeouts毫秒
				if (!GetOverlappedResult(m_hComm, &m_ReadOverlapped, &dwReadBytes, FALSE))
				{
					if (ERROR_IO_INCOMPLETE != GetLastError())
					{
						 dwReadBytes = 0;
					}
				}
			}
			else
			{
				dwReadBytes = 0;
			}
		 }
		 else
		 {
			 dwReadBytes = 0; //读取错误
		 }
	 }

	 return dwReadBytes;
}

/************************************************************************
   向串口写数据
************************************************************************/
DWORD CComPort::WriteComm(const void* pData, DWORD dwDataSize)
{
     ASSERT(pData);
	 ASSERT(IsOpen());

	 DWORD dwError;
	 if(::ClearCommError(m_hComm, &dwError, NULL) && dwError > 0) 
		 ::PurgeComm(m_hComm, PURGE_TXABORT | PURGE_TXCLEAR); 

	 DWORD dwWriteBytes = 0;
	 LPOVERLAPPED pOver = NULL;
	 if (m_bOverlapped)
	 {
		 pOver = &m_WriteOverlapped;
	 }
	 
	 if (!WriteFile(m_hComm, pData, dwDataSize, &dwWriteBytes, pOver))
	 {
		 if (pOver)
		 {
			 //异步写,在后台完成
			 if (ERROR_IO_PENDING != GetLastError())
			 {
				 dwWriteBytes = 0;  //写入错误
			 }
		 }
		 else
		 {
			 dwWriteBytes = 0;     //写入错误
		 }
		
	 }
	 return  dwWriteBytes;
}

/************************************************************************
   1. 该函数仅支持异步模式, 由读线程负责调用,即当串口有数据到来时
      会自动调用该函数,且pData存放好了所接收到的数据
      pData为接受到的数据缓冲区, dwDataSize为接收到的字节数

   2. 可在派生类中重写该虚函数, 解析缓冲区数据
************************************************************************/
void  CComPort::OnReceive(PVOID pBuffer, DWORD dwDataSize)
{
     
}

/************************************************************************
                  读取线程类定义                                                    
************************************************************************/
CComPort::CReadComThread::CReadComThread(CComPort *pComPort):
m_pComPort(pComPort),
m_hThread(NULL),
m_bExit(FALSE)
{
   ZeroMemory(m_InputBuf, sizeof(m_InputBuf));
}

CComPort::CReadComThread::~CReadComThread()
{

}

BOOL CComPort::CReadComThread::Create(DWORD dwCreateFlags /* = 0 */,UINT nStackSize /* = 0 */,LPSECURITY_ATTRIBUTES lpSecurityAttrs /* = NULL */)
{
    m_hThread = CreateThread(lpSecurityAttrs, nStackSize, ThreadProc, this, dwCreateFlags, NULL);
	if (NULL == m_hThread)
	{
		return FALSE;
	}
	m_bExit = FALSE;
	return  TRUE;
}

void CComPort::CReadComThread::Resume()
{
   ASSERT(m_hThread);
   ResumeThread(m_hThread);
}

void CComPort::CReadComThread::Suspend()
{
   ASSERT(m_hThread);
   SuspendThread(m_hThread);
}

void CComPort::CReadComThread::Exit()
{
	 ASSERT(m_pComPort && m_hThread);

	 m_bExit = TRUE;
	 m_pComPort->SetEvent(0);
	
     if (m_pComPort->m_bOverlapped)
	 {
		 ::SetEvent(m_pComPort->m_WaitOverlapped.hEvent);
	 }
     WaitForSingleObject(m_hThread, INFINITE);
	 CloseHandle(m_hThread);
	 m_hThread = NULL;
}

DWORD WINAPI CComPort::CReadComThread::ThreadProc(LPVOID lpParam)
{
	TRACE("ReadThread is runing... \r\n");

	CReadComThread* pThis = (CReadComThread*)lpParam;
    CComPort* pComPort = pThis->m_pComPort;
	pComPort->SetEvent(DEFAULT_EVENT_MASK);

	for (DWORD dwMask = 0; !pThis->m_bExit; dwMask = 0)
	{
		if (!pComPort->WaitEvent(dwMask))
		{
			continue;
		}
		if (0 == dwMask)
		{
			continue;
		}

		switch (dwMask)
		{
		case EV_RXCHAR:
			{
				DWORD dwReadSize = pComPort->ReadComm(pThis->m_InputBuf,sizeof(pThis->m_InputBuf), INFINITE);
				pThis->m_InputBuf[dwReadSize] = '\0';
				pComPort->OnReceive(pThis->m_InputBuf, dwReadSize);
			}
			break;

		case EV_TXEMPTY:
			{
				
			}

		case EV_CTS :
			{
				
			}
			break;

		case EV_DSR :
			{
				
			}
			break;

		case EV_RING :
			{
				
			}
			break;

		case EV_RLSD :
			{
			
			}
			break;

		case EV_BREAK:
			{
			
			}
			break;

		case EV_ERR :
			{
			
			}
			break;
		}

	}


	TRACE("ReadThread is exit... \r\n");

	return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -