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

📄 multithreadserial.cpp

📁 多线程串口通信的例子,可以实现同时多串口的通信
💻 CPP
字号:
/*****************************************************************
  ||文件 : MultiThreadSerial.cpp(多线程串口通信类)
  ||编者 : 许伟群 
  ||EMail: xuweiqun@126.com
  ||QQ   : 12626946
  ||日期 : 2004-05
  ||修改 : 2005-09
  ||使用 :
  ||       1、设置DCB 
  ||          最好使用简单设置(4个主要参数)SetDCB(int nBaudRate,int nDataBit,int nCheckBit,int nStopBit );
  ||          也可以自定义设置SetDCB(DCB dcb)(对各个变量不熟悉,自定义很容易出错)
  ||          不设置默认为:波特率9600  数据位8  偶校验  停止位1
  ||       2、初使化串口InitComm(传入串口号和窗口句柄m_hWnd)
  ||       3、BeginComm启动串口接收数据的线程
  ||       4、当串口收到数据,向m_hWnd发送WM_ACTIVE_TRANS消息,并且发送了串口号
  ||          在消息处理函数中处理数据(通过串口号判断是哪个串口对象来接收数据)
  ||		  然后调用ReceiveData函数接收数据.
  ||	   5、写数据通过WriteComm函数
******************************************************************/
#include "stdafx.h"
#include "MultiThreadSerial.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

MultiThreadSerial::MultiThreadSerial()
{
	m_bCommConnected = false;//端口连接标志
	memset(m_sRtnData,0x00,sizeof(m_sRtnData));
	m_bComIsOpen = false;
	bCommRxSign = false;

	//默认DCB设置
	m_nBaudRate  = CBR_9600 ;
	m_nDataBit   = 8;
	m_nCheckBit  = EVENPARITY;
	m_nStopBit   = ONESTOPBIT;

	m_DCB.DCBlength = sizeof(DCB);
	m_DCB.BaudRate  = m_nBaudRate;
	m_DCB.ByteSize  = m_nDataBit;
	m_DCB.Parity    = m_nCheckBit;
	m_DCB.StopBits  = m_nStopBit;
	m_DCB.fOutxDsrFlow = false;
    m_DCB.fOutxCtsFlow = false;
    m_DCB.fDtrControl = RTS_CONTROL_DISABLE;
    m_DCB.fRtsControl = RTS_CONTROL_DISABLE;
    m_DCB.fInX = false;
    m_DCB.fOutX = false;
    m_DCB.fBinary = TRUE;
    m_DCB.fParity = TRUE;
	//m_DCB.wReserved  = 0;

}
MultiThreadSerial::~MultiThreadSerial()
{

}
UINT jThreadFunction(LPVOID lpParam) 
{
	//线程函数主体,监视串口
    
	//AfxMessageBox("进入线程");                           //测试

	MultiThreadSerial *pComm = ( MultiThreadSerial*)lpParam;
	OVERLAPPED os;
	DWORD dwEventMask, dwTransfer;
	DWORD dwErrorFlags;
	COMSTAT ComStat;
	memset(&os, 0, sizeof(OVERLAPPED));
	os.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //FALSE: nonsignaled
	if (os.hEvent == NULL)
	{
		return FALSE;
	}
	if (!SetCommMask(pComm->m_hCom, EV_RXCHAR)) 
		return FALSE;
	//Loop until user requests disconnect
	while (pComm->ComIsConnected())
	{
		ClearCommError(pComm->m_hCom, &dwErrorFlags, &ComStat);
		if(ComStat.cbInQue) //有数据
		{
			//AfxMessageBox("进入COMSTAT");                           //测试
			pComm->bCommRxSign = true;
			ResetEvent(pComm->hPostMsgEvent);
			pComm->OnCommRecvNotify(0,1);
           
			WaitForSingleObject(pComm->hPostMsgEvent, 0xFFFFFFFF);
            //AfxMessageBox("waitforsingleobject");                           //测试
			continue;
		}
		dwEventMask = 0;
		if (!WaitCommEvent(pComm->m_hCom, &dwEventMask, &os))// dwEventMask: receive event
		{
			//WaitCommEvent()没有等到结果,如果ERROR_IO_PENDING == GetLastError()
			//就用GetOverlappedResult()来等待。
			if (ERROR_IO_PENDING == GetLastError())
			{
				//AfxMessageBox("进入等待");                           //测试
				GetOverlappedResult(pComm->m_hCom, &os, &dwTransfer, TRUE); //dwTransfer:actual bytes count
				//TRUE:If TRUE, the function does not return until the operation has been completed. 
			}
		}
		if ((dwEventMask & EV_RXCHAR) == EV_RXCHAR)
		{
			//Sets the state of the event to nonsignaled until explicitly set to signaled by the SetEvent member function. 
			pComm->bCommRxSign = true;
			ResetEvent(pComm->hPostMsgEvent);
			pComm->OnCommRecvNotify(0, 1);
			//AfxMessageBox("进入EventMask,等待事件");                           //测试
			WaitForSingleObject(pComm->hPostMsgEvent, 0xFFFFFFFF);	
		}
	}
	CloseHandle(os.hEvent);

	return TRUE;
}


