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

📄 pserialport.cpp

📁 本程序在serialport的基础上修改. 1. 加强了串口发送纠错能力
💻 CPP
字号:
// PSerialPort.cpp: implementation of the CPSerialPort class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "SerialPort.h"
#include "PSerialPort.h"

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

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CPSerialPort::CPSerialPort()
{
	m_hComm=INVALID_HANDLE_VALUE;
	m_hReadThread=NULL;
	m_bReceiving=FALSE;
	m_nBufferSize=256; //缓冲大小
}

CPSerialPort::~CPSerialPort()
{
	ClosePort();
}

/* 事件驱动
//串口读线程函数
DWORD CCESeries::ReadThreadFunc(LPVOID lparam)
{
	CCESeries *ceSeries = (CCESeries*)lparam;
	
	DWORD	evtMask;
	BYTE * readBuf = NULL;//读取的字节
	DWORD actualReadLen=0;//实际读取的字节数
	DWORD willReadLen;
	
	DWORD dwReadErrors;
	COMSTAT	cmState;
	
	// 清空缓冲,并检查串口是否打开。
	ASSERT(ceSeries->m_hComm !=INVALID_HANDLE_VALUE); 
	
	
	//清空串口
	PurgeComm(ceSeries->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR );
	
	SetCommMask (ceSeries->m_hComm, EV_RXCHAR | EV_CTS | EV_DSR );
	while (TRUE)
	{   	
		if (WaitCommEvent(ceSeries->m_hComm,&evtMask,0))
		{			
			SetCommMask (ceSeries->m_hComm, EV_RXCHAR | EV_CTS | EV_DSR ); //此句可省略
			//表示串口收到字符		
			if (evtMask & EV_RXCHAR) 
			{
				
				ClearCommError(ceSeries->m_hComm,&dwReadErrors,&cmState);
				willReadLen = cmState.cbInQue ;
				if (willReadLen <= 0)
				{
					continue;
				}
				
				readBuf = new BYTE[willReadLen];
				ReadFile(ceSeries->m_hComm, readBuf, willReadLen, &actualReadLen,0);
				
				//如果读取的数据大于0,
				if (actualReadLen>0)
				{
					//触发读取回调函数 ,将所读内容显示在方框中
					ceSeries->m_OnSeriesRead(ceSeries->m_pPortOwner,readBuf,actualReadLen);
				}
			}
		}
		//如果收到读线程退出信号,则退出线程
		if (WaitForSingleObject(ceSeries->m_hReadCloseEvent,500) == WAIT_OBJECT_0)
		{
			break;
		}
	}
	return 0;
}
//*/


DWORD WINAPI CPSerialPort::ReadPortThread(LPVOID lpParameter)  //参数指向串口类
{
	DWORD evtMask;		//事件驱动变量WaitCommEvent()用
	DWORD dwReadErrrors; //保存出错状态用
	COMSTAT cmState;

	CPSerialPort* m_pSerial;

	m_pSerial=(CPSerialPort*)lpParameter;


	if(m_pSerial->m_hComm!=INVALID_HANDLE_VALUE)  
	{	
		PurgeComm(m_pSerial->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR ); //清空串口
		SetCommMask (m_pSerial->m_hComm, EV_RXCHAR);				//设置响应事件
	}


	while((m_pSerial->m_hComm!=INVALID_HANDLE_VALUE)&&(m_pSerial->m_bReceiving))
	{	
		if(WaitCommEvent(m_pSerial->m_hComm,&evtMask,NULL))  //等接收信号
		{	//有数据
			ClearCommError(m_pSerial->m_hComm,&dwReadErrrors,&cmState);	//清错误并查询,保证下一次的waitcommEvent();
			m_pSerial->ReceiveChar(m_pSerial,cmState);  //读数据
		}
	}

	return 0;
}


