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

📄 mywin32port.cpp

📁 多线程
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/************************************************************************/
/* 类名称:   串口操作类                                                 */
/* 功  能:   实现对串口的基本操作                                       */
/* 设计者:   Jinlong|Luo                                                */
/* 修订记录:                                                            */
/* 设计时间: 2007-9-24                                                  */
/************************************************************************/
#include<StdAfx.h>
#include "MyWin32Port.h"

//全局变量定义
CRITICAL_SECTION g_cslistReceiveInfoMutex;		  //接收队列关键代码段的同步变量
CList< CInfoCell, CInfoCell& > g_listReceiveInfo; //接收队列

CFile m_ycDataFile;//遥测数据文件
/************************************************************************/
// 函数名称: ReceiveThread()
// 函数描述: 接收线程
// 入口参数:                                                            
// 出口参数:         
// 返 回 值:    
// 其    它:                                                            
/************************************************************************/
UINT MyWin32Port::ReceiveThread( PVOID pParameter )
{
	MyWin32Port* pSerialPort = (MyWin32Port*)pParameter;
	ASSERT(pSerialPort->m_hCom != INVALID_HANDLE_VALUE);//检测串口是否打开

	//清空串口
	PurgeComm(pSerialPort->m_hCom,PURGE_RXCLEAR | PURGE_TXCLEAR);

	if( pSerialPort->m_hCom )
		SetCommMask( pSerialPort->m_hCom, EV_RXCHAR );//输入设备接受字符

	int   i=0;
	int   j=0;
	short   sCurLoc  = 0;//临时缓冲区中的当前位置
	UWord16 wHead  = 0;
	DWORD dwReadNum = 0;
	char*	pSegment = NULL;
	CString strDateTime;
	CTime time = CTime::GetCurrentTime();	
	strDateTime.Format("%d-%d-%d",time.GetYear(),time.GetMonth(),time.GetDay());
	CString strFileName = "GPSData";
	strFileName+=strDateTime;
	strFileName+=".yc";
	BOOL bCreateFile = m_ycDataFile.Open(strFileName,CFile::modeCreate|CFile::modeWrite|CFile::typeBinary);

	while( TRUE )
	{
		//如果收到接收线程退出信号,则退出线程
		if (WaitForSingleObject(pSerialPort->m_hReceiveCloseEvent,500) == WAIT_OBJECT_0)
		{
			break;
		}

		//从串口读取数据
		ReadFile( pSerialPort->m_hCom, pSerialPort->m_csRevBuf, RECEIVE_CHAR_BUFFER_MAX, &dwReadNum, NULL );	//读字符
		pSerialPort->m_csRevBuf[dwReadNum] = '\0';
		if (dwReadNum<=0)  //dwReadNum<=0
		{
			Sleep(20);
			continue;
		}
	
		//保存当前数据
		if( bCreateFile )
		{
			m_ycDataFile.Write( pSerialPort->m_csRevBuf,dwReadNum);
		}

		//处理数据
		if (sCurLoc>(SERIAL_CHAR_BUFFER_MAX*2-dwReadNum))
		{
			sCurLoc = 0;//防止溢出
		}
		memcpy(&pSerialPort->m_csTempBuf[sCurLoc],&pSerialPort->m_csRevBuf[0],dwReadNum);//保存当前数据到临时缓冲区中
		for (i=0;i<(dwReadNum+sCurLoc-1);i++)
		{
			wHead = (pSerialPort->m_csTempBuf[i]<<8) | pSerialPort->m_csTempBuf[i+1];
			if (0xEB90 == wHead)//帧同步头
			{	
				if ((i+50)<=(dwReadNum+sCurLoc))//当前数据为一条完整的数据帧,遥测一帧数据为50byte
				{	
					if ((pSerialPort->m_csTempBuf[i+46]==0x55) && (pSerialPort->m_csTempBuf[i+47]==0x55)
						&& (pSerialPort->m_csTempBuf[i+48]==0x55) && (pSerialPort->m_csTempBuf[i+49]==0x55))//帧尾标志
					{
						EnterCriticalSection(&g_cslistReceiveInfoMutex);
						pSegment = (char*)&pSerialPort->m_csTempBuf[i];
						CInfoCell oCell(pSegment,50);					
						g_listReceiveInfo.AddTail(oCell);
						LeaveCriticalSection(&g_cslistReceiveInfoMutex);
						i+=49;
						j = i+1;
					}					
				}
			}
		}

		if (j<(dwReadNum+sCurLoc))//当前数据未处理完,保存不完整帧
		{
			sCurLoc = dwReadNum+sCurLoc-j;
			memmove(&pSerialPort->m_csTempBuf[0],&pSerialPort->m_csTempBuf[j],sCurLoc);
			j=0;
		}
		else//当前数据处理完毕
		{
			sCurLoc = 0;
			j = 0;
		}
		pSerialPort->m_csRevBuf[0] = '\0';	//接收缓冲区置空
	}


	return 0;
}
/************************************************************************/
// 函数名称: InfoProcessThread()
// 函数描述: 信息处理线程
// 入口参数:                                                            
// 出口参数:         
// 返 回 值:    
// 其    它:                                                            
/************************************************************************/
UINT MyWin32Port::InfoProcessThread( PVOID pParameter )
{
	MyWin32Port* pSerialPort = (MyWin32Port*)pParameter;
	ASSERT(pSerialPort->m_hCom != INVALID_HANDLE_VALUE);
	int iCount = 0;

	//处理接收缓冲区中的数据
	while( true )
	{
		EnterCriticalSection( &g_cslistReceiveInfoMutex );
		iCount =  g_listReceiveInfo.GetCount();		
		while(iCount>0 )
		{			
			CInfoCell& oCell = g_listReceiveInfo.GetHead();
			pSerialPort->Process( oCell.csInfo, oCell.nLength );	//信息处理
			g_listReceiveInfo.RemoveHead();
			iCount =  g_listReceiveInfo.GetCount();
		}		
		LeaveCriticalSection( &g_cslistReceiveInfoMutex );

		//如果收到解析线程退出信号,则退出线程
		if (WaitForSingleObject(pSerialPort->m_hInfoProcessCloseEvent,500) == WAIT_OBJECT_0)
		{
			pSerialPort->m_hInfoProcessThread = NULL;
			break;
		}
		Sleep(10);
	}

	return 0;
}

