基本信息
源码名称:c++ 串口通信
源码大小:12.55M
文件格式:.rar
开发语言:C/C++
更新时间:2020-11-26
   友情提示:(无需注册或充值,赞助后即可获取资源下载链接)

     嘿,亲!知识可是无价之宝呢,但咱这精心整理的资料也耗费了不少心血呀。小小地破费一下,绝对物超所值哦!如有下载和支付问题,请联系我们QQ(微信同号):813200300

本次赞助数额为: 2 元 
   源码介绍


#include "StdAfx.h"
#include "SerialComm.h"


CSerialComm::CSerialComm(void)
{
	m_recvData = "";
	m_bConnected = FALSE;
	m_pThread = NULL;
}

CSerialComm::~CSerialComm(void)
{
	if(m_bConnected)             //程序结束时删除线程、关闭串口操作
		closeConnection();

	if(m_hPostMsgEvent)         //删除事件句柄
		CloseHandle(m_hPostMsgEvent);

	if(m_osRead.hEvent)
		CloseHandle(m_osRead.hEvent);

	if(m_osWrite.hEvent)
		CloseHandle(m_osWrite.hEvent);
}

BOOL CSerialComm::openConnection(CString commno, UINT8 baud, UINT8 datalen, UINT8 stopbit, UINT8 parity)
{
	if((baud > COMM_BAUD_115200) || 
	   (datalen > COMM_DATA_LEN_8) || 
	   (stopbit > COMM_STOP_BIT_2) || 
	   (parity > COMM_SPACE_PARITY))
	{
		m_bConnected = FALSE;
		AfxMessageBox(_T("串口参数设置错误"));

		return FALSE;
	}

	m_hPostMsgEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
	if(m_hPostMsgEvent == NULL)
		return FALSE;

	memset(&m_osRead, 0, sizeof(OVERLAPPED));
	memset(&m_osWrite, 0, sizeof(OVERLAPPED));

	m_osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);  //为重叠读创建事件对象,手工重置,初始化为无信号
	if(m_osRead.hEvent == NULL)
		return FALSE;

	m_osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //为重叠写创建事件对象,手工重置,初始化为无信号
	if(m_osWrite.hEvent == NULL)
		return FALSE;

	m_hComm = CreateFile(commno,                             //打开串口
		                 GENERIC_READ | GENERIC_WRITE,       //允许对设备进行读写访问
						 0,                                  //独占方式
						 NULL,                               //
						 OPEN_EXISTING,                      //打开而不是创建
						 FILE_FLAG_OVERLAPPED,               //使用异步通信
						 NULL);
	if(m_hComm == (HANDLE)-1)
	{
		m_bConnected = FALSE;
		AfxMessageBox(_T("打开串口失败"));
		
		return FALSE;
	} else
	{
		SetupComm(m_hComm, MAXBLOCK, MAXBLOCK);              //输入缓冲区和输出缓冲区的大小都是1024
		SetCommMask(m_hComm, EV_RXCHAR | EV_TXEMPTY );       //设置事件驱动的类型		
		
		COMMTIMEOUTS TimeOuts;
		TimeOuts.ReadIntervalTimeout = MAXDWORD;             //时间间隔设为最大,设为0会导致ReadFile立即返回并完成操作
		TimeOuts.ReadTotalTimeoutMultiplier = 0;
		TimeOuts.ReadTotalTimeoutConstant = 0;

		TimeOuts.WriteTotalTimeoutMultiplier = 50;           //设置写超时用于GetOverlapperResult函数的等待时间
		TimeOuts.WriteTotalTimeoutConstant = 2000;
		SetCommTimeouts(m_hComm, &TimeOuts);                 //设置超时

		//PurgeComm(m_hComm, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ); //清干净输入、输出缓冲区

		if(!configureConnection(commno, baud, datalen, stopbit, parity))
		{
			CloseHandle(m_hComm);
			return FALSE;
		}

		return TRUE;
	}
}

BOOL CSerialComm::configureConnection(CString commno, UINT8 baud, UINT8 datalen, UINT8 stopbit, UINT8 parity)
{
	DCB dcb;
	if(!GetCommState(m_hComm, &dcb))           //读串口原来的参数设置
		return false;

	switch(baud)                               //波特率
	{
	case COMM_BAUD_2400:
		dcb.BaudRate = 2400;
		break;
	case COMM_BAUD_4800:
		dcb.BaudRate = 4800;
		break;
	case COMM_BAUD_9600:
		dcb.BaudRate = 9600;
		break;
	case COMM_BAUD_19200:
		dcb.BaudRate = 19200;
		break;
	case COMM_BAUD_38400:
		dcb.BaudRate = 38400;
		break;
	case COMM_BAUD_115200:
		dcb.BaudRate = 115200;
		break;
	default:
		break;
	}

	switch(datalen)                          //字节数
	{
	case COMM_DATA_LEN_5:
		dcb.ByteSize = 5;
		break;
	case COMM_DATA_LEN_6:
		dcb.ByteSize = 6;
		break;
	case COMM_DATA_LEN_7:
		dcb.ByteSize = 7;
		break;
	case COMM_DATA_LEN_8:
		dcb.ByteSize = 8;
		break;
	default:
		break;
	}

	switch(stopbit)                        //停止位
	{
	case COMM_STOP_BIT_1:
		dcb.StopBits = ONESTOPBIT;
		break;
	case COMM_STOP_BIT_1_5:
		dcb.StopBits = ONE5STOPBITS;
		break;
	case COMM_STOP_BIT_2:
		dcb.StopBits = TWOSTOPBITS;
		break;
	default:
		break;
	}

	switch(parity)                              //校验
	{
	case COMM_NONE_PARITY:
		dcb.Parity = NOPARITY;
		break;
	case COMM_ODD_PARITY:
		dcb.Parity = ODDPARITY;
		break;
	case COMM_EVEN_PARITY:
		dcb.Parity = EVENPARITY;
		break;
	case COMM_MARK_PARITY:
		dcb.Parity = MARKPARITY;
		break;
	case COMM_SPACE_PARITY:
		dcb.Parity = SPACEPARITY;
		break;
	default:
		break;
	}

	return SetCommState(m_hComm, &dcb);
}

