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

📄 cecomm.cpp

📁 windows CE下面的简单的串口调试工具
💻 CPP
字号:
//////////////////////////////////////////////////////////////////////
// CEComm.cpp: implementation of the CCEComm class.
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "CEComm.h"

//类CVCCom构造函数
CCEComm::CCEComm()
{
	m_hComm = INVALID_HANDLE_VALUE;
	m_pPortOwner = NULL;
	m_nPort = 0;
	
	m_hReadThread = NULL;
	m_hReadCloseEvent = NULL;
	m_hWriteThread = NULL;
	m_hWriteCloseEvent = NULL;

	m_nCloseDelayTime = 1000;
}

//类CVCCom析构函数
CCEComm::~CCEComm()
{
	ClosePort();
}




/*
*函数介绍:设置串口读取、写入超时
*入口参数:CommTimeOuts : 指向COMMTIMEOUTS结构
*出口参数:(无)
*返回值:TRUE:设置成功;FALSE:设置失败
*/
BOOL CCEComm::SetSeriesTimeouts(COMMTIMEOUTS* pCommTimeOuts)
{
	ASSERT(m_hComm != INVALID_HANDLE_VALUE);
	if (!SetCommTimeouts(m_hComm,pCommTimeOuts))
	{		
		TRACE(_T("SetCommTimeouts error"));		
		return FALSE;
	}
	return TRUE;
}

BOOL CCEComm::GetSeriesState(DCB* pCommParam)
{
	ASSERT(m_hComm != INVALID_HANDLE_VALUE);
	if (!GetCommState(m_hComm,pCommParam))
	{		
		TRACE(_T("GetCommState error"));		
		return FALSE;
	}
	return TRUE;
};

BOOL CCEComm::SetSeriesState(DCB* pCommParam)
{
	ASSERT(m_hComm != INVALID_HANDLE_VALUE);
	if (!SetCommState(m_hComm, pCommParam))
	{
		TRACE(_T("SetCommState error"));		
		return FALSE;
	}
	return TRUE;
};

void CCEComm::ConfigPort()
{
/*	DCB dcb;
	TCHAR szPort[15];	
	wsprintf(szPort, _T("COM%d"), m_nPort);
	GetSeriesState(&dcb);
	COMMCONFIG comm;
	comm.dwSize = sizeof(COMMCONFIG);
	CopyMemory(&comm.dcb,&dcb,sizeof(DCB));
	CommConfigDialog(szPort,m_pPortOwner->GetSafeHwnd(),&comm);
	SetSeriesState(&comm.dcb);
*/}

/*
*函数介绍:关闭串口
*入口参数:(无)
*出口参数:(无)
*返回值:  (无)
*/
void CCEComm::CloseRead()
{
	if(m_hComm!=INVALID_HANDLE_VALUE)
	{
	//关闭读线程
		if(m_hReadCloseEvent!=NULL) SetEvent(m_hReadCloseEvent);
		//设置所有事件无效无效
		SetCommMask(m_hComm, 0);
		//清空所有将要读的数据
		PurgeComm( m_hComm,  PURGE_RXCLEAR );
		//等待10秒,如果读线程没有退出,则强制退出
		if (WaitForSingleObject(m_hReadThread,m_nCloseDelayTime) == WAIT_TIMEOUT)
		{
			TerminateThread(m_hReadThread,0);
		}
		if(m_hReadCloseEvent!=NULL)
		{
			CloseHandle(m_hReadCloseEvent);
			m_hReadCloseEvent = NULL;
		}
		if(m_hReadThread!=NULL)
		{
			CloseHandle(m_hReadThread);
			m_hReadThread = NULL;
		}
	}
}

void CCEComm::CloseWrite()
{
	if(m_hComm!=INVALID_HANDLE_VALUE)
	{
	//关闭写线程
		if(m_hWriteCloseEvent!=NULL) SetEvent(m_hWriteCloseEvent);
		//清空所有将要写的数据
		PurgeComm( m_hComm,  PURGE_TXCLEAR );
		//等待10秒,如果读线程没有退出,则强制退出
		if (WaitForSingleObject(m_hWriteThread,m_nCloseDelayTime) == WAIT_TIMEOUT)
		{
			TerminateThread(m_hWriteThread,0);
		}
		if(m_hWriteCloseEvent!=NULL)
		{
			CloseHandle(m_hWriteCloseEvent);
			m_hWriteCloseEvent = NULL;
		}
		if(m_hWriteThread!=NULL)
		{
			CloseHandle(m_hWriteThread);
			m_hWriteThread = NULL;
		}
	}
}

void CCEComm::ClosePort()
{	
	if(m_hComm!=INVALID_HANDLE_VALUE)
	{
		//关闭读线程
		CloseRead();

		//关闭写线程
		CloseWrite();
		
		//关闭串口
		CloseHandle (m_hComm);
		m_hComm = INVALID_HANDLE_VALUE;
		m_nPort = 0;
	}
}

void CCEComm::SetCloseDelayTime(UINT t)
{
	if(t<1000) t=1000;
	m_nCloseDelayTime = t;
}

