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

📄 serialcomm.cpp

📁 可实现串口通信的DLL文件源码.通信速度快,易调试,占用系统资源少,非常实用.
💻 CPP
字号:
#include "stdafx.h"


CSerialComm::CSerialComm(LPCTSTR xComName,CommPortSettings xPortSettings)
{
	mPortName = xComName;	
	mPortSettings = xPortSettings;
	mPortStatus.dwrError = 0;
	mPortStatus.dwwError = 0;
	mPortStatus.dwOpen = 0;//没有打开

	mPortStatus.dwrecvbytesLimit = 1;
	mdwStoredFlags = EV_ERR | EV_RXCHAR;
	mdwCommEvent = 0;

	ZeroMemory(mrecvBuf,InOutBufferSize);//初始化接收缓冲区
	mrecvBytesNum = 0;

	ZeroMemory(&mosRead,sizeof(OVERLAPPED));//用于重叠读/写
    ZeroMemory(&mosWrite,sizeof(OVERLAPPED));
    ZeroMemory(&mosStatus,sizeof(OVERLAPPED));

	mPortStatus.hReadEvent = CreateEvent(NULL,TRUE,FALSE,NULL);   //手工初始无信号

	mosRead.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);   //手工初始无信号
    mosStatus.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); //手工初始无信号

	mosWrite.hEvent = CreateEvent(NULL,TRUE,TRUE,NULL); //手工初始有信号
	
	mhCom=CreateFile(mPortName.c_str(),GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,NULL);
	if(mhCom == INVALID_HANDLE_VALUE)//打开端口错误
    {
        mPortStatus.dwwError = GetLastError( );
		mPortStatus.dwrError = mPortStatus.dwwError;
    }
	else //打开端口正确
	{
		mPortStatus.dwOpen = 1;//表示串口已打开
		SetupComm(mhCom,InOutBufferSize,InOutBufferSize);//设置缓冲区大小

		mcommTimeOuts.ReadIntervalTimeout = MAXDWORD;
		mcommTimeOuts.ReadTotalTimeoutConstant = 1200;//If no character arrives within the time specified by ReadTotalTimeoutConstant, ReadFile times out.
		mcommTimeOuts.ReadTotalTimeoutMultiplier = MAXDWORD;
		mcommTimeOuts.WriteTotalTimeoutConstant = 1000;
		mcommTimeOuts.WriteTotalTimeoutMultiplier = 50;
		SetCommTimeouts(mhCom,&mcommTimeOuts);//设置超时

		FillMemory(&mDCB,sizeof(DCB),0);
		GetCommState(mhCom,&mDCB);
		mDCB.BaudRate = mPortSettings.BaudRate;
		mDCB.ByteSize = mPortSettings.ByteSize;
        mDCB.Parity   = mPortSettings.Parity;
        mDCB.StopBits = mPortSettings.StopBits;
		SetCommState(mhCom,&mDCB);//设置串口通信参数

		SetCommMask(mhCom,mdwStoredFlags);//设置事件屏蔽
	}
	//---------------------------------创建读线程
	if(mPortStatus.dwwError == 0)
	{
		mbReadFlag  = TRUE;//线程运行标志
		mhReadThread  = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ReadThread,(LPVOID)this,CREATE_SUSPENDED,&mdwReadThreadId);
        ResumeThread(mhReadThread);
	}
	//---------------------------------Initialize the critical section one time only.
    InitializeCriticalSection(&CriticalSection);
}

DWORD CSerialComm::ReadComm(BYTE* xBuffer,DWORD xLength) //从缓冲区中读入指定数量的字符
{
    DWORD tmLength = 0;	
	EnterCriticalSection(&CriticalSection); 
	//----------------------------------
	tmLength = min(xLength,mrecvBytesNum);
	if(tmLength > 0)
	{
		CopyMemory(xBuffer,mrecvBuf,tmLength);
	}
	//----------------------------------
	LeaveCriticalSection(&CriticalSection);
	return tmLength;
}