void CSerialComm::closeConnection()
{
	if(!m_bConnected)
		return ;

	m_bConnected = FALSE;

	SetEvent(m_hPostMsgEvent);          //结束commProc线程中WaitSingleObject函数的等待
	SetCommMask(m_hComm, 0);            //结束commProc线程中WaitCommEvent的等待

	WaitForSingleObject(m_pThread->m_hThread, INFINITE);  //等待辅助线程终止
	m_pThread = NULL;

	CloseHandle(m_hComm);
}

DWORD CSerialComm::writeComm(char *buf, DWORD len)
{
	BOOL ret;
	DWORD length = len;
	DWORD errorflags;
	COMSTAT comstat;
	
	ClearCommError(m_hComm, &errorflags, &comstat);
	
	ret = WriteFile(m_hComm, buf, length, &length, &m_osWrite);
	if(!ret)
	{
		if(GetLastError() == ERROR_IO_PENDING)
		{
			GetOverlappedResult(m_hComm, &m_osWrite, &length, TRUE);    //等待
		} else
		{
			length = 0;
		}
	}

	return length;
}

DWORD CSerialComm::readComm(char *pbuf, DWORD len)
{
	DWORD length = 0;
	DWORD errorflags;
	COMSTAT comstat;

	ClearCommError(m_hComm, &errorflags, &comstat);

	length = min(len, comstat.cbInQue);
	ReadFile(m_hComm, pbuf, length, &length, &m_osRead);

	return length;
}

void CSerialComm::enumerateSerialPorts(CUIntArray& ports)
{
	//Make sure we clear out any elements which may already be in the array
	ports.RemoveAll();

	//Determine what OS we are running on
	OSVERSIONINFO osvi;
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	BOOL bGetVer = GetVersionEx(&osvi);

	//On NT use the QueryDosDevice API
	if (bGetVer && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT))
	{
		//Use QueryDosDevice to look for all devices of the form COMx. This is a better
		//solution as it means that no ports have to be opened at all.
		TCHAR szDevices[65535];
		DWORD dwChars = QueryDosDevice(NULL, szDevices, 65535);
		if (dwChars)
		{
			int i = 0;
			for ( ;; )
			{
				//Get the current device name
				TCHAR* pszCurrentDevice = &szDevices[i];
				//If it looks like "COMX" then
				//add it to the array which will be returned
				int nLen = _tcslen(pszCurrentDevice);
				if (nLen > 3 && _tcsnicmp(pszCurrentDevice, _T("COM"), 3) == 0)
				{
					//Work out the port number
					int nPort = _ttoi(&pszCurrentDevice[3]);
					ports.Add(nPort);
				}
				// Go to next NULL character
				while(szDevices[i] != _T('\0'))
					i  ;
				// Bump pointer to the next string
				i  ;
				// The list is double-NULL terminated, so if the character is
				// now NULL, we're at the end
				if (szDevices[i] == _T('\0'))
					break;
			}
		}
		else
			TRACE(_T("Failed in call to QueryDosDevice, GetLastError:%d\n"), GetLastError());
	}
	else
	{
		//On 95/98 open up each port to determine their existence
		//Up to 255 COM ports are supported so we iterate through all of them seeing
		//if we can open them or if we fail to open them, get an access denied or general error error.
		//Both of these cases indicate that there is a COM port at that number. 
		for (UINT i=1; i<256; i  )
		{
			//Form the Raw device name
			CString sPort;
			sPort.Format(_T("\\\\.\\COM%d"), i);

			//Try to open the port
			BOOL bSuccess = FALSE;
			HANDLE hPort = ::CreateFile(sPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
			if (hPort == INVALID_HANDLE_VALUE)
			{
				DWORD dwError = GetLastError();
				//Check to see if the error was because some other app had the port open or a general failure
				if (dwError == ERROR_ACCESS_DENIED || dwError == ERROR_GEN_FAILURE)
					bSuccess = TRUE;
			}
			else
			{
				//The port was opened successfully
				bSuccess = TRUE;
				//Don't forget to close the port, since we are going to do nothing with it anyway
				CloseHandle(hPort);
			}
			//Add the port number to the array which will be returned
			if (bSuccess)
				ports.Add(i);
		}
	}
}