//读并保存串口数据
void CPSerialPort::ReceiveChar(CPSerialPort *port, COMSTAT comstat)
{
	BOOL bResult=TRUE;
	DWORD dwError=0;
	DWORD dwWantRead;

	BOOL fReadState;
	DWORD dwLength;

	char* buf=new char[port->m_nBufferSize];  //生成缓存区
	
	for(;;)  //读数
	{
		bResult=ClearCommError(port->m_hComm,&dwError,&comstat);

		if(comstat.cbInQue==0 || !port->m_bReceiving) //无数据或按退出则退出程序
		{
			break;	//返回
		}
		//确定读数长度
		if(comstat.cbInQue<9)	dwWantRead=9;//小于9个字符
		else					dwWantRead=comstat.cbInQue;		
		if(dwWantRead> (DWORD)port->m_nBufferSize) dwWantRead=port->m_nBufferSize;

		fReadState=ReadFile(port->m_hComm,buf,dwWantRead,&dwLength,NULL);

		if(!fReadState)
		{
			//AfxMessageBox(_T("无法从串口读取数据!"));
		}
		else
		{
			if(dwLength!=0)
			{
				//回送数据
				if(port->m_lpDataArriveProc!=NULL)
				{
					port->m_lpDataArriveProc(buf,dwLength,port->m_dwUserData);
				}
			}	
		}	
	}
	delete[] buf;
}



BOOL CPSerialPort::OpenPort(LPCTSTR Port,int BaudRate,int DataBits,int StopBits,int Parity,LPDataArriveProc proc,DWORD userdata)
{
	m_lpDataArriveProc=proc;	//接收线程用的回调函数
	m_dwUserData=userdata;		//用户参数(指向调用OpenPort()的窗口

	if(m_hComm==INVALID_HANDLE_VALUE)
	{
		m_hComm=CreateFile(Port,GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,0,0); //打开串口
		if(m_hComm==INVALID_HANDLE_VALUE )
		{
			AfxMessageBox(_T("无法打开端口!请检查是否已被占用。"));
			return FALSE;
		}
		GetCommState(m_hComm,&dcb);
		dcb.BaudRate=BaudRate;
		dcb.ByteSize=DataBits;
		dcb.Parity=Parity;
		dcb.StopBits=StopBits;
		dcb.fParity=FALSE;
		dcb.fBinary=TRUE;
		dcb.fDtrControl=0;
		dcb.fRtsControl=0;
		dcb.fOutX=dcb.fInX=dcb.fTXContinueOnXoff=0;
		
		//设置状态参数
		SetCommMask(m_hComm,EV_RXCHAR);	//设置"接收到一个字符"事件	
		SetupComm(m_hComm,16384,16384);	//设置接收,发送缓存大小为16384byte	
		if(!SetCommState(m_hComm,&dcb)) //将设置的参数写入串口
		{
			AfxMessageBox(_T("无法按当前参数配置端口,请检查参数!"));
			PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR); //清除串口发送接收
			ClosePort();				//关闭
			return FALSE;
		}
		
		//设置超时参数
		GetCommTimeouts(m_hComm,&CommTimeOuts);		
		CommTimeOuts.ReadIntervalTimeout=100;		//查询方式读数时的时间间隔
		CommTimeOuts.ReadTotalTimeoutMultiplier=1;  //读一个字节时的时间超时上限
		CommTimeOuts.ReadTotalTimeoutConstant=100;	//总超时量
		CommTimeOuts.WriteTotalTimeoutMultiplier=0;
		CommTimeOuts.WriteTotalTimeoutConstant=0;		
		if(!SetCommTimeouts(m_hComm,&CommTimeOuts))  //写入串口
		{
			AfxMessageBox(_T("无法设置超时参数!"));
			PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR); //清除串口发送接收区
			ClosePort();
			return FALSE;
		}
		
		PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);		//清除串口发送接收区	
		return TRUE;		
	}
	
	return FALSE;
}

BOOL CPSerialPort::ClosePort()
{
	Deactivate();
	if(m_hComm!=INVALID_HANDLE_VALUE)
	{
		SetCommMask(m_hComm,0);	 //清事件	
		PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR); //清除串口发送接收区
		CloseHandle(m_hComm);
		m_hComm=INVALID_HANDLE_VALUE;
		return TRUE;
	}
	
	return TRUE;	
}