bool MultiThreadSerial::InitComm(int nCom , HWND hWnd)
{
    m_hWnd = hWnd; //是主程序的窗口句柄,此参数必须传入,否则数据不能
    //响应到主程序中去
    m_nCom = nCom;

    CString    sCommPort;
    sCommPort.Format( "COM%d", m_nCom );
    HANDLE hCom;
    hCom= CreateFile(sCommPort, GENERIC_READ|GENERIC_WRITE, 0, NULL,
		OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
		NULL); //以重叠I/O的形式打开串口
    m_hCom = hCom;
    if(m_hCom == INVALID_HANDLE_VALUE)
	{

	    m_bComIsOpen=false;

	    return false;
	}
    SetupComm(m_hCom, COMM232GETDATAMAX, COMM232SENDDATAMAX);

    COMMTIMEOUTS CommTimeOuts;
    GetCommTimeouts(m_hCom, &CommTimeOuts);
    if(!SetCommMask(m_hCom, EV_RXCHAR))
	{
	    return false;
	}
    CommTimeOuts.ReadIntervalTimeout            =   MAXDWORD;
    CommTimeOuts.ReadTotalTimeoutMultiplier	    =	0;//20;
    CommTimeOuts.ReadTotalTimeoutConstant		=	0;//1000;
    CommTimeOuts.WriteTotalTimeoutMultiplier = 0;//20;
    CommTimeOuts.WriteTotalTimeoutConstant = 5000;//1000
    SetCommTimeouts(m_hCom, &CommTimeOuts);

 
    DCB dcb;
	dcb.DCBlength = sizeof(DCB);
    GetCommState(m_hCom, &dcb);
 
    dcb.BaudRate = m_DCB.BaudRate;
    dcb.ByteSize = m_DCB.ByteSize;
    dcb.Parity =   m_DCB.Parity;
    dcb.StopBits = m_DCB.StopBits;

    dcb.fOutxDsrFlow = m_DCB.fOutxDsrFlow;
    dcb.fOutxCtsFlow = m_DCB.fOutxCtsFlow;
    dcb.fDtrControl = m_DCB.fDtrControl;
    dcb.fRtsControl = m_DCB.fRtsControl;
    dcb.fInX = m_DCB.fInX;
    dcb.fOutX = m_DCB.fOutX;
    dcb.fBinary = m_DCB.fBinary;
    dcb.fParity = m_DCB.fParity;
    //dcb.wReserved  = 0;

    if(!SetCommState(m_hCom,&dcb))
	    return false;

    if((hPostMsgEvent = CreateEvent(NULL, TRUE, TRUE, NULL))==NULL) //有信号状态
	    return false;


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

    m_bComIsOpen = true;


    return true;
}