/*
*函数介绍:向串口发送数据
*入口参数:buf		: 将要往串口写入的数据的缓冲区
		   bufLen	: 将要往串口写入的数据的缓冲区长度
*出口参数:(无)
*返回值:TRUE:表示成功地将要发送的数据传递到写线程消息队列。
		 FALSE:表示将要发送的数据传递到写线程消息队列失败。
		 注视:此处的TRUE,不直接代表数据一定成功写入到串口了。
*/
BOOL CCEComm::SendPort(const BYTE *buf,int bufLen)
{
	//将要发送的数据传递到写线程消息队列
    BYTE * bufsend = new BYTE[bufLen];	//传送完成后自动释放内存
	CopyMemory(bufsend,buf,bufLen);
	if (PostThreadMessage(m_dwWriteThreadID,CM_THREADCOMMWRITE,
		WPARAM(bufLen), LPARAM(bufsend)))
	{
		return TRUE;
	};
	return FALSE;
}

BOOL CCEComm::SendPort(LPCTSTR szSend)
{
	CString tmpstr = szSend; //复制要发送的字符串
	int charlen = WideCharToMultiByte( //转换Unicode到Ansi
			  CP_ACP,
			  WC_COMPOSITECHECK | WC_DEFAULTCHAR,
			  tmpstr.GetBuffer(tmpstr.GetLength()),
			  -1,
			  NULL, //转换到缓冲区中
			  0,
			  0,
			  0
			);
	tmpstr.ReleaseBuffer();
	charlen-=1;
	if(charlen<=0) return FALSE;
    BYTE * buf = new BYTE[charlen];//传送完成后自动释放内存
	ZeroMemory(buf,charlen); //缓冲区清零
	WideCharToMultiByte( //转换Unicode到Ansi
			  CP_ACP,
			  WC_COMPOSITECHECK | WC_DEFAULTCHAR,
			  tmpstr.GetBuffer(tmpstr.GetLength()),
			  -1,
			  (char*)buf, //转换到缓冲区中
			  charlen,
			  0,
			  0
			);
	tmpstr.ReleaseBuffer();
	if (PostThreadMessage(m_dwWriteThreadID,CM_THREADCOMMWRITE,
		WPARAM(charlen), LPARAM(buf)))
	{
		return TRUE;
	};
	return FALSE;
}

BOOL CCEComm::SendPortU(LPCTSTR szSend)
{
	CString tmpstr = szSend; //复制要发送的字符串
	int charlen = tmpstr.GetLength();
	charlen*=2;
	if(charlen<=0) return FALSE;
    BYTE * buf = new BYTE[charlen];//传送完成后自动释放内存
	ZeroMemory(buf,charlen); //缓冲区清零
	_tcscpy((WCHAR*)buf,tmpstr);
	if (PostThreadMessage(m_dwWriteThreadID,CM_THREADCOMMWRITE,
		WPARAM(charlen), LPARAM(buf)))
	{
		return TRUE;
	};
	return FALSE;
}

void CCEComm::SetPortReceive(CWnd* pWnd,ONSERIESREAD proc)
{
	m_pPortOwner = pWnd;
	m_OnSeriesRead = proc;
};

//串口读线程函数
DWORD CCEComm::ReadThreadFunc(LPVOID lparam)
{
	CCEComm *ceSeries = (CCEComm*)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);
				}

				delete[] readBuf;
			}
		}
		//如果收到读线程退出信号,则退出线程
		if (WaitForSingleObject(ceSeries->m_hReadCloseEvent,0) == WAIT_OBJECT_0)
		{
			break;
		}
	}
	return 0;
}

//串口写线程函数
DWORD CCEComm::WriteThreadFunc(LPVOID lparam)
{
	CCEComm *ceSeries = (CCEComm*)lparam;
	MSG msg;
	DWORD dwWriteLen = 0;
	BYTE * buf = NULL;
	
	while (TRUE)
	{
		//如果捕捉到线程消息
		if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
		{
			if (msg.hwnd != 0 )
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
				continue;
			}
			if (msg.message == CM_THREADCOMMWRITE)
			{
				//向串口写
				buf = (BYTE*)msg.lParam;
				dwWriteLen = msg.wParam;
				//向串口写
				WritePort(ceSeries->m_hComm,buf,dwWriteLen);
				//删除动态分配的内存
				delete[] buf;
			}
		}
		//如果收到写线程退出信号,则退出线程
		if (WaitForSingleObject(ceSeries->m_hWriteCloseEvent,0) == WAIT_OBJECT_0)
		{
			break;
		}
	}
	
	return 0;
}