BOOL CSerialComm::WriteComm(BYTE* xBuffer,DWORD xLength) //把指定数量的字符(字节)从串口中输出
{
	BOOL    tmRes = TRUE;
	BOOL    tmfState = TRUE;
	DWORD   tmLength = 0;
	COMSTAT tmComStat;
	DWORD   tmErrorFlags;

	mPortStatus.dwwError = 0;
	//--------------------------------
	tmfState = GetOverlappedResult(mhCom,&mosWrite,&tmLength,FALSE);  //等待上一次操作的完成
	if(!tmfState)
	{
		mPortStatus.dwwError = GetLastError();
		if(mPortStatus.dwwError == ERROR_IO_INCOMPLETE)  //上次写操作还没有完成
		{
			tmRes = FALSE;//不能进行该次写操作
		}
		return tmRes;
	}
	//---------------------------------
	ResetEvent(mosWrite.hEvent);//重置为无信号
	ClearCommError(mhCom,&tmErrorFlags,&tmComStat);//clears the device's error flag to enable next input and output (I/O) operations.

	tmfState = WriteFile(mhCom,xBuffer,xLength,&tmLength,&mosWrite);
	if(!tmfState)  //写操作没有完成
	{
		mPortStatus.dwwError = GetLastError();
		if( mPortStatus.dwwError == ERROR_IO_PENDING)  //写操作正在进行(write is pending)
		{
		    tmRes = TRUE;	
		}
		else 
		{
			tmRes = FALSE;//写操作失败
		}
	}
	else
	{		
		tmRes = TRUE;//write operation completed immediately
	}
	//---------------------------------
	return tmRes;
}

CSerialComm::~CSerialComm()
{
	//---------------------------------退出线程
	SetCommMask(mhCom,0);//不再等待任何事件
	mbReadFlag = FALSE;
	WaitForSingleObject(mhReadThread,INFINITE);//等待线程结束
	CloseHandle(mhReadThread);
    //---------------------------------	
	if(mPortStatus.dwOpen == 1)
	{
		CloseHandle(mosRead.hEvent);
        CloseHandle(mosWrite.hEvent);
        CloseHandle(mosStatus.hEvent);
        CloseHandle(mPortStatus.hReadEvent);
        
		CloseHandle(mhCom);
	}
	//---------------------------------
	DeleteCriticalSection(&CriticalSection);//Release resources used by the critical section object.
}