/************************************************************************/
/* 构造/析构                                                            */
/************************************************************************/
MyWin32Port::MyWin32Port()
{

	//串口句柄
	m_hCom = INVALID_HANDLE_VALUE;

	//串口占用标示
	m_bIsOpen = FALSE;

	//窗口句柄
	m_hWnd  = NULL;     
	
	//接收线程句柄
	m_hReceiveThread = NULL;	

	//解析线程句柄
	m_hInfoProcessThread = NULL;

	//接收队列关键代码段的同步变量初始化
	InitializeCriticalSection(&g_cslistReceiveInfoMutex);	

	//当前解析的协议指令字符串
	m_pCurParsedContent = NULL;	

	//接收字符串缓冲区
	memset(m_csRevBuf,0,(SERIAL_CHAR_BUFFER_MAX+1)*sizeof(BYTE));
	
	//临时缓冲区
	memset(m_csTempBuf,0,(SERIAL_CHAR_BUFFER_MAX*2+1)*sizeof(BYTE));


}
MyWin32Port::~MyWin32Port()
{
	//关闭串口
	if (m_bIsOpen)
	{
		CloseMyWin32Port();
		m_bIsOpen = FALSE;
	}

	//清除接收队列关键代码段的同步变量
	if ((NULL==m_hInfoProcessThread) && (NULL==m_hReceiveThread))
	{
		DeleteCriticalSection( &g_cslistReceiveInfoMutex );
	}

	//当前解析的协议指令字符串
	if (m_pCurParsedContent!=NULL)
	{
		delete m_pCurParsedContent;
		m_pCurParsedContent = NULL;
	}
}