//私用方法,用于向串口写数据,被写线程调用
BOOL CCEComm::WritePort(HANDLE hComm,const BYTE *buf,DWORD bufLen)
{
	DWORD dwNumBytesWritten;
	DWORD dwHaveNumWritten =0 ; //已经写入多少
	
	ASSERT(hComm != INVALID_HANDLE_VALUE);
	do
	{
		if (WriteFile (hComm,					//串口句柄 
			buf+dwHaveNumWritten,				//被写数据缓冲区 
			bufLen - dwHaveNumWritten,          //被写数据缓冲区大小
			&dwNumBytesWritten,					//函数执行成功后,返回实际向串口写的个数	
			NULL))								//此处必须设置NULL
		{
			dwHaveNumWritten = dwHaveNumWritten + dwNumBytesWritten;
			//写入完成
			if (dwHaveNumWritten == bufLen)
			{
				break;
			}
			Sleep(10);
		}
		else
		{
			return FALSE;
		}
	}while (TRUE);
	
	return TRUE;	
}
/*
*函数介绍:打开串口
*入口参数:portNo		:串口号
		   baud			:波特率
		   parity		:奇偶校验
		   databits		:数据位
		   stopbits		:停止位
		   maxblock		:最大数据块
*出口参数:(无)
*返回值:TRUE:成功打开串口;FALSE:打开串口失败
*/


BOOL CCEComm::OpenPort(BYTE portNo, DWORD baud, BYTE parity,
					   BYTE databits, BYTE stopbits, DWORD maxblock)
{
	DCB commParam;
	TCHAR szPort[15];	
	
	// 已经打开的话,直接返回
	if (m_hComm != INVALID_HANDLE_VALUE)
	{
		return TRUE;
	}
	//ASSERT(portNo > 0 && portNo < 5);
	
	//设置串口名
	m_nPort = portNo;
	wsprintf(szPort, _T("COM%d:"), m_nPort);
	//打开串口
	m_hComm = CreateFile(
		szPort,
		GENERIC_READ | GENERIC_WRITE,	//允许读和写
		0,								//独占方式(共享模式)
		NULL,
		OPEN_EXISTING,					//打开而不是创建(创建方式)
		0,
		NULL 
		);
	
	if (m_hComm == INVALID_HANDLE_VALUE)
	{
		// 无效句柄,返回。		
		TRACE(_T("CreateFile 返回无效句柄"));
		return FALSE;
	}
	
		
	// 得到打开串口的当前属性参数,修改后再重新设置串口。
	// 设置串口的超时特性为立即返回。
	if(!GetSeriesState(&commParam)) return FALSE;

	commParam.BaudRate = baud;					// 设置波特率 
	commParam.fBinary = TRUE;					// 设置二进制模式,此处必须设置TRUE
	commParam.fParity = TRUE;					// 支持奇偶校验 
	commParam.ByteSize = databits;				// 数据位,范围:4-8 
	commParam.StopBits = stopbits;				// 停止位 
	commParam.Parity = parity;					// 校验模式
	
	commParam.fOutxCtsFlow = FALSE;				// No CTS output flow control 
	commParam.fOutxDsrFlow = FALSE;				// No DSR output flow control 
	//commParam.fDtrControl = DTR_CONTROL_ENABLE; // DTR flow control type 
	commParam.fDsrSensitivity = FALSE;			// DSR sensitivity 
	commParam.fTXContinueOnXoff = TRUE;			// XOFF continues Tx 
	commParam.fOutX = FALSE;					// No XON/XOFF out flow control 
	commParam.fInX = FALSE;						// No XON/XOFF in flow control 
	commParam.fErrorChar = FALSE;				// Disable error replacement 
	commParam.fNull = FALSE;					// Disable null stripping 
	//commParam.fRtsControl = RTS_CONTROL_ENABLE; // RTS flow control 
	commParam.fAbortOnError = FALSE;			// 当串口发生错误,并不终止串口读写
	
	if(!SetSeriesState(&commParam)) return FALSE;
	
    //设置串口读写时间
	COMMTIMEOUTS CommTimeOuts;
	GetCommTimeouts (m_hComm, &CommTimeOuts);
	CommTimeOuts.ReadIntervalTimeout = MAXDWORD;  
	CommTimeOuts.ReadTotalTimeoutMultiplier = 0;  
	CommTimeOuts.ReadTotalTimeoutConstant = 0;    
	CommTimeOuts.WriteTotalTimeoutMultiplier = 10;  
	CommTimeOuts.WriteTotalTimeoutConstant = 1000;  
	
	if(!SetSeriesTimeouts(&CommTimeOuts)) return FALSE;
	
	//指定端口监测的事件集
	SetCommMask (m_hComm, EV_RXCHAR | EV_CTS | EV_DSR | EV_TXEMPTY);
	
	//分配设备缓冲区
	SetupComm(m_hComm,maxblock,maxblock);
	
	//初始化缓冲区中的信息
	PurgeComm(m_hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);
	
	//创建读串口线程
	m_hReadThread = CreateThread(NULL,0,ReadThreadFunc,this,0,&m_dwReadThreadID);
	m_hReadCloseEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
	//创建写串口线程
	m_hWriteThread = CreateThread(NULL,0,WriteThreadFunc,this,0,&m_dwWriteThreadID);
	m_hWriteCloseEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
	
	if( (m_hReadThread==NULL)
		||(m_hReadCloseEvent==NULL)
		||(m_hWriteThread==NULL)
		||(m_hWriteCloseEvent==NULL) )
	{
		return FALSE;
	}

	TRACE(_T("串口打开成功"));
	
	return TRUE;

}

⌨️ 快捷键说明

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