//==============================================================================================读过程
DWORD WINAPI ReadThread(LPVOID xpParam)
{
	DWORD tmdwRes = 0;
	DWORD tmdwRead;
	DWORD tmError = 0;
	BOOL  tmbWaitingOnStatus = FALSE;
	COMSTAT tmComStat;
	CSerialComm* mpCSerialComm = (CSerialComm*)xpParam;

	mpCSerialComm->mPortStatus.dwrError = 0;
	while(mpCSerialComm->mbReadFlag)  //读数据循环
	{
		if(!tmbWaitingOnStatus)
		{
            if(!WaitCommEvent(mpCSerialComm->mhCom,&(mpCSerialComm->mdwCommEvent),&(mpCSerialComm->mosStatus))) //重叠等待
			{
				tmError = GetLastError();
				if(tmError == ERROR_IO_PENDING)//the operation is executing in the background
			    {
					tmbWaitingOnStatus = TRUE;
				}
				else  //error in WaitCommEvent,clear
				{
					mpCSerialComm->mPortStatus.dwrError = tmError;
					ClearCommError(mpCSerialComm->mhCom,&tmError,&tmComStat);
					if(tmComStat.cbInQue > 0)  //清理输入缓冲
					{
						PurgeComm(mpCSerialComm->mhCom,PURGE_RXCLEAR);
					}
                    ::Sleep(1000);
				}
			}
			else  //WaitCommEvent returned immediately
            {
                tmbWaitingOnStatus = FALSE;
                ReportStatusEvent(mpCSerialComm);
            }
		}
		//------------------------------check on overlapped operation
		if(tmbWaitingOnStatus)
		{
			tmdwRes = WaitForSingleObject(mpCSerialComm->mosStatus.hEvent,STATUS_CHECK_TIMEOUT);
			switch(tmdwRes)
            {
			case WAIT_OBJECT_0://mosStatus.hEvent is signaled.
                {
                    if(!GetOverlappedResult(mpCSerialComm->mhCom,&(mpCSerialComm->mosStatus),&tmdwRead,FALSE))
                    {
                        tmError = GetLastError();// For a WaitCommEvent operation, tmdwRead value is undefined.
                        if(tmError != ERROR_IO_INCOMPLETE)  //WaitCommEvent operation failed
                        {
							mpCSerialComm->mPortStatus.dwrError = tmError;
							ClearCommError(mpCSerialComm->mhCom,&tmError,&tmComStat);
							if(tmComStat.cbInQue > 0)  //清理输入缓冲
                            {
                                PurgeComm(mpCSerialComm->mhCom,PURGE_RXCLEAR);
                            }
                            Sleep(1000);
							tmbWaitingOnStatus = FALSE;//应该进行下一个WaitCommEvent
						}
                    }
                    else  //a new WaitCommEvent can be issued
					{
						tmbWaitingOnStatus = FALSE;
						ReportStatusEvent(mpCSerialComm);                        
					}					
				}
				break;
			case WAIT_TIMEOUT:
				{	
					ClearCommError(mpCSerialComm->mhCom,&tmError,&tmComStat);
					PurgeComm(mpCSerialComm->mhCom,PURGE_RXCLEAR);//清理输入缓冲(完整数据传输必须在一定的时间内到达)
					Sleep(1000);
					tmbWaitingOnStatus = FALSE;//应该进行下一个WaitCommEvent
				}
				break;
			default://Error in WaitForSingleObject;a problem with the mosStatus.hEvent
				{
					ClearCommError(mpCSerialComm->mhCom,&tmError,&tmComStat);
					if(tmComStat.cbInQue > 0)  //清理输入缓冲
                    {
                        PurgeComm(mpCSerialComm->mhCom,PURGE_RXCLEAR);
                    }
					mpCSerialComm->mPortStatus.dwrError = GetLastError();
					Sleep(1000);
					tmbWaitingOnStatus = FALSE;//应该进行下一个WaitCommEvent
				}
			}
		}
	}
	//---------------------------------
	return tmdwRes;
}

void ReportStatusEvent(LPVOID xpParam)   //辅助过程
{
	DWORD tmError = 0;
	COMSTAT tmComStat;

	CSerialComm* mpCSerialComm = (CSerialComm*)xpParam;
	if(!ClearCommError(mpCSerialComm->mhCom,&tmError,&tmComStat))
	{
		mpCSerialComm->mPortStatus.dwrError = GetLastError();
	}
	else
	{
		if((mpCSerialComm->mdwCommEvent) & EV_RXCHAR)
		{
            if(tmComStat.cbInQue >= (mpCSerialComm->mPortStatus.dwrecvbytesLimit))
            {
                EnterCriticalSection(&(mpCSerialComm->CriticalSection)); 
                ReadFile(mpCSerialComm->mhCom,mpCSerialComm->mrecvBuf,InOutBufferSize,&(mpCSerialComm->mrecvBytesNum),&(mpCSerialComm->mosRead));
				SetEvent(mpCSerialComm->mPortStatus.hReadEvent);//置为有信号状态,在外部将其置为无信号状态
                LeaveCriticalSection(&(mpCSerialComm->CriticalSection));
            }
		}
		else
		{
			mpCSerialComm->mPortStatus.dwrError = EV_ERR;
		}
	}
}	

⌨️ 快捷键说明

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