DWORD MultiThreadSerial::WriteComm(unsigned char *buf, DWORD dwLength)
{
	BOOL fState;
    DWORD l_dwRes; 
	DWORD length = dwLength;
	COMSTAT ComStat;
	DWORD dwErrorFlags = 0;
	OVERLAPPED  osWrite = {0} ; 
	if((osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL))==NULL)
	{
	    length = 0;
		//AfxMessageBox("Event失败");             //测试   :结果;没经过
		return length;
	}
	ClearCommError(m_hCom, &dwErrorFlags, &ComStat);
	fState = WriteFile(m_hCom, buf, length, &length, &osWrite);
	if(!fState)
	{
		if(GetLastError() == ERROR_IO_PENDING)
		{
				l_dwRes = WaitForSingleObject(osWrite.hEvent, INFINITE);
				switch(l_dwRes)
				{
					case WAIT_OBJECT_0:	
						if (!GetOverlappedResult(m_hCom, &osWrite, &length, FALSE))
						{
							length = 0;                 
						}
						else
						{
							 
							 return length;

						}
						break;            
					default:
						length = 0;
						break;  
				}
		}
		else
		length = 0;
	}
	return length;	
}

DWORD MultiThreadSerial::ReadComm(unsigned char *buf, DWORD dwLength )
{
	DWORD length = 0;
	COMSTAT ComStat;
	DWORD dwErrorFlags;
	Sleep(250);

	ClearCommError(m_hCom, &dwErrorFlags, &ComStat);
	length = min(dwLength, ComStat.cbInQue);
	
	/////////////////////////////////////////////////////////////  测试  
	//   以下是自己添加代码: 为了解决ReadFile,如果不加ReadFile返回0,
	//  加代码,直到读完,返回 length
	////////////////////////////////////////////////////////////   测试
    OVERLAPPED  osRead = {0};

	BOOL l_bWaitingOnRead = FALSE;   //用来检测是否在读
	osRead.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL);
	if(osRead.hEvent == NULL)
	{
		return FAIL;
	}
    if(!ReadFile(m_hCom, buf, length, &length, &osRead))
	{
		if(GetLastError() != ERROR_IO_PENDING)
		{
			length = FAIL;
			//AfxMessageBox("读失败2,ReadFile");  //测试

		}
		else
		{
		       l_bWaitingOnRead = TRUE;
		}
	}
    else 
	{   
		
		return length;
	}
    
	DWORD l_dwRes;
    if(l_bWaitingOnRead)
    {
	   l_dwRes = WaitForSingleObject(osRead.hEvent, 10 * 1000);  
	   switch(l_dwRes)
	   {
		   case WAIT_OBJECT_0:	
				if (!GetOverlappedResult(m_hCom, &osRead, &length, FALSE))
				{
				   length = FAIL;
				}
		  	    else
				{
					return length;
				}
			    break;
		    default:
				length = FAIL;
	   }
	}
	CloseHandle(osRead.hEvent);
	return length;

}
/////////////////////////////////////////////////////////////
void MultiThreadSerial::CloseComm()
{
	m_bCommConnected = false;
   
	m_bComIsOpen=false;

	SetCommMask(m_hCom, 0);
	
    //Clears the DTR (data-terminal-ready) signal
	EscapeCommFunction(m_hCom, CLRDTR);
	//清除操作
	PurgeComm(m_hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
	
	CloseHandle(m_hCom);

	pThread = NULL;
	

}


bool MultiThreadSerial::BeginComm()
{
	if (!m_bComIsOpen) return false;
	m_bCommConnected = true;

	if((pThread = AfxBeginThread(jThreadFunction, this)) == NULL)
	{
		m_bCommConnected = false;
		CloseHandle(m_hCom);
		return false;
	}
	else	
	{
		//函数会建立一个辅助线程并暂时将其挂起。
		//调用CWinThread:: ResumeThread使线程开始运行
		pThread->SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
		pThread->ResumeThread();
		//AfxMessageBox("线程运行完了");                           //测试
		EscapeCommFunction(m_hCom, SETDTR);  //Sends the DTR (data-terminal-ready) signal.
	}

	return true;
}




//bool MultiThreadSerial::ChangeBaud()
//{
//	//此函数现在没有用到。
//	if(hCom==NULL)
//		return false;
//	COMMTIMEOUTS CommTimeOuts;
//	GetCommTimeouts(hCom, &CommTimeOuts);
//	if(!SetCommMask(hCom, EV_RXCHAR))
//	{
//		return false;
//	}
//	SetupComm(hCom, 4096, 4096);
//	CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
//	CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
//	CommTimeOuts.ReadTotalTimeoutConstant = 0;
//	CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
//	CommTimeOuts.WriteTotalTimeoutConstant = 5000;
//	SetCommTimeouts(hCom, &CommTimeOuts);
//
//	DCB Dcb;
//	Dcb.DCBlength = sizeof(DCB);
//	GetCommState(hCom,&Dcb);
//	Dcb.BaudRate=iBaud;
//	Dcb.ByteSize=8;
//	Dcb.Parity=EVENPARITY;
//	Dcb.StopBits=ONESTOPBIT;
//	Dcb.fOutxDsrFlow = false;
//	Dcb.fOutxCtsFlow = false;
//	Dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
//	Dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
//	Dcb.fInX = Dcb.fOutX = false;
//	//Dcb.XonChar = ASCII_XON;
//	//Dcb.XoffChar = ASCII_XOFF;
//	Dcb.XonLim = 100;
//	Dcb.XoffLim = 100;
//	Dcb.fBinary = TRUE;
//	Dcb.fParity = TRUE;
//	if(!SetCommState(hCom,&Dcb))
//		return false;
//	return true;
//}
void MultiThreadSerial::OnCommRecvNotify(WPARAM wParam, LPARAM lParam)
{
	//取得数据缓冲

	m_nCommGetCounter = ReadComm((unsigned char *)m_sCommGetBuffer,COMM232GETDATAMAX);
	if(m_nCommGetCounter == 0)
    { 
		SetEvent(hPostMsgEvent);   //根本就没有取到数据,所以返回
		return;
	}
	memset(m_sRtnData, 0x00, sizeof(m_sRtnData)); //每一次都必须初始化
    memcpy(m_sRtnData, m_sCommGetBuffer, m_nCommGetCounter*sizeof(BYTE)); 
	memset(m_sCommGetBuffer, 0x00, COMM232GETDATAMAX * sizeof(BYTE)); //清空接收缓冲

	//提示接收数据,将串口号传送出去,以便判断哪个串口接收了数据
    ::SendMessage(m_hWnd, WM_ACTIVE_TRANS, m_nCom, 0);
	Sleep(20);
	//允许发送下一个WM_COMMNOTIFY消息
	SetEvent(hPostMsgEvent); 
 
}

void MultiThreadSerial::SetDCB(DCB dcb)
{
	ZeroMemory(&m_DCB,sizeof(DCB));
    memcpy(&m_DCB,&dcb,sizeof(DCB));
}

void MultiThreadSerial::SetDCB(int nBaudRate,int nDataBit,int nCheckBit,int nStopBit)
{
	///////////////设置波特率
	m_nBaudRate    = nBaudRate;
	m_DCB.BaudRate = nBaudRate;

	////////////////设置数据位
	m_nDataBit     = nDataBit;
	m_DCB.ByteSize = nDataBit;
	
	/////////////////设置校验位
	m_nCheckBit    = nCheckBit;
	m_DCB.Parity   = nCheckBit;  
	
	/////////////////设置停止位
	m_nStopBit     = nStopBit;
	m_DCB.StopBits = nStopBit;

}

//////////取得串口号
int MultiThreadSerial::GetComNum()
{
	return m_nCom;
}
//////////取得速率
int  MultiThreadSerial::GetBaudRate()
{        
	return m_nBaudRate;

}

//////取得数据位
int  MultiThreadSerial::GetDataBit()
{
	return m_nDataBit;
}
///////////取得校验位
int  MultiThreadSerial::GetCheckBit()
{
	return m_nCheckBit;
}

///////取得停止位
int  MultiThreadSerial::GetStopBit()
{
	return m_nStopBit;
}


//串口是否打开
bool MultiThreadSerial::ComIsOpen()
{
	return m_bComIsOpen;
}

//线程是否启动
bool MultiThreadSerial::ComIsConnected()
{
	return m_bCommConnected;

}

void MultiThreadSerial::ReceiveData(BYTE* psz)
{
	memcpy(psz, m_sRtnData, sizeof(m_sRtnData));
}

⌨️ 快捷键说明

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