/************************************************************************/
// 函数名称: Open(HWND hWnd,char btID,long dwBaudRate, char btParity ,char btSize,
//				  char btStopBits,long ReadIntervalTimeout,long ReadTotalTimeoutMultiplier,
//				  long ReadTotalTimeoutConstant,long WriteTotalTimeoutMultiplier,
//			      long WriteTotalTimeoutConstant,long dwCommMask ) 
// 函数描述: 根据指定的参数打开串口并开启串口读、写及解析线程           
// 入口参数:    
//           HWND     hWnd                传入的窗口句柄                                                        
//           char     btID                待打开串口ID号 1--COM1:、2--COM2:...
//           long     dwBaudRate          待打开串口数据传输率 4800、9600、19200...
//           char     btParity            待打开串口奇偶校验 默认为无校验。
//           char     btSize              待打开串口数据位 默认为8 
//           char     btStopBits          待打开串口停止位 默认为1 
//			 long	  ReadIntervalTimeout 
//			 long     ReadTotalTimeoutMultiplier
//		     long	  ReadTotalTimeoutConstant
//			 long	  WriteTotalTimeoutMultiplier
//           long	  WriteTotalTimeoutConstant	 串口通讯占用端口超时结构参数
//           long     dwCommMask          待打开串口串口响应事件
// 出口参数:         
// 返 回 值: 串口打开成功或已打开,返回TRUE;否则返回FALSE     
// 其    它:                                                            
/************************************************************************/
BOOL MyWin32Port::OpenMyWin32Port(HWND hWnd,char btID,long dwBaudRate,  char btParity /* = NOPARITY */,char btSize /* = 8 */, 
					   char btStopBits /* = ONESTOPBIT */,long ReadIntervalTimeout, long ReadTotalTimeoutMultiplier,
					   long ReadTotalTimeoutConstant,long WriteTotalTimeoutMultiplier,
					   long WriteTotalTimeoutConstant,long dwCommMask /* = EV_RXCHAR|EV_TXEMPTY */)
{
	//打开串口
	DCB           dcb             ;
	long          dwError = 0     ;
	CString       szPort = _T("") ;
	COMMTIMEOUTS  CommTimeOuts    ;
	if( FALSE != m_bIsOpen )
	{
		AfxMessageBox(_T("串口已打开或未找到!")) ;
		return 0 ;
	}	
	szPort.Format("COM%d:",btID) ;// 确定待打开的串口名称完整性(COM1:)		
	m_hCom = INVALID_HANDLE_VALUE ;// 设置串口通讯占用端口的句柄为占用模式
	m_hCom = CreateFile( szPort, 
		                  GENERIC_READ | GENERIC_WRITE, 
						  0, 
						  NULL, 
						  OPEN_EXISTING, 
						  FILE_ATTRIBUTE_NORMAL, 
						  NULL ) ;// 根据输入的串口通讯参数打开串口


	if( INVALID_HANDLE_VALUE == m_hCom )
	{
		return FALSE ;	
	}
	// 设置串口通讯占用端口超时结构参数
	CommTimeOuts.ReadIntervalTimeout         = 0xFFFFFFFF ;
	CommTimeOuts.ReadTotalTimeoutMultiplier  = 0          ;
	CommTimeOuts.ReadTotalTimeoutConstant    = 0          ;
	CommTimeOuts.WriteTotalTimeoutMultiplier = 0          ;
	CommTimeOuts.WriteTotalTimeoutConstant   = 5000       ;

	// 设置串口通讯占用端口超时结构
	SetCommTimeouts(m_hCom,&CommTimeOuts) ;

	// 设置串口通讯占用端口DCB结构
	dcb.DCBlength = sizeof( DCB ) ;
	GetCommState( m_hCom, &dcb ) ;
	dcb.BaudRate  = dwBaudRate    ;
	dcb.ByteSize  = btSize        ;
	if (1==btStopBits)
	{
		dcb.StopBits = ONESTOPBIT;
	}
	else if (2== btStopBits)
	{
		dcb.StopBits = TWOSTOPBITS;
	}
	else if (5 == btStopBits)
	{
		dcb.StopBits = ONE5STOPBITS;
	}
	else
	{
		dcb.StopBits = ONESTOPBIT;
	}
	switch(btParity)
	{
	case 'N':  //无奇偶校验位
		dcb.Parity = NOPARITY;
		break;
	case 'O':
		dcb.Parity = ODDPARITY;
		break;
	case 'E':
		dcb.Parity = EVENPARITY;
		break;
	case 'M':
		dcb.Parity = MARKPARITY;
		break;
	case 'S':
		dcb.Parity = SPACEPARITY;
		break;
	default:
		dcb.Parity    = NOPARITY ;
		break;
	}
	
	// 如果设置串口通讯占用端口选项参数失败直接返回FALSE
	if( 0 == SetCommState(m_hCom,&dcb) || 0 == SetupComm(m_hCom,10000,10000) || 0 == SetCommMask(m_hCom,dwCommMask) )
	{
		// 获取错误标示
		dwError = GetLastError() ;

		// 关闭串口通讯并释放其占用端口
		m_hWnd = NULL;

		CloseMyWin32Port() ;

		return FALSE ;
	}

	// 清空串口通讯占用端口的缓冲区
	PurgeComm(m_hCom,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT) ;

	//启动接收线程
	if (!StartReceiveThread())
	{
		CloseMyWin32Port() ;//关闭串口

		return FALSE;
	}
	 
	//启动解析线程
	if (!StartInfoProcessThread())
	{
		CloseMyWin32Port() ;//关闭串口

		return FALSE;
	}

	// 设置串口通讯是否占用端口的标识
	m_hWnd = hWnd ;
	m_bIsOpen = TRUE ;
	return TRUE;
}

⌨️ 快捷键说明

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