BOOL CPSerialPort::Activate()
{
	if(m_hComm==INVALID_HANDLE_VALUE)
	{
		return FALSE;
	}

	if(!m_bReceiving)
	{
		//开始接收线程
		PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);
		m_bReceiving=TRUE;
		m_hReadThread=CreateThread(NULL,0,ReadPortThread,this,0,NULL);
	}
	if(m_hReadThread!=NULL)
	{		
		return TRUE;
	}
	else
	{
		m_bReceiving=FALSE;
		return FALSE;
	}

	return FALSE;
}

BOOL CPSerialPort::Deactivate()
{
	if(m_hComm==INVALID_HANDLE_VALUE)
	{
		return FALSE;
	}

	//停止接收线程
	if(m_bReceiving)
	{
		m_bReceiving=FALSE;  //关串口读数线程
		SetCommMask(m_hComm,0);	//退出等待线程
		
		WaitForSingleObject(m_hReadThread,1000);
		CloseHandle(m_hReadThread);
		m_hReadThread=NULL;
		return TRUE;
	}

	return FALSE;
}

BOOL CPSerialPort::IsActive()
{
	return m_bReceiving;
}

DWORD CPSerialPort::WritePort(char *data,int length)
{
	DWORD fg;
	COMSTAT cmstat;
	if(m_hComm==INVALID_HANDLE_VALUE)
	{
		return 0;
	}
	ClearCommError(m_hComm,&fg,&cmstat); //清错并查询状态
	BOOL fWriteState;
	DWORD dwBytesWritten=0;

	fWriteState=WriteFile(m_hComm,data,length*sizeof(char),&dwBytesWritten,NULL);
	
	return dwBytesWritten;
}

DWORD CPSerialPort::ReadPort(char *data,int length)
{
	BOOL fReadState;
	DWORD dwLength,dwBytesRead;
	int TimeOutCount;

	dwBytesRead=0;
	TimeOutCount=0;
	
	while(m_hComm!=INVALID_HANDLE_VALUE)
	{
		char* buf=new char[length];
		fReadState=ReadFile(m_hComm,data,length,&dwLength,NULL);
		if(!fReadState)
		{
			break;
		}
		else
		{
			dwBytesRead+=dwLength;
			data+=dwLength;			
		}
		if(dwBytesRead==(DWORD)length)
		{
			break;
		}
		if(dwLength!=0)
		{
			TimeOutCount=0;
		}
		else
		{
			TimeOutCount++;
			Sleep(5);
		}
		if(TimeOutCount==5)
		{
			break;
		}
	}
	return dwBytesRead;
}

DWORD CPSerialPort::WriteFileToPort(LPCTSTR FileName)
{
	if(m_hComm==INVALID_HANDLE_VALUE)
	{
		return 0;
	}

	CFile cf;

	BOOL fWriteState;
	DWORD dwBytesWritten;
	DWORD dwCharToWrite;

	dwCharToWrite=0;

	if(!cf.Open(FileName,CFile::modeRead))
	{
		//AfxMessageBox(_T("无法打开Hex文件!"));
		return 0;
	}
	dwCharToWrite=(DWORD)cf.GetLength();
	cf.Seek(0,CFile::begin);
	dwBytesWritten=0;
	
	if(m_hComm!=INVALID_HANDLE_VALUE&&dwCharToWrite!=0)
	{
		char* buf=new char[dwCharToWrite];
		cf.Read(buf,dwCharToWrite);

		fWriteState=WriteFile(m_hComm,buf,dwCharToWrite*sizeof(char),&dwBytesWritten,NULL);
		if(!fWriteState)
		{
			//AfxMessageBox(_T("无法向端口写入数据!"));
		}
		delete[] buf;		
	}
	cf.Close();
	return dwBytesWritten;
}

⌨️ 快捷